rpi5_native_boot.c: carve /reserved-memory out of the Pi 5 memory map
Build / build-amd64-iso (push) Canceled after 0s
Build / build-aarch64-iso (push) Canceled after 0s
Build / build-riscv64-img (push) Canceled after 0s

Previously deferred (rpi5_native_boot.c's own header comment flagged this
as needing interval-splitting logic written blind against hardware not
yet in hand) -- revisited by fetching bcm2712-ds.dtsi directly rather than
assuming reserved-memory was empty or absent. It has one static child
(atf@0, ARM Trusted Firmware's own region) and one dynamic child
(linux,cma, size/alloc-ranges only, no fixed reg) -- the dynamic one is
skipped, nothing fixed to carve and no allocator this early to service it
against anyway.

Adds two fdt.c primitives: fdt_find_node_by_name() (reserved-memory has
neither compatible nor device_type per DT spec) and fdt_next_child_node()
-- one exported symbol, not the two-primitive general sibling-walker
originally sketched, collapsed after review since the only real use here
is "iterate one node's direct children."

collect_reserved_ranges() reads each child's own #address-cells/
#size-cells with a fallback to root's only if absent -- confirmed
necessary, not just defensive: reserved-memory's own declared <2>/<1>
genuinely differs from root's <2>/<2>. emit_region_with_carveouts()
clips a sorted reserved-range list against each RAM region, emitting
alternating EfiConventionalMemory gaps and EfiReservedMemoryType
carve-outs (insertion sort, no libc qsort in freestanding).
RPI5_MAX_MEMMAP_ENTRIES is the exact worst-case count, recomputed rather
than estimated -- the rpi5_mailbox.c buffer-size bug is the standing
lesson for this pattern.

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:
Robert Allan James
2026-09-04 22:24:57 -04:00
co-authored by Claude Sonnet 5
parent 67e3fb7459
commit 7187d68082
12 changed files with 28050 additions and 50 deletions
+181
View File
@@ -325,6 +325,187 @@ const void* fdt_find_node_by_device_type(const void* fdt, const char* type)
return (void*)0;
}
/**
* @brief Test whether a node-name string (blob text, possibly followed by
* an `@unit-address`) matches @p want up to that boundary.
*/
static int node_name_eq(const char* node_name, const char* want)
{
while (*want && *node_name && *node_name == *want)
{
node_name++;
want++;
}
if (*want) return 0;
return *node_name == '\0' || *node_name == '@';
}
const void* fdt_find_node_by_name(const void* fdt, const char* name)
{
const fdt_header_t* h = (const fdt_header_t*)fdt;
const unsigned char *base, *p, *end;
uint32_t size_struct;
if (!fdt_valid(fdt) || !name) 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;
/* Matching by the node's own inline name needs no strings-block
* lookup, unlike the compatible/device_type finders above. */
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;
if (node_name_eq((const char*)p, name))
{
return (const void*)(((uintptr_t)(q + 1) + 3u) & ~(uintptr_t)3u);
}
p = (const unsigned char*)(((uintptr_t)(q + 1) + 3u) & ~(uintptr_t)3u);
}
else if (token == FDT_PROP)
{
uint32_t len;
if (p + 8 > end) break;
len = be32(p);
p += 8;
if (len > (uint32_t)(end - p)) break;
p = (const unsigned char*)(((uintptr_t)(p + len) + 3u) & ~(uintptr_t)3u);
}
else if (token == FDT_END_NODE || token == FDT_NOP)
{
/* no payload */
}
else
{
break;
}
}
return (void*)0;
}
/**
* @brief Advance @p p past one complete node body (properties, then every
* descendant, recursively via a depth counter) starting just inside it
* (i.e. @p p is a node handle, right after its own FDT_BEGIN_NODE name),
* stopping just after the matching FDT_END_NODE.
*
* Internal to @c fdt_next_child_node() — a node handle's own children may
* have further descendants even though this reader's public node-lookup
* functions never return anything but direct-child handles, so finding
* the *next sibling* after a child still requires skipping past whatever
* that child itself contains.
*/
static const unsigned char* skip_node_body(const unsigned char* p, const unsigned char* end)
{
int depth = 1;
while (p + 4 <= end && depth > 0)
{
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) return end;
p = (const unsigned char*)(((uintptr_t)(q + 1) + 3u) & ~(uintptr_t)3u);
depth++;
}
else if (token == FDT_PROP)
{
uint32_t len;
if (p + 8 > end) return end;
len = be32(p);
p += 8;
if (len > (uint32_t)(end - p)) return end;
p = (const unsigned char*)(((uintptr_t)(p + len) + 3u) & ~(uintptr_t)3u);
}
else if (token == FDT_END_NODE)
{
depth--;
}
else if (token == FDT_NOP)
{
/* no payload */
}
else
{
return end;
}
}
return p;
}
const void* fdt_next_child_node(const void* fdt, const void* parent,
const void* prev_child)
{
const fdt_header_t* h = (const fdt_header_t*)fdt;
const unsigned char *end, *p;
if (!fdt_valid(fdt) || !parent) return (void*)0;
end = (const unsigned char*)fdt + be32(&h->off_dt_struct) + be32(&h->size_dt_struct);
p = prev_child ? skip_node_body((const unsigned char*)prev_child, end)
: (const unsigned char*)parent;
/* If prev_child is NULL, p starts at parent's own leading property
* list -- skip past those the same way fdt_find_prop_in_node() does.
* If prev_child is non-NULL, skip_node_body() already consumed that
* child's own properties and descendants, so this loop sees only
* FDT_BEGIN_NODE (the next sibling) or FDT_END_NODE (parent closing)
* immediately. */
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) return (void*)0;
return (const void*)(((uintptr_t)(q + 1) + 3u) & ~(uintptr_t)3u);
}
else if (token == FDT_PROP)
{
uint32_t len;
if (p + 8 > end) break;
len = be32(p);
p += 8;
if (len > (uint32_t)(end - p)) break;
p = (const unsigned char*)(((uintptr_t)(p + len) + 3u) & ~(uintptr_t)3u);
}
else if (token == FDT_NOP)
{
/* no payload */
}
else
{
/* FDT_END_NODE (parent closing), FDT_END, or unknown */
return (void*)0;
}
}
return (void*)0;
}
const void* fdt_find_prop_in_node(const void* fdt, const void* node,
const char* name, uint32_t* len_out)
{