瀏覽代碼

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.
Marcin Undak 3 年之前
父節點
當前提交
3cc5752a69

+ 105 - 0
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;
+    }
+};
+}

+ 33 - 45
Kernel/Prekernel/Arch/aarch64/Mailbox.cpp

@@ -33,6 +33,30 @@ constexpr u32 MBOX_EMPTY = 0x4000'0000;
 
 
 constexpr int ARM_TO_VIDEOCORE_CHANNEL = 8;
 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)
 static void wait_until_we_can_write(MMIO& mmio)
 {
 {
     // Since nothing else writes to the mailbox, this wait is mostly cargo-culted.
     // 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();
     auto& mmio = MMIO::the();
 
 
     // The mailbox interface has a FIFO for message deliverly in both directions.
     // 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);
     wait_until_we_can_write(mmio);
 
 
     // The mailbox message is 32-bit based, so this assumes that message is in the first 4 GiB.
     // 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);
     mmio.write(MBOX_WRITE_DATA, request);
 
 
     for (;;) {
     for (;;) {
@@ -68,52 +98,10 @@ bool Mailbox::call(u8 channel, u32 volatile* __attribute__((aligned(16))) messag
         u32 response = mmio.read(MBOX_READ_DATA);
         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.
         // We keep at most one message in flight and do synchronous communication, so response will always be == request for us.
         if (response == request)
         if (response == request)
-            return message[1] == MBOX_RESPONSE_SUCCESS;
+            return message_header->success();
     }
     }
 
 
     return true;
     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];
-}
-
 }
 }

+ 34 - 21
Kernel/Prekernel/Arch/aarch64/Mailbox.h

@@ -14,28 +14,41 @@ namespace Prekernel {
 // https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface
 // https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface
 class Mailbox {
 class Mailbox {
 public:
 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;
 };
 };
 
 
 }
 }

+ 37 - 0
Kernel/Prekernel/Arch/aarch64/Timer.cpp

@@ -5,7 +5,9 @@
  */
  */
 
 
 #include <Kernel/Prekernel/Arch/aarch64/MMIO.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/Timer.h>
+#include <Kernel/Prekernel/Arch/aarch64/Utils.h>
 
 
 namespace Prekernel {
 namespace Prekernel {
 
 
@@ -48,4 +50,39 @@ u64 Timer::microseconds_since_boot()
     return (static_cast<u64>(high) << 32) | low;
     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;
+}
+
 }
 }

+ 19 - 0
Kernel/Prekernel/Arch/aarch64/Timer.h

@@ -18,6 +18,25 @@ public:
 
 
     u64 microseconds_since_boot();
     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:
 private:
     Timer();
     Timer();
 
 

+ 2 - 2
Kernel/Prekernel/Arch/aarch64/UART.cpp

@@ -6,7 +6,7 @@
 
 
 #include <Kernel/Prekernel/Arch/aarch64/GPIO.h>
 #include <Kernel/Prekernel/Arch/aarch64/GPIO.h>
 #include <Kernel/Prekernel/Arch/aarch64/MMIO.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>
 #include <Kernel/Prekernel/Arch/aarch64/UART.h>
 
 
 namespace Prekernel {
 namespace Prekernel {
@@ -101,7 +101,7 @@ UART::UART()
 
 
     // Set UART clock so that the baud rate divisor ends up as 1.0.
     // 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.
     // 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.
     // The BCM's PL011 UART is alternate function 0 on pins 14 and 15.
     auto& gpio = Prekernel::GPIO::the();
     auto& gpio = Prekernel::GPIO::the();

+ 28 - 1
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_el2_mode();
 static void set_up_el3_mode();
 static void set_up_el3_mode();
 static void print_current_exception_level(const char* msg);
 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_el2();
 [[noreturn]] static void jump_to_os_start_from_el3();
 [[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("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");
     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_str("Firmware version: ");
     uart.print_num(firmware_version);
     uart.print_num(firmware_version);
     uart.print_str("\r\n");
     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_num(exception_level);
     uart.print_str("\r\n");
     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;
+}