fix(raspi): the Pi 5's native path turns the MMU and caches on before any C; bounded mailbox; framebuffer address from dma-ranges
boards/BRINGUP.md R2/R3, FABRIC-3 SXXXIX. The entry stub cleans the cache over the image, builds an identity map (the image's GiB Normal, the rest Device) and enables MMU and caches at EL2 (or EL1); rpi5_mmu.c makes the devicetree's RAM Normal and the framebuffer uncached. Mailbox waits give up after one second; the buffer is cleaned around the exchange; the framebuffer address goes through dma-ranges, not a Pi 4 mask. New rpi5-rehearsal target runs the native image on QEMU virt at EL2. It found three more that would each have stopped the board: the PL011 shift (mine, c9519173; the host test asserted it), the GIC address not carried through /soc's ranges (new fdt_reg_address(), checked against the real Pi 5 DTB), and no timer IRQ at EL2 (HCR_EL2.IMO/FMO/AMO). Rehearsal: POST 1052 passed, same parity hash as UEFI. Standard acceptance on three ISAs: POST 1052, hash 0x82f4ae7cb2e2d424. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
4da370f492
commit
0e2c60dac3
@@ -654,3 +654,97 @@ const void* fdt_find_prop_in_node(const void* fdt, const void* node,
|
||||
|
||||
return (void*)0;
|
||||
}
|
||||
|
||||
/* ---- a node's address, carried through its buses (2026-10-14) ---- */
|
||||
|
||||
#define FDT_PATH_MAX 12u
|
||||
|
||||
static uint32_t node_cells(const void* fdt, const void* node, const char* name, uint32_t otherwise)
|
||||
{
|
||||
uint32_t len;
|
||||
const void* v = fdt_find_prop_in_node(fdt, node, name, &len);
|
||||
return (v && len == 4) ? be32(v) : otherwise;
|
||||
}
|
||||
|
||||
static uint64_t read_cells_at(const unsigned char* p, uint32_t n)
|
||||
{
|
||||
return n == 2 ? ((uint64_t)be32(p) << 32) | be32(p + 4) : (uint64_t)be32(p);
|
||||
}
|
||||
|
||||
static int node_enabled(const void* fdt, const void* node)
|
||||
{
|
||||
uint32_t len;
|
||||
const char* v = (const char*)fdt_find_prop_in_node(fdt, node, "status", &len);
|
||||
return !v || compat_list_contains(v, len, "okay") || compat_list_contains(v, len, "ok");
|
||||
}
|
||||
|
||||
/* Depth first: the path from the root to the first enabled node
|
||||
* compatible with `want` -- path[0] the root, path[depth-1] the node. */
|
||||
static uint32_t path_to(const void* fdt, const void* node, const char* want,
|
||||
const void** path, uint32_t depth)
|
||||
{
|
||||
const void* child = (const void*)0;
|
||||
uint32_t len;
|
||||
const char* c;
|
||||
|
||||
if (depth >= FDT_PATH_MAX) return 0;
|
||||
path[depth] = node;
|
||||
c = (const char*)fdt_find_prop_in_node(fdt, node, "compatible", &len);
|
||||
if (c && compat_list_contains(c, len, want) && node_enabled(fdt, node)) return depth + 1;
|
||||
while ((child = fdt_next_child_node(fdt, node, child)) != (const void*)0)
|
||||
{
|
||||
uint32_t d = path_to(fdt, child, want, path, depth + 1);
|
||||
if (d) return d;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_reg_address(const void* fdt, const char* compatible, uint32_t index, uint64_t* out)
|
||||
{
|
||||
const void* path[FDT_PATH_MAX];
|
||||
const unsigned char* reg;
|
||||
const void* root;
|
||||
uint32_t depth, len, ac, sc, i;
|
||||
uint64_t addr;
|
||||
|
||||
if (!out || !compatible || !fdt_complete(fdt)) return 0;
|
||||
root = fdt_root_node(fdt);
|
||||
if (!root) return 0;
|
||||
depth = path_to(fdt, root, compatible, path, 0);
|
||||
if (depth < 2) return 0;
|
||||
|
||||
/* entry `index` of its reg, in its parent's cells */
|
||||
ac = node_cells(fdt, path[depth - 2], "#address-cells", 2);
|
||||
sc = node_cells(fdt, path[depth - 2], "#size-cells", 1);
|
||||
if (ac < 1 || ac > 2 || sc > 2) return 0;
|
||||
reg = (const unsigned char*)fdt_find_prop_in_node(fdt, path[depth - 1], "reg", &len);
|
||||
if (!reg || len < 4u * (ac + sc) * (index + 1u)) return 0;
|
||||
addr = read_cells_at(reg + 4u * (ac + sc) * index, ac);
|
||||
|
||||
/* up through each bus to the CPU's addresses: an empty ranges is the
|
||||
* same addresses above, no ranges at all is no way up */
|
||||
for (i = depth - 2; i >= 1; i--)
|
||||
{
|
||||
uint32_t cac = node_cells(fdt, path[i], "#address-cells", 2);
|
||||
uint32_t csc = node_cells(fdt, path[i], "#size-cells", 1);
|
||||
uint32_t pac = node_cells(fdt, path[i - 1], "#address-cells", 2);
|
||||
const unsigned char* r = (const unsigned char*)fdt_find_prop_in_node(fdt, path[i], "ranges", &len);
|
||||
uint32_t entry, at;
|
||||
int carried = 0;
|
||||
|
||||
if (!r) return 0;
|
||||
if (len == 0) continue;
|
||||
if (cac < 1 || cac > 2 || pac < 1 || pac > 2 || csc < 1 || csc > 2) return 0;
|
||||
entry = 4u * (cac + pac + csc);
|
||||
for (at = 0; at + entry <= len; at += entry)
|
||||
{
|
||||
uint64_t from = read_cells_at(r + at, cac);
|
||||
uint64_t to = read_cells_at(r + at + 4u * cac, pac);
|
||||
uint64_t size = read_cells_at(r + at + 4u * (cac + pac), csc);
|
||||
if (addr >= from && addr - from < size) { addr = to + (addr - from); carried = 1; break; }
|
||||
}
|
||||
if (!carried) return 0;
|
||||
}
|
||||
*out = addr;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -146,7 +146,11 @@ int fdt_console_uart(const void* fdt, fdt_uart_t* out)
|
||||
if (!v) return 0;
|
||||
if (compatible_has(v, len, "arm,pl011") || compatible_has(v, len, "arm,pl011-axi"))
|
||||
{
|
||||
out->reg_shift = 0;
|
||||
/* A PL011's registers are 32-bit words: register n is at n << 2.
|
||||
* (0 until 2026-10-14, which put the flag register at +6 instead
|
||||
* of +0x18 -- an alignment fault on Device memory, found
|
||||
* rehearsing the Pi 5's native path; FABRIC-3.md SXXXIX.) */
|
||||
out->reg_shift = 2;
|
||||
out->io_width = 4;
|
||||
out->base = addr;
|
||||
out->kind = FDT_UART_PL011;
|
||||
|
||||
Reference in New Issue
Block a user