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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user