mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 08:27:45 +00:00
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.
This commit is contained in:
parent
82a73b8499
commit
3cc5752a69
7 changed files with 257 additions and 68 deletions
105
Kernel/Prekernel/Arch/aarch64/FramebufferMailboxMessages.h
Normal file
105
Kernel/Prekernel/Arch/aarch64/FramebufferMailboxMessages.h
Normal file
|
@ -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,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];
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
// Base class for Mailbox messages. Implemented in subsystems that use Mailbox.
|
||||||
|
class Message {
|
||||||
|
protected:
|
||||||
|
Message(u32 tag, u32 arguments_size);
|
||||||
|
|
||||||
static u32 query_firmware_version();
|
private:
|
||||||
|
u32 m_tag;
|
||||||
enum class ClockID {
|
u32 m_arguments_size;
|
||||||
Reserved = 0,
|
u32 m_command_tag;
|
||||||
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,
|
|
||||||
};
|
};
|
||||||
static u32 set_clock_rate(ClockID, u32 rate_hz, bool skip_setting_turbo = true);
|
|
||||||
|
// 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;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue