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:
rajames
2026-10-14 12:58:35 -04:00
co-authored by Claude Opus 5.5
parent 4da370f492
commit 0e2c60dac3
23 changed files with 36835 additions and 85 deletions
+147 -2
View File
@@ -2,8 +2,9 @@
* native_rpi5_entry.S (aarch64) - Raspberry Pi 5 native (non-UEFI) entry
* stub (FABRIC-3.md §IV.3 item 1, 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.
* Never run on the board yet. Rehearsed on QEMU's virt machine at EL2
* since 2026-10-14 (`make ... rpi5-rehearsal`, FABRIC-3.md §XXXIX): POST
* passes there, same parity hash as the UEFI build.
*
* Entered directly by Pi 5 firmware at the classic bare-metal load address
* 0x80000 (item 6, `config.txt`'s `os_check=0`, is still open -- that's
@@ -47,6 +48,18 @@
g_rpi5_dtb_ptr:
.space 8 /* uint64_t -- masked DTB pointer */
/* The early identity map (2026-10-14): one level-1 table of 512 1 GiB
* entries (39-bit VA, 4 KiB granule), and one level-2 table that splits
* the GiB the image is in into 2 MiB blocks, so that a framebuffer
* inside it can be made uncached alone (rpi5_mmu.c). */
.align 12
.global g_rpi5_l1
g_rpi5_l1:
.space 4096
.global g_rpi5_l2
g_rpi5_l2:
.space 4096
.align 4
g_rpi5_native_stack:
.space 0x200000 /* 2 MiB, same convention as the
@@ -63,6 +76,30 @@ rpi5_native_start:
mov x1, #0xffffffff
and x0, x0, x1
/* Clean and invalidate the data cache over the whole image, .bss and
* stack included, FIRST: whatever the firmware may have left in the
* cache for these addresses goes to RAM now, before anything below
* writes them with the cache off -- a dirty line cleaned later would
* land on top of that work. Line size from CTR_EL0.DminLine. */
mrs x6, ctr_el0
ubfx x6, x6, #16, #4
mov x7, #4
lsl x7, x7, x6 /* x7 = line size in bytes */
sub x8, x7, #1
adrp x4, __kernel_start
add x4, x4, :lo12:__kernel_start
bic x4, x4, x8
adrp x5, __kernel_end
add x5, x5, :lo12:__kernel_end
.Lcache_clean:
cmp x4, x5
b.hs .Lcache_done
dc civac, x4
add x4, x4, x7
b .Lcache_clean
.Lcache_done:
dsb sy
/* Zero .bss: [__bss_start, __bss_end), both 16-byte aligned by the
* native linker script. */
adrp x4, __bss_start
@@ -85,6 +122,114 @@ rpi5_native_start:
add x0, x0, :lo12:g_rpi5_native_stack_top
mov sp, x0
/* MMU and caches on, before any C (2026-10-14). The firmware enters
* with the MMU off, where every access is Device memory: an unaligned
* access or an exclusive faults, and nothing is cached. Identity map:
* the first GiB Normal write-back (every Pi 5 has at least that much
* RAM; rpi5_mmu.c makes the rest of the devicetree's RAM Normal once C
* runs), everything else Device-nGnRE, never executable. At
* whichever EL the firmware chose -- EL2 on the Pi 5, EL1 handled too.
* "The first GiB" is precisely the GiB the image is in: 0 on the Pi 5
* (0x80000), 1 on QEMU's virt machine, where it is rehearsed.
* MAIR: attr0 Normal WB RA/WA (0xFF), attr1 Device-nGnRE (0x04),
* attr2 Normal non-cacheable (0x44).
* block: AF (bit 10), SH inner (bits 9:8 = 3) for Normal, AttrIndx
* (bits 4:2), bit 54 XN/UXN for Device. */
adrp x1, g_rpi5_l1
add x1, x1, :lo12:g_rpi5_l1
adrp x2, g_rpi5_l2
add x2, x2, :lo12:g_rpi5_l2
adrp x10, __kernel_start
add x10, x10, :lo12:__kernel_start
lsr x10, x10, #30 /* x10 = the GiB the image is in */
lsl x11, x10, #30 /* level 2: that GiB, 512 x 2 MiB Normal */
mov x3, #0
mov x4, #0x701
.Ll2_fill:
lsl x5, x3, #21
add x5, x5, x11
orr x5, x5, x4
str x5, [x2, x3, lsl #3]
add x3, x3, #1
cmp x3, #512
b.lo .Ll2_fill
mov x3, #0 /* level 1: 1 GiB Device, but the image's GiB */
mov x4, #0x405
orr x4, x4, #(1 << 54)
.Ll1_fill:
lsl x5, x3, #30
orr x5, x5, x4
cmp x3, x10
b.ne .Ll1_store
orr x5, x2, #3 /* -> the level 2 table */
.Ll1_store:
str x5, [x1, x3, lsl #3]
add x3, x3, #1
cmp x3, #512
b.lo .Ll1_fill
dsb sy
movz x6, #0x04FF
movk x6, #0x0044, lsl #16 /* MAIR = 0x4404FF */
mov x7, #(1 << 0) | (1 << 2) | (1 << 12) /* SCTLR: M, C, I */
mrs x8, CurrentEL
ubfx x8, x8, #2, #2
cmp x8, #2
b.ne .Lmmu_el1
msr mair_el2, x6
movz x9, #0x3519 /* T0SZ 25, IRGN0/ORGN0 WB, SH0 inner, TG0 4K */
movk x9, #0x8082, lsl #16 /* PS 40-bit, RES1 bits 23 and 31 */
msr tcr_el2, x9
msr ttbr0_el2, x1
isb
tlbi alle2
dsb ish
isb
ic iallu
dsb ish
mrs x9, sctlr_el2
orr x9, x9, x7
bic x9, x9, #(1 << 1) /* A: no alignment checking */
bic x9, x9, #(1 << 19) /* WXN: the image is writable Normal memory */
msr sctlr_el2, x9
isb
/* Interrupts to EL2, where the kernel runs: with HCR_EL2.IMO/FMO/AMO
* clear (as a stub that hands Linux EL1 leaves them, and QEMU resets
* them) an IRQ targets EL1 and is never taken at EL2 -- the timer
* never ticked (FABRIC-3.md SXXXIX). */
mrs x9, hcr_el2
orr x9, x9, #(1 << 3) /* FMO */
orr x9, x9, #(1 << 4) /* IMO */
orr x9, x9, #(1 << 5) /* AMO */
msr hcr_el2, x9
isb
b .Lmmu_done
.Lmmu_el1:
msr mair_el1, x6
movz x9, #0x3519 /* T0SZ 25, IRGN0/ORGN0 WB, SH0 inner, TG0 4K */
movk x9, #0x0080, lsl #16 /* EPD1: no TTBR1 walks */
movk x9, #0x0002, lsl #32 /* IPS 40-bit */
msr tcr_el1, x9
msr ttbr0_el1, x1
isb
tlbi vmalle1
dsb ish
isb
ic iallu
dsb ish
mrs x9, sctlr_el1
orr x9, x9, x7
bic x9, x9, #(1 << 1)
bic x9, x9, #(1 << 19)
msr sctlr_el1, x9
isb
.Lmmu_done:
/* 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