summaryrefslogtreecommitdiff
path: root/Kernel/Prekernel
diff options
context:
space:
mode:
authorMarcin Undak <mcinek@gmail.com>2021-10-16 18:52:31 -0400
committerAndreas Kling <kling@serenityos.org>2021-10-31 12:35:53 +0100
commit3cc5752a69eebc1a92d447b3bf254faaa5eafb7b (patch)
treeb45c6d746a9ebb6acdd79cc0e089fe20fe20d08b /Kernel/Prekernel
parent82a73b8499472e1b035ab7b80ef5578de42f2840 (diff)
downloadserenity-3cc5752a69eebc1a92d447b3bf254faaa5eafb7b.zip
Kernel: Refactor Aarch64 MailBox class
The goal was to reduce common setup of messages. Changes: * MailBox turned into singleton to follow existing patterns * Removed device specific messages from MailBox requiring clients to know the details instead * Created base Message class which clients should deriver from It really simplify the usage for more complicated message queues like framebuffer setup - see followup commits.
Diffstat (limited to 'Kernel/Prekernel')
-rw-r--r--Kernel/Prekernel/Arch/aarch64/FramebufferMailboxMessages.h105
-rw-r--r--Kernel/Prekernel/Arch/aarch64/Mailbox.cpp78
-rw-r--r--Kernel/Prekernel/Arch/aarch64/Mailbox.h55
-rw-r--r--Kernel/Prekernel/Arch/aarch64/Timer.cpp37
-rw-r--r--Kernel/Prekernel/Arch/aarch64/Timer.h19
-rw-r--r--Kernel/Prekernel/Arch/aarch64/UART.cpp4
-rw-r--r--Kernel/Prekernel/Arch/aarch64/init.cpp29
7 files changed, 258 insertions, 69 deletions
diff --git a/Kernel/Prekernel/Arch/aarch64/FramebufferMailboxMessages.h b/Kernel/Prekernel/Arch/aarch64/FramebufferMailboxMessages.h
new file mode 100644
index 0000000000..3b11bf869c
--- /dev/null
+++ b/Kernel/Prekernel/Arch/aarch64/FramebufferMailboxMessages.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2021, Marcin Undak <mcinek@gmail.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <Kernel/Prekernel/Arch/aarch64/Mailbox.h>
+
+namespace Prekernel {
+
+class FramebufferSetPhysicalSizeMboxMessage : public Mailbox::Message {
+public:
+ u32 width;
+ u32 height;
+
+ FramebufferSetPhysicalSizeMboxMessage()
+ : Mailbox::Message(0x48003, 8)
+ {
+ width = 0;
+ height = 0;
+ }
+};
+
+class FramebufferSetVirtualSizeMboxMessage : public Mailbox::Message {
+public:
+ u32 width;
+ u32 height;
+
+ FramebufferSetVirtualSizeMboxMessage()
+ : Mailbox::Message(0x48004, 8)
+ {
+ width = 0;
+ height = 0;
+ }
+};
+
+class FramebufferSetVirtualOffsetMboxMessage : public Mailbox::Message {
+public:
+ u32 x;
+ u32 y;
+
+ FramebufferSetVirtualOffsetMboxMessage()
+ : Mailbox::Message(0x48009, 8)
+ {
+ x = 0;
+ y = 0;
+ }
+};
+
+class FramebufferSetDepthMboxMessage : public Mailbox::Message {
+public:
+ u32 depth_bits;
+
+ FramebufferSetDepthMboxMessage()
+ : Mailbox::Message(0x48005, 4)
+ {
+ depth_bits = 0;
+ }
+};
+
+class FramebufferSetPixelOrderMboxMessage : public Mailbox::Message {
+public:
+ enum PixelOrder : u32 {
+ BGR = 0,
+ RGB = 1
+ };
+
+ PixelOrder pixel_order;
+
+ FramebufferSetPixelOrderMboxMessage()
+ : Mailbox::Message(0x48006, 4)
+ {
+ pixel_order = PixelOrder::BGR;
+ }
+};
+
+class FramebufferAllocateBufferMboxMessage : public Mailbox::Message {
+public:
+ union {
+ u32 alignment;
+ u32 address;
+ };
+ u32 size = 0;
+
+ FramebufferAllocateBufferMboxMessage()
+ : Mailbox::Message(0x40001, 8)
+ {
+ alignment = 0;
+ size = 0;
+ }
+};
+
+class FramebufferGetPithMboxMessage : public Mailbox::Message {
+public:
+ u32 pitch;
+
+ FramebufferGetPithMboxMessage()
+ : Mailbox::Message(0x40008, 4)
+ {
+ pitch = 0;
+ }
+};
+}
diff --git a/Kernel/Prekernel/Arch/aarch64/Mailbox.cpp b/Kernel/Prekernel/Arch/aarch64/Mailbox.cpp
index 005869c68b..b22cec535e 100644
--- a/Kernel/Prekernel/Arch/aarch64/Mailbox.cpp
+++ b/Kernel/Prekernel/Arch/aarch64/Mailbox.cpp
@@ -33,6 +33,30 @@ constexpr u32 MBOX_EMPTY = 0x4000'0000;
constexpr int ARM_TO_VIDEOCORE_CHANNEL = 8;
+Mailbox::Message::Message(u32 tag, u32 arguments_size)
+{
+ m_tag = tag;
+ m_arguments_size = arguments_size;
+ m_command_tag = MBOX_REQUEST;
+}
+
+Mailbox::MessageHeader::MessageHeader()
+{
+ m_message_queue_size = 0;
+ m_command_tag = MBOX_REQUEST;
+}
+
+bool Mailbox::MessageHeader::success() const
+{
+ return m_command_tag == MBOX_RESPONSE_SUCCESS;
+}
+
+Mailbox& Mailbox::the()
+{
+ static Mailbox instance;
+ return instance;
+}
+
static void wait_until_we_can_write(MMIO& mmio)
{
// Since nothing else writes to the mailbox, this wait is mostly cargo-culted.
@@ -47,8 +71,14 @@ static void wait_for_reply(MMIO& mmio)
;
}
-bool Mailbox::call(u8 channel, u32 volatile* __attribute__((aligned(16))) message)
+bool Mailbox::send_queue(void* queue, u32 queue_size) const
{
+ // According to Raspberry Pi specs this is the only channel implemented.
+ const u32 channel = ARM_TO_VIDEOCORE_CHANNEL;
+
+ auto message_header = reinterpret_cast<MessageHeader*>(queue);
+ message_header->set_queue_size(queue_size);
+
auto& mmio = MMIO::the();
// The mailbox interface has a FIFO for message deliverly in both directions.
@@ -59,7 +89,7 @@ bool Mailbox::call(u8 channel, u32 volatile* __attribute__((aligned(16))) messag
wait_until_we_can_write(mmio);
// The mailbox message is 32-bit based, so this assumes that message is in the first 4 GiB.
- u32 request = static_cast<u32>(reinterpret_cast<FlatPtr>(message) & ~0xF) | (channel & 0xF);
+ u32 request = static_cast<u32>(reinterpret_cast<FlatPtr>(queue) & ~0xF) | (channel & 0xF);
mmio.write(MBOX_WRITE_DATA, request);
for (;;) {
@@ -68,52 +98,10 @@ bool Mailbox::call(u8 channel, u32 volatile* __attribute__((aligned(16))) messag
u32 response = mmio.read(MBOX_READ_DATA);
// We keep at most one message in flight and do synchronous communication, so response will always be == request for us.
if (response == request)
- return message[1] == MBOX_RESPONSE_SUCCESS;
+ return message_header->success();
}
return true;
}
-constexpr u32 MBOX_TAG_GET_FIRMWARE_VERSION = 0x0000'0001;
-constexpr u32 MBOX_TAG_SET_CLOCK_RATE = 0x0003'8002;
-
-u32 Mailbox::query_firmware_version()
-{
- // See https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface for data format.
- u32 __attribute__((aligned(16))) message[7];
- message[0] = sizeof(message);
- message[1] = MBOX_REQUEST;
-
- message[2] = MBOX_TAG_GET_FIRMWARE_VERSION;
- message[3] = 0; // Tag data size. MBOX_TAG_GET_FIRMWARE_VERSION needs no arguments.
- message[4] = MBOX_REQUEST;
- message[5] = 0; // Trailing zero for request, room for data in response.
-
- message[6] = 0; // Room for trailing zero in response.
-
- if (call(ARM_TO_VIDEOCORE_CHANNEL, message) && message[2] == MBOX_TAG_GET_FIRMWARE_VERSION)
- return message[5];
-
- return 0xffff'ffff;
-}
-
-u32 Mailbox::set_clock_rate(ClockID clock_id, u32 rate_hz, bool skip_setting_turbo)
-{
- u32 __attribute__((aligned(16))) message[9];
- message[0] = sizeof(message);
- message[1] = MBOX_REQUEST;
-
- message[2] = MBOX_TAG_SET_CLOCK_RATE;
- message[3] = 12; // Tag data size.
- message[4] = MBOX_REQUEST;
- message[5] = static_cast<u32>(clock_id);
- message[6] = rate_hz;
- message[7] = skip_setting_turbo ? 1 : 0;
-
- message[8] = 0;
-
- call(ARM_TO_VIDEOCORE_CHANNEL, message);
- return message[6];
-}
-
}
diff --git a/Kernel/Prekernel/Arch/aarch64/Mailbox.h b/Kernel/Prekernel/Arch/aarch64/Mailbox.h
index 9f06cbea8c..f54eea7c99 100644
--- a/Kernel/Prekernel/Arch/aarch64/Mailbox.h
+++ b/Kernel/Prekernel/Arch/aarch64/Mailbox.h
@@ -14,28 +14,41 @@ namespace Prekernel {
// https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface
class Mailbox {
public:
- static bool call(u8 channel, u32 volatile* __attribute__((aligned(16))) data);
-
- static u32 query_firmware_version();
-
- enum class ClockID {
- Reserved = 0,
- EMMC = 1,
- UART = 2,
- ARM = 3,
- CORE = 4,
- V3D = 5,
- H264 = 6,
- ISP = 7,
- SDRAM = 8,
- PIXEL = 9,
- PWM = 10,
- HEVC = 11,
- EMMC2 = 12,
- M2MC = 13,
- PIXEL_BVB = 14,
+ // Base class for Mailbox messages. Implemented in subsystems that use Mailbox.
+ class Message {
+ protected:
+ Message(u32 tag, u32 arguments_size);
+
+ private:
+ u32 m_tag;
+ u32 m_arguments_size;
+ u32 m_command_tag;
+ };
+
+ // Must be at the beginning of every command message queue
+ class MessageHeader {
+ public:
+ MessageHeader();
+
+ u32 queue_size() { return m_message_queue_size; }
+ void set_queue_size(u32 size) { m_message_queue_size = size; }
+ bool success() const;
+
+ private:
+ u32 m_message_queue_size;
+ u32 m_command_tag;
};
- static u32 set_clock_rate(ClockID, u32 rate_hz, bool skip_setting_turbo = true);
+
+ // Must be at the end of every command message queue
+ class MessageTail {
+ private:
+ u32 m_empty_tag = 0;
+ };
+
+ static Mailbox& the();
+
+ // Sends message queue to VideoCore
+ bool send_queue(void* queue, u32 queue_size) const;
};
}
diff --git a/Kernel/Prekernel/Arch/aarch64/Timer.cpp b/Kernel/Prekernel/Arch/aarch64/Timer.cpp
index 4d1f8812ca..b40fe8cf7c 100644
--- a/Kernel/Prekernel/Arch/aarch64/Timer.cpp
+++ b/Kernel/Prekernel/Arch/aarch64/Timer.cpp
@@ -5,7 +5,9 @@
*/
#include <Kernel/Prekernel/Arch/aarch64/MMIO.h>
+#include <Kernel/Prekernel/Arch/aarch64/Mailbox.h>
#include <Kernel/Prekernel/Arch/aarch64/Timer.h>
+#include <Kernel/Prekernel/Arch/aarch64/Utils.h>
namespace Prekernel {
@@ -48,4 +50,39 @@ u64 Timer::microseconds_since_boot()
return (static_cast<u64>(high) << 32) | low;
}
+class SetClockRateMboxMessage : Prekernel::Mailbox::Message {
+public:
+ u32 clock_id;
+ u32 rate_hz;
+ u32 skip_setting_turbo;
+
+ SetClockRateMboxMessage()
+ : Prekernel::Mailbox::Message(0x0003'8002, 12)
+ {
+ clock_id = 0;
+ rate_hz = 0;
+ skip_setting_turbo = 0;
+ }
+};
+
+u32 Timer::set_clock_rate(ClockID clock_id, u32 rate_hz, bool skip_setting_turbo)
+{
+ struct __attribute__((aligned(16))) {
+ Prekernel::Mailbox::MessageHeader header;
+ SetClockRateMboxMessage set_clock_rate;
+ Prekernel::Mailbox::MessageTail tail;
+ } message_queue;
+
+ message_queue.set_clock_rate.clock_id = static_cast<u32>(clock_id);
+ message_queue.set_clock_rate.rate_hz = rate_hz;
+ message_queue.set_clock_rate.skip_setting_turbo = skip_setting_turbo ? 1 : 0;
+
+ if (!Prekernel::Mailbox::the().send_queue(&message_queue, sizeof(message_queue))) {
+ warnln("Timer::set_clock_rate() failed!");
+ return 0;
+ }
+
+ return message_queue.set_clock_rate.rate_hz;
+}
+
}
diff --git a/Kernel/Prekernel/Arch/aarch64/Timer.h b/Kernel/Prekernel/Arch/aarch64/Timer.h
index 278df3d493..27762930bf 100644
--- a/Kernel/Prekernel/Arch/aarch64/Timer.h
+++ b/Kernel/Prekernel/Arch/aarch64/Timer.h
@@ -18,6 +18,25 @@ public:
u64 microseconds_since_boot();
+ enum class ClockID {
+ Reserved = 0,
+ EMMC = 1,
+ UART = 2,
+ ARM = 3,
+ CORE = 4,
+ V3D = 5,
+ H264 = 6,
+ ISP = 7,
+ SDRAM = 8,
+ PIXEL = 9,
+ PWM = 10,
+ HEVC = 11,
+ EMMC2 = 12,
+ M2MC = 13,
+ PIXEL_BVB = 14,
+ };
+ u32 set_clock_rate(ClockID, u32 rate_hz, bool skip_setting_turbo = true);
+
private:
Timer();
diff --git a/Kernel/Prekernel/Arch/aarch64/UART.cpp b/Kernel/Prekernel/Arch/aarch64/UART.cpp
index 53596f0576..4c4bbce121 100644
--- a/Kernel/Prekernel/Arch/aarch64/UART.cpp
+++ b/Kernel/Prekernel/Arch/aarch64/UART.cpp
@@ -6,7 +6,7 @@
#include <Kernel/Prekernel/Arch/aarch64/GPIO.h>
#include <Kernel/Prekernel/Arch/aarch64/MMIO.h>
-#include <Kernel/Prekernel/Arch/aarch64/Mailbox.h>
+#include <Kernel/Prekernel/Arch/aarch64/Timer.h>
#include <Kernel/Prekernel/Arch/aarch64/UART.h>
namespace Prekernel {
@@ -101,7 +101,7 @@ UART::UART()
// Set UART clock so that the baud rate divisor ends up as 1.0.
// FIXME: Not sure if this is a good UART clock rate.
- u32 rate_in_hz = Mailbox::set_clock_rate(Mailbox::ClockID::UART, 16 * baud_rate);
+ u32 rate_in_hz = Timer::the().set_clock_rate(Timer::ClockID::UART, 16 * baud_rate);
// The BCM's PL011 UART is alternate function 0 on pins 14 and 15.
auto& gpio = Prekernel::GPIO::the();
diff --git a/Kernel/Prekernel/Arch/aarch64/init.cpp b/Kernel/Prekernel/Arch/aarch64/init.cpp
index da0a1250e9..d9d7f7e5ba 100644
--- a/Kernel/Prekernel/Arch/aarch64/init.cpp
+++ b/Kernel/Prekernel/Arch/aarch64/init.cpp
@@ -19,6 +19,7 @@ static void set_up_el1_mode();
static void set_up_el2_mode();
static void set_up_el3_mode();
static void print_current_exception_level(const char* msg);
+static u32 query_firmware_version();
[[noreturn]] static void jump_to_os_start_from_el2();
[[noreturn]] static void jump_to_os_start_from_el3();
@@ -30,7 +31,7 @@ extern "C" [[noreturn]] void init()
uart.print_str("Imagine this being your ideal operating system.\r\n");
uart.print_str("Observed deviations from that ideal are shortcomings of your imagination.\r\n\r\n");
- u32 firmware_version = Prekernel::Mailbox::query_firmware_version();
+ auto firmware_version = query_firmware_version();
uart.print_str("Firmware version: ");
uart.print_num(firmware_version);
uart.print_str("\r\n");
@@ -212,3 +213,29 @@ static void print_current_exception_level(const char* msg)
uart.print_num(exception_level);
uart.print_str("\r\n");
}
+
+class QueryFirmwareVersionMboxMessage : Prekernel::Mailbox::Message {
+public:
+ u32 version;
+
+ QueryFirmwareVersionMboxMessage()
+ : Prekernel::Mailbox::Message(0x0000'0001, 4)
+ {
+ version = 0;
+ }
+};
+
+static u32 query_firmware_version()
+{
+ struct __attribute__((aligned(16))) {
+ Prekernel::Mailbox::MessageHeader header;
+ QueryFirmwareVersionMboxMessage query_firmware_version;
+ Prekernel::Mailbox::MessageTail tail;
+ } message_queue;
+
+ if (!Prekernel::Mailbox::the().send_queue(&message_queue, sizeof(message_queue))) {
+ return 0xffff'ffff;
+ }
+
+ return message_queue.query_firmware_version.version;
+}