From 81dd29f713331be3e884b026f6714ae7206f2f2f Mon Sep 17 00:00:00 2001 From: Daniel Bertalan Date: Mon, 24 Apr 2023 20:35:29 +0200 Subject: [PATCH] Kernel/aarch64: Support reading the command line via the RPi Mailbox This reuses the existing `RPi::Mailbox` interface to read the command line via a VideoCore-specific mailbox message. This will have to be replaced if that interface starts being smarter, as this is needed very early, and nothing guarantees that a smarter Mailbox interface wouldn't need to allocate or log, which is a no-no during early boot. As the response string can be arbitrarily long, it's the caller's job to provide a long enough buffer for `Mailbox::query_kernel_command_line`. This commit chose 512 bytes, as it provides a large enough headroom over the 150-200 characters implicitly added by the VC firmware. The portable way would be to parse the `/chosen/bootargs` property of the device tree, but we currently lack the scaffolding for doing that. Support for this in QEMU relies on a patch that has not yet been accepted upstream, but is available via our `Toolchain/BuildQEMU.sh` script. It should, however, work on bare metal. Tested-By: Timon Kruiper --- Kernel/Arch/aarch64/RPi/Mailbox.cpp | 36 +++++++++++++++++++++++++++++ Kernel/Arch/aarch64/RPi/Mailbox.h | 4 ++++ Kernel/Arch/init.cpp | 7 +++++- 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/Kernel/Arch/aarch64/RPi/Mailbox.cpp b/Kernel/Arch/aarch64/RPi/Mailbox.cpp index 237ed89c17..9ac0849591 100644 --- a/Kernel/Arch/aarch64/RPi/Mailbox.cpp +++ b/Kernel/Arch/aarch64/RPi/Mailbox.cpp @@ -130,4 +130,40 @@ u32 Mailbox::query_firmware_version() return message_queue.query_firmware_version.version; } +// https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface#get-command-line +// +// Note: This function is called very early in the boot process, before the heap or the console +// is initialized. Please ensure that it does the minimum amount of work possible. +StringView Mailbox::query_kernel_command_line(Bytes buffer) +{ + // We want to use the user-provided buffer rather than a fixed-size one on the stack, + // so we need to construct the message manually. + auto aligned_buffer = buffer.align_to(16); + if (aligned_buffer.size() < 24) + return ""sv; + + auto max_response_length = aligned_buffer.size() - 24; + + auto* message = reinterpret_cast(aligned_buffer.data()); + message[0] = aligned_buffer.size(); + message[1] = MBOX_REQUEST; + + message[2] = 0x0005'0001; // Query command line + message[3] = max_response_length; + message[4] = max_response_length; + + message[aligned_buffer.size() / sizeof(u32) - 1] = 0; + + if (!the().send_queue(message, aligned_buffer.size())) + return ""sv; + + // Bit 31 indicates that this is a response, the rest denote the length. + auto response_length = message[4] & 0x7fff'ffff; + + if (response_length > max_response_length) + return ""sv; // The buffer was too small to hold the response. + + return StringView { (char const*)&message[5], response_length }; +} + } diff --git a/Kernel/Arch/aarch64/RPi/Mailbox.h b/Kernel/Arch/aarch64/RPi/Mailbox.h index c1e67b6e17..658254d6c4 100644 --- a/Kernel/Arch/aarch64/RPi/Mailbox.h +++ b/Kernel/Arch/aarch64/RPi/Mailbox.h @@ -6,6 +6,7 @@ #pragma once +#include #include namespace Kernel::RPi { @@ -51,6 +52,9 @@ public: bool send_queue(void* queue, u32 queue_size) const; u32 query_firmware_version(); + + // Returns the kernel command line as a StringView into the given buffer. + StringView query_kernel_command_line(Bytes buffer); }; } diff --git a/Kernel/Arch/init.cpp b/Kernel/Arch/init.cpp index 883e450d7d..86f5fa082f 100644 --- a/Kernel/Arch/init.cpp +++ b/Kernel/Arch/init.cpp @@ -149,6 +149,10 @@ READONLY_AFTER_INIT u8 multiboot_framebuffer_type; Atomic g_boot_console; +#if ARCH(AARCH64) +READONLY_AFTER_INIT static u8 s_command_line_buffer[512]; +#endif + extern "C" [[noreturn]] UNMAP_AFTER_INIT void init([[maybe_unused]] BootInfo const& boot_info) { g_in_early_boot = true; @@ -193,7 +197,8 @@ extern "C" [[noreturn]] UNMAP_AFTER_INIT void init([[maybe_unused]] BootInfo con multiboot_module_entry_t modules[] = {}; multiboot_modules = modules; multiboot_modules_count = 0; - kernel_cmdline = ""sv; + // FIXME: Read the /chosen/bootargs property. + kernel_cmdline = RPi::Mailbox::the().query_kernel_command_line(s_command_line_buffer); #endif setup_serial_debug();