diff options
author | Marcin Undak <mcinek@gmail.com> | 2021-10-16 18:52:31 -0400 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-10-31 12:35:53 +0100 |
commit | 3cc5752a69eebc1a92d447b3bf254faaa5eafb7b (patch) | |
tree | b45c6d746a9ebb6acdd79cc0e089fe20fe20d08b /Kernel/Prekernel | |
parent | 82a73b8499472e1b035ab7b80ef5578de42f2840 (diff) | |
download | serenity-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.h | 105 | ||||
-rw-r--r-- | Kernel/Prekernel/Arch/aarch64/Mailbox.cpp | 78 | ||||
-rw-r--r-- | Kernel/Prekernel/Arch/aarch64/Mailbox.h | 55 | ||||
-rw-r--r-- | Kernel/Prekernel/Arch/aarch64/Timer.cpp | 37 | ||||
-rw-r--r-- | Kernel/Prekernel/Arch/aarch64/Timer.h | 19 | ||||
-rw-r--r-- | Kernel/Prekernel/Arch/aarch64/UART.cpp | 4 | ||||
-rw-r--r-- | Kernel/Prekernel/Arch/aarch64/init.cpp | 29 |
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; +} |