rpi5_native_boot.c: Pi 5 DTB->BootInfo constructor (FABRIC-3.md §IV.3 item 2)
rpi5_native_boot() populates the existing BootInfo struct from the devicetree instead of UEFI protocols, then calls the existing, unmodified kernel_main() -- the crux of why most of M1-M9 stays shared between the UEFI and native boot paths. native_rpi5_entry.S now tail-calls into it instead of halting. memory_map is built from /memory's own reg, honoring the *root* node's #address-cells/#size-cells (confirmed against bcm2712.dtsi's actual root node -- <2>/<2> -- not assumed; a wrong cell width here would compile and boot clean in QEMU while silently corrupting the real memory map on real silicon). Required a new fdt_find_node_by_device_type() since /memory is identified by device_type = "memory" per DT spec, not compatible. args comes from /chosen's bootargs fed into the existing cmdline_parse_ascii() (confirmed pure C99 with no UEFI coupling before reusing it). framebuffer comes from the already-built rpi5_mailbox_get_framebuffer() at a fixed 1920x1080x32 default -- no EDID query exists in this codebase, flagged rather than guessed past. Deliberately scoped out, not silently skipped: /reserved-memory is not parsed. Carving reserved sub-ranges out of /memory's span needs interval-splitting logic that would be written blind against hardware not yet in hand -- exactly the kind of code that hides a bug until real silicon. pmm.c's Pass 3 only ever clears pages this file lists as EfiConventionalMemory, so the gap is "less usable RAM than optimal," never "reserved RAM wrongly marked free." Left as its own future item. Also fixes a real link failure this work surfaced: boot/cmdline.c was only in LOADER_SRCS_BASE (the .efi target), not KERNEL_SRCS_BASE (the separate .elf target arch/aarch64/*.c also wildcards into) -- added it there too. Compile-only-verified; nothing in the existing UEFI/QEMU path calls rpi5_native_boot(), so this cannot be exercised until real hardware. Verified 3-arch boot to ok>/zuse)ok>. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019YcT3H2PQeyujrzjqS3Var
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
281de9547c
commit
67e3fb7459
+35
-11
@@ -315,17 +315,41 @@ blocker for free.
|
||||
loop) afterward rather than tail-calling into item 2's constructor, which doesn't exist yet.
|
||||
**Not yet linked at `0x80000`** — that needs its own linker script/build target (item 6's own
|
||||
`config.txt` work is the sibling piece; the separate-image build itself is not scoped into
|
||||
this item). Verified 3-arch boot to `ok>`/`zuse)ok>` — `Makefile.starkernel`'s `KERNEL_ASM`
|
||||
wildcards every `*.S` in `arch/aarch64/`, so this file compiles and links into the existing
|
||||
QEMU/UEFI acceptance build as dead code (unreferenced symbol, nothing there ever branches to
|
||||
it), same as `rpi5_dtb.c`/`rpi5_mailbox.c` before it.
|
||||
2. **DTB → `BootInfo` constructor**: new C function populating the *existing* `BootInfo`
|
||||
struct (`include/starkernel/uefi.h`) from the DTB instead of UEFI protocols — `dtb` = the
|
||||
real pointer, `acpi_table` = `NULL` (already the correct value for "no ACPI," per IV's own
|
||||
research above), `runtime_services` = `NULL`, `memory_map`/`framebuffer`/`args` populated
|
||||
from DTB `/memory`+`/reserved-memory`, the mailbox interface (next item), and DTB `/chosen`
|
||||
`bootargs` respectively. Then calls the **existing, unmodified** `kernel_main()` — this is
|
||||
the crux of why most of M1–M9 stays shared.
|
||||
this item). Now tail-calls item 2's constructor (below) instead of halting — updated
|
||||
2026-09-04 when that item landed. Verified 3-arch boot to `ok>`/`zuse)ok>` —
|
||||
`Makefile.starkernel`'s `KERNEL_ASM` wildcards every `*.S` in `arch/aarch64/`, so this file
|
||||
compiles and links into the existing QEMU/UEFI acceptance build as dead code (unreferenced
|
||||
symbol, nothing there ever branches to it), same as `rpi5_dtb.c`/`rpi5_mailbox.c` before it.
|
||||
2. **DTB → `BootInfo` constructor — DONE 2026-09-04.** New
|
||||
`include/starkernel/rpi5_native_boot.h` / `src/starkernel/arch/aarch64/rpi5_native_boot.c`:
|
||||
`rpi5_native_boot()` populates the *existing* `BootInfo` struct from the devicetree instead
|
||||
of UEFI protocols (`dtb` = the real pointer, `acpi_table`/`runtime_services` = `NULL`,
|
||||
`kernel_stack_base` = `NULL`/BSS-fallback — aarch64 has no `kernel_entry.S` trampoline at
|
||||
all, so item 1's own BSS stack already *is* the stack `kernel_main_impl` runs on),
|
||||
`args` via `/chosen`'s `bootargs` fed straight into the *existing*
|
||||
`cmdline_parse_ascii()` (pure C99, no UEFI coupling — confirmed before reusing it, not
|
||||
assumed), `framebuffer` via item 3's `rpi5_mailbox_get_framebuffer()` at a fixed
|
||||
1920x1080x32 default (no EDID query exists in this codebase — flagged, not guessed past
|
||||
this comment, revisit once real hardware and a real attached display are in hand), then
|
||||
calls the **existing, unmodified** `kernel_main()` — this is the crux of why most of M1–M9
|
||||
stays shared. `memory_map` comes from `/memory`'s own `reg`, honoring the *root* node's
|
||||
`#address-cells`/`#size-cells` (confirmed against `bcm2712.dtsi`'s actual root node — `<2>`/
|
||||
`<2>` — not assumed; a hardcoded-wrong cell width here would compile clean and boot clean in
|
||||
QEMU while silently corrupting the real memory map on real silicon, so this was verified
|
||||
from the source rather than recalled). Required a new `fdt_find_node_by_device_type()`
|
||||
(`fdt.c`/`fdt.h`) since `/memory` is identified by `device_type = "memory"` per DT spec
|
||||
§3.4, not `compatible`. Required a Makefile fix: `boot/cmdline.c` was only in `LOADER_SRCS_BASE`
|
||||
(the `.efi` target), not `KERNEL_SRCS_BASE` (the separate `.elf` target `arch/aarch64/*.c`
|
||||
also wildcards into) — added it there too, a real link failure caught before it could ship.
|
||||
**Deliberately scoped out, not silently skipped:** `/reserved-memory` is not parsed —
|
||||
carving reserved sub-ranges out of `/memory`'s span needs interval-splitting logic that
|
||||
would be written blind against hardware not yet in hand, exactly the kind of code that
|
||||
hides a bug until real silicon; left as its own future item. `memory/pmm.c`'s Pass 3 only
|
||||
ever clears pages this file explicitly lists as `EfiConventionalMemory`, so the gap is
|
||||
"less usable RAM than optimal," never "reserved RAM wrongly marked free." Verified 3-arch
|
||||
boot to `ok>`/`zuse)ok>` — compile-only, same caveat as every item in this list: nothing in
|
||||
the existing UEFI/QEMU path calls `rpi5_native_boot()`, so this cannot be exercised until
|
||||
real hardware.
|
||||
3. **Mailbox-property-interface framebuffer driver — DONE 2026-09-04.** New
|
||||
`include/starkernel/rpi5_mailbox.h` / `src/starkernel/arch/aarch64/rpi5_mailbox.c`:
|
||||
`rpi5_mailbox_get_framebuffer()` builds and sends one property-tag buffer (phys size, virt
|
||||
|
||||
@@ -479,6 +479,7 @@ endif
|
||||
|
||||
KERNEL_SRCS_BASE := \
|
||||
$(KERNEL_SRC)/kernel_main.c \
|
||||
$(KERNEL_SRC)/boot/cmdline.c \
|
||||
$(wildcard $(KERNEL_SRC)/hal/*.c) \
|
||||
$(wildcard $(KERNEL_SRC)/memory/*.c) \
|
||||
$(wildcard $(KERNEL_SRC)/math/*.c) \
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Capsule Block Manifest — Auto-generated
|
||||
<!-- Generated by mkcapsule --manifest 2026-09-04T18:10:39Z -->
|
||||
<!-- Generated by mkcapsule --manifest 2026-09-04T18:40:17Z -->
|
||||
<!-- DO NOT EDIT — re-run mkcapsule --manifest to refresh. -->
|
||||
<!-- Hand-written justifications and immutability notes live -->
|
||||
<!-- in MANIFEST.md alongside this auto-generated index. -->
|
||||
|
||||
Binary file not shown.
@@ -85,6 +85,23 @@ int fdt_prop_u32(const void* fdt, const char* name, uint32_t* out);
|
||||
*/
|
||||
const void* fdt_find_node_by_compatible(const void* fdt, const char* compatible);
|
||||
|
||||
/**
|
||||
* @brief Find the first node whose "device_type" property equals @p type.
|
||||
*
|
||||
* Some standard nodes (`/memory` per DT spec §3.4) are identified by
|
||||
* `device_type`, not `compatible` — unlike `compatible`, `device_type` is a
|
||||
* single NUL-terminated string, not a list, so this matches the whole
|
||||
* property value rather than scanning entries within it. Scans the whole
|
||||
* tree in document order; the first matching node wins if more than one
|
||||
* exists.
|
||||
*
|
||||
* @param fdt Blob, already checked with @c fdt_valid().
|
||||
* @param type device_type value to match, NUL-terminated.
|
||||
* @return An opaque handle to the matched node, for use with
|
||||
* @c fdt_find_prop_in_node() only — or NULL if no node matches.
|
||||
*/
|
||||
const void* fdt_find_node_by_device_type(const void* fdt, const char* type);
|
||||
|
||||
/**
|
||||
* @brief Find a property by name, scoped to one node.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
StarForth — Steady-State Virtual Machine Runtime
|
||||
Copyright (c) 2023–2025 Robert A. James. All rights reserved.
|
||||
Licensed under the StarForth License, Version 1.0.
|
||||
*/
|
||||
|
||||
/**
|
||||
* rpi5_native_boot.h - Raspberry Pi 5 DTB->BootInfo constructor
|
||||
* (FABRIC-3.md §IV.3 item 2).
|
||||
*
|
||||
* `native_rpi5_entry.S`'s `rpi5_native_start` tail-calls
|
||||
* `rpi5_native_boot()` with the masked DTB pointer it captured. This
|
||||
* function builds the *existing*, unmodified `BootInfo` struct
|
||||
* (`include/starkernel/uefi.h`) from the devicetree instead of UEFI
|
||||
* protocols, then calls the *existing*, unmodified `kernel_main()` — see
|
||||
* this file's own `.c` for exactly what is and is not populated, and why.
|
||||
*/
|
||||
|
||||
#ifndef STARKERNEL_RPI5_NATIVE_BOOT_H
|
||||
#define STARKERNEL_RPI5_NATIVE_BOOT_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void rpi5_native_boot(uint64_t dtb) __attribute__((noreturn));
|
||||
|
||||
#endif /* STARKERNEL_RPI5_NATIVE_BOOT_H */
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -16,14 +16,15 @@
|
||||
* UNSPECIFIED -- must mask before use.
|
||||
* x1-x3 = reserved / zero, unused here.
|
||||
*
|
||||
* This stub's own job, and nothing more yet: mask and capture that DTB
|
||||
* pointer into `g_rpi5_dtb_ptr` (declared in
|
||||
* `include/starkernel/rpi5_native_entry.h`) where the still-open
|
||||
* DTB->BootInfo constructor (§IV.3 item 2) can find it, then establish a
|
||||
* dedicated stack -- this path has no EDK2 boot stack to inherit, there is
|
||||
* no EDK2 at all here. It intentionally halts afterward rather than
|
||||
* tail-calling into a function that does not exist yet; wiring that call
|
||||
* is item 2's own job, not this one's.
|
||||
* This stub's own job: mask and capture that DTB pointer into
|
||||
* `g_rpi5_dtb_ptr` (declared in `include/starkernel/rpi5_native_entry.h`),
|
||||
* establish a dedicated stack -- this path has no EDK2 boot stack to
|
||||
* inherit, there is no EDK2 at all here -- then tail-call
|
||||
* `rpi5_native_boot()` (`rpi5_native_boot.c`, §IV.3 item 2), which builds
|
||||
* `BootInfo` from the devicetree and calls the existing `kernel_main()`.
|
||||
* `rpi5_native_boot()` never returns; the `wfe`/`b` loop after the `bl`
|
||||
* exists only so this file's own control flow has somewhere defined to
|
||||
* go if that contract is ever violated.
|
||||
*
|
||||
* Build-system note: `Makefile.starkernel`'s `KERNEL_ASM` wildcards every
|
||||
* `*.S` file in this directory into the monolithic kernel ELF build (not
|
||||
@@ -68,9 +69,13 @@ rpi5_native_start:
|
||||
add x0, x0, :lo12:g_rpi5_native_stack_top
|
||||
mov sp, x0
|
||||
|
||||
/* §IV.3 item 2 (DTB->BootInfo constructor) does not exist yet --
|
||||
* halt rather than branch to a function that isn't real. Replace
|
||||
* this loop with a tail call once that item lands. */
|
||||
/* x0 was clobbered above for the stack-top address -- reload the
|
||||
* masked DTB pointer from g_rpi5_dtb_ptr before calling in. */
|
||||
adrp x0, g_rpi5_dtb_ptr
|
||||
add x0, x0, :lo12:g_rpi5_dtb_ptr
|
||||
ldr x0, [x0]
|
||||
bl rpi5_native_boot
|
||||
|
||||
.Lhalt:
|
||||
wfe
|
||||
b .Lhalt
|
||||
|
||||
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
StarForth — Steady-State Virtual Machine Runtime
|
||||
Copyright (c) 2023–2025 Robert A. James. All rights reserved.
|
||||
Licensed under the StarForth License, Version 1.0.
|
||||
*/
|
||||
|
||||
/**
|
||||
* rpi5_native_boot.c - Raspberry Pi 5 DTB->BootInfo constructor
|
||||
* (FABRIC-3.md §IV.3 item 2, 2026-09-04).
|
||||
*
|
||||
* **Never run on real hardware** -- the Pi 5 isn't in hand until
|
||||
* 2026-09-17 (FABRIC-3.md §II). Compile-only-verified; 3-arch QEMU boot
|
||||
* confirms this compiles and links, and does not disturb the existing
|
||||
* UEFI/ACPI path -- it cannot exercise a single line of this function,
|
||||
* since nothing in that path calls it (same caveat as
|
||||
* `rpi5_dtb.c`/`rpi5_mailbox.c`/`native_rpi5_entry.S` before it).
|
||||
*
|
||||
* `rpi5_native_start` (`native_rpi5_entry.S`) tail-calls this function
|
||||
* with the masked DTB pointer it captured. This builds the *existing*,
|
||||
* unmodified `BootInfo` struct from the devicetree instead of UEFI
|
||||
* protocols, then calls the *existing*, unmodified `kernel_main()` --
|
||||
* this is the crux of why most of M1-M9 stays shared between the UEFI
|
||||
* and native boot paths.
|
||||
*
|
||||
* What this deliberately does NOT do yet, named honestly rather than
|
||||
* silently skipped:
|
||||
*
|
||||
* - **`/reserved-memory` is not parsed.** Only `/memory`'s own `reg` is
|
||||
* turned into `EfiConventionalMemory` descriptors. Carving reserved
|
||||
* sub-ranges (VideoCore firmware regions, CMA, etc.) out of that span
|
||||
* requires interval-splitting logic that would be written blind
|
||||
* against hardware not yet in hand -- exactly the kind of code that
|
||||
* hides a subtle bug until real silicon. Deferred to its own
|
||||
* FABRIC-3.md item rather than merged into this one. The bitmap PMM
|
||||
* builds from this memory map starts fully reserved and only clears
|
||||
* pages this file lists as `EfiConventionalMemory`
|
||||
* (`memory/pmm.c`'s Pass 3) -- so the gap here is "less RAM than
|
||||
* optimal," never "reserved RAM wrongly marked free."
|
||||
* - **The mailbox framebuffer request uses a fixed 1920x1080x32
|
||||
* default**, not real display negotiation (no EDID query exists in
|
||||
* this codebase). Flagged, not guessed past this comment -- revisit
|
||||
* once real hardware and a real attached display are in hand.
|
||||
* - **Root `#address-cells`/`#size-cells` must be exactly 1 or 2** --
|
||||
* confirmed against `bcm2712.dtsi`'s actual root node (2/2) before
|
||||
* writing this, not assumed; other widths halt rather than guess.
|
||||
*/
|
||||
|
||||
#include "starkernel/rpi5_native_boot.h"
|
||||
#include "starkernel/fdt.h"
|
||||
#include "starkernel/rpi5_mailbox.h"
|
||||
#include "starkernel/cmdline.h"
|
||||
#include "starkernel/uefi.h"
|
||||
|
||||
#define RPI5_MAX_MEMMAP_ENTRIES 8
|
||||
#define RPI5_FB_DEFAULT_WIDTH 1920u
|
||||
#define RPI5_FB_DEFAULT_HEIGHT 1080u
|
||||
#define RPI5_FB_DEFAULT_BPP 32u
|
||||
|
||||
extern void kernel_main(BootInfo *boot_info);
|
||||
|
||||
static BootInfo g_rpi5_boot_info = {0};
|
||||
static EFI_MEMORY_DESCRIPTOR g_rpi5_memmap[RPI5_MAX_MEMMAP_ENTRIES];
|
||||
|
||||
static uint32_t be32_at(const unsigned char *p)
|
||||
{
|
||||
return ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16) |
|
||||
((uint32_t)p[2] << 8) | (uint32_t)p[3];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read one big-endian cell group (1 or 2 u32 cells) as a uint64_t.
|
||||
*/
|
||||
static uint64_t read_cells(const unsigned char *p, uint32_t ncells)
|
||||
{
|
||||
if (ncells == 1) return (uint64_t)be32_at(p);
|
||||
return ((uint64_t)be32_at(p) << 32) | (uint64_t)be32_at(p + 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Halt this core. No console exists yet (M1 hasn't run) and there
|
||||
* is nowhere safe to report failure -- this is the same halt shape
|
||||
* `native_rpi5_entry.S` itself uses before this function existed.
|
||||
*/
|
||||
static void rpi5_native_halt(void) __attribute__((noreturn));
|
||||
|
||||
static void rpi5_native_halt(void)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
__asm__ volatile("wfe");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Parse `/memory`'s `reg` into `g_rpi5_memmap`, honoring the
|
||||
* root's own `#address-cells`/`#size-cells` (NOT the `soc` node's -- see
|
||||
* this file's own doc comment; `/memory` is a direct child of root).
|
||||
*
|
||||
* @return Number of entries written (0 on any failure).
|
||||
*/
|
||||
static uint32_t build_memory_map(const void *dtb)
|
||||
{
|
||||
uint32_t acells, scells;
|
||||
const void *mem_node;
|
||||
const void *reg;
|
||||
uint32_t reg_len;
|
||||
uint32_t entry_bytes, count, i;
|
||||
const unsigned char *p;
|
||||
|
||||
if (!fdt_prop_u32(dtb, "#address-cells", &acells) ||
|
||||
!fdt_prop_u32(dtb, "#size-cells", &scells))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if ((acells != 1 && acells != 2) || (scells != 1 && scells != 2))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
mem_node = fdt_find_node_by_device_type(dtb, "memory");
|
||||
if (!mem_node) return 0;
|
||||
|
||||
reg = fdt_find_prop_in_node(dtb, mem_node, "reg", ®_len);
|
||||
if (!reg) return 0;
|
||||
|
||||
entry_bytes = (acells + scells) * 4u;
|
||||
if (entry_bytes == 0) return 0;
|
||||
|
||||
count = reg_len / entry_bytes;
|
||||
if (count > RPI5_MAX_MEMMAP_ENTRIES) count = RPI5_MAX_MEMMAP_ENTRIES;
|
||||
|
||||
p = (const unsigned char *)reg;
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
uint64_t addr = read_cells(p, acells);
|
||||
uint64_t size = read_cells(p + acells * 4u, scells);
|
||||
|
||||
g_rpi5_memmap[i].Type = EfiConventionalMemory;
|
||||
g_rpi5_memmap[i].PhysicalStart = addr;
|
||||
g_rpi5_memmap[i].VirtualStart = addr;
|
||||
g_rpi5_memmap[i].NumberOfPages = size / 4096u;
|
||||
g_rpi5_memmap[i].Attribute = 0;
|
||||
|
||||
p += entry_bytes;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
void rpi5_native_boot(uint64_t dtb)
|
||||
{
|
||||
const void *dtb_ptr = (const void *)(uintptr_t)dtb;
|
||||
uint32_t memmap_count;
|
||||
const void *bootargs;
|
||||
uint32_t bootargs_len;
|
||||
Rpi5FramebufferInfo fb;
|
||||
|
||||
if (!fdt_valid(dtb_ptr))
|
||||
{
|
||||
rpi5_native_halt();
|
||||
}
|
||||
|
||||
memmap_count = build_memory_map(dtb_ptr);
|
||||
if (memmap_count == 0)
|
||||
{
|
||||
rpi5_native_halt();
|
||||
}
|
||||
|
||||
g_rpi5_boot_info.memory_map = g_rpi5_memmap;
|
||||
g_rpi5_boot_info.memory_map_size =
|
||||
(UINTN)memmap_count * sizeof(EFI_MEMORY_DESCRIPTOR);
|
||||
g_rpi5_boot_info.memory_map_descriptor_size = sizeof(EFI_MEMORY_DESCRIPTOR);
|
||||
g_rpi5_boot_info.runtime_services = (void *)0;
|
||||
/* No ACPI at all on this path (§IV.1) -- NULL is the already-correct
|
||||
* value every existing acpi_table consumer already degrades safely
|
||||
* against. */
|
||||
g_rpi5_boot_info.acpi_table = (void *)0;
|
||||
g_rpi5_boot_info.dtb = (void *)dtb_ptr;
|
||||
|
||||
/* No UEFI boot services ever existed on this path -- there is no
|
||||
* EDK2 here at all, so "exited" is the closest honest value (no
|
||||
* downstream consumer branches on this field today; it is not a
|
||||
* live behavioral gate). */
|
||||
g_rpi5_boot_info.uefi_boot_services_exited = 1;
|
||||
|
||||
/* No dynamic allocator exists this early -- fall back to the 2 MiB
|
||||
* BSS stack, same convention as every other boot path. Unlike
|
||||
* amd64/riscv64, aarch64 has no kernel_entry.S trampoline to honor
|
||||
* this field: `native_rpi5_entry.S`'s own BSS stack already *is* the
|
||||
* stack kernel_main_impl runs on, so this is a documented fact about
|
||||
* this path, not a live fallback switch. */
|
||||
g_rpi5_boot_info.kernel_stack_base = (void *)0;
|
||||
g_rpi5_boot_info.kernel_stack_size = 0;
|
||||
|
||||
bootargs = fdt_find_prop(dtb_ptr, "bootargs", &bootargs_len);
|
||||
cmdline_parse_ascii(bootargs ? (const char *)bootargs : (const char *)0,
|
||||
&g_rpi5_boot_info.args);
|
||||
|
||||
g_rpi5_boot_info.framebuffer.base = (void *)0;
|
||||
g_rpi5_boot_info.framebuffer.size = 0;
|
||||
g_rpi5_boot_info.framebuffer.width = 0;
|
||||
g_rpi5_boot_info.framebuffer.height = 0;
|
||||
g_rpi5_boot_info.framebuffer.pixels_per_scanline = 0;
|
||||
g_rpi5_boot_info.framebuffer.pixel_format = 0;
|
||||
|
||||
if (rpi5_mailbox_get_framebuffer(dtb_ptr, RPI5_FB_DEFAULT_WIDTH,
|
||||
RPI5_FB_DEFAULT_HEIGHT,
|
||||
RPI5_FB_DEFAULT_BPP, &fb) == 0)
|
||||
{
|
||||
g_rpi5_boot_info.framebuffer.base = fb.base;
|
||||
g_rpi5_boot_info.framebuffer.size = fb.size;
|
||||
g_rpi5_boot_info.framebuffer.width = fb.width;
|
||||
g_rpi5_boot_info.framebuffer.height = fb.height;
|
||||
g_rpi5_boot_info.framebuffer.pixels_per_scanline = fb.pixels_per_scanline;
|
||||
g_rpi5_boot_info.framebuffer.pixel_format = fb.pixel_format;
|
||||
}
|
||||
/* On failure, framebuffer stays zeroed -- the same degraded state the
|
||||
* UEFI path already leaves it in when GOP is BltOnly/absent
|
||||
* (`boot/uefi_loader.c`). */
|
||||
|
||||
kernel_main(&g_rpi5_boot_info);
|
||||
|
||||
/* kernel_main() never returns (REPL loop or panic) -- this is
|
||||
* unreachable, kept only so the noreturn contract holds even if that
|
||||
* ever changes. */
|
||||
rpi5_native_halt();
|
||||
}
|
||||
@@ -256,6 +256,75 @@ const void* fdt_find_node_by_compatible(const void* fdt, const char* compatible)
|
||||
return (void*)0;
|
||||
}
|
||||
|
||||
const void* fdt_find_node_by_device_type(const void* fdt, const char* type)
|
||||
{
|
||||
const fdt_header_t* h = (const fdt_header_t*)fdt;
|
||||
const unsigned char *base, *p, *end, *strings;
|
||||
uint32_t size_struct;
|
||||
int fresh_node = 0;
|
||||
const void* node_body_start = (void*)0;
|
||||
|
||||
if (!fdt_valid(fdt) || !type) return (void*)0;
|
||||
|
||||
base = (const unsigned char*)fdt;
|
||||
size_struct = be32(&h->size_dt_struct);
|
||||
p = base + be32(&h->off_dt_struct);
|
||||
end = p + size_struct;
|
||||
strings = base + be32(&h->off_dt_strings);
|
||||
|
||||
while (p + 4 <= end)
|
||||
{
|
||||
uint32_t token = be32(p);
|
||||
p += 4;
|
||||
|
||||
if (token == FDT_BEGIN_NODE)
|
||||
{
|
||||
const unsigned char* q = p;
|
||||
while (q < end && *q) q++;
|
||||
if (q >= end) break;
|
||||
p = (const unsigned char*)(((uintptr_t)(q + 1) + 3u) & ~(uintptr_t)3u);
|
||||
fresh_node = 1;
|
||||
node_body_start = (const void*)p;
|
||||
}
|
||||
else if (token == FDT_PROP)
|
||||
{
|
||||
uint32_t len, nameoff;
|
||||
const unsigned char* val;
|
||||
|
||||
if (p + 8 > end) break;
|
||||
len = be32(p);
|
||||
nameoff = be32(p + 4);
|
||||
p += 8;
|
||||
val = p;
|
||||
if (len > (uint32_t)(end - p)) break;
|
||||
|
||||
if (fresh_node &&
|
||||
str_eq((const char*)(strings + nameoff), "device_type") &&
|
||||
str_eq((const char*)val, type))
|
||||
{
|
||||
return node_body_start;
|
||||
}
|
||||
|
||||
p = (const unsigned char*)(((uintptr_t)(p + len) + 3u) & ~(uintptr_t)3u);
|
||||
}
|
||||
else if (token == FDT_END_NODE)
|
||||
{
|
||||
fresh_node = 0;
|
||||
}
|
||||
else if (token == FDT_NOP)
|
||||
{
|
||||
/* no payload; does not end the leading property list */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* FDT_END, or a token this reader does not know: stop. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (void*)0;
|
||||
}
|
||||
|
||||
const void* fdt_find_prop_in_node(const void* fdt, const void* node,
|
||||
const char* name, uint32_t* len_out)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user