/* * Board-specific memory layout for RPi4 (BCM2711). * Picked up via the per-board include path set in build.zig. */ #ifndef BOARD_ASM_DEFS_INC #define BOARD_ASM_DEFS_INC #define LOW_MEMORY (2 * SECTION_SIZE) #define HIGH_MAP_PAGES 6 #define HIGH_MAP_TABLE_SIZE (HIGH_MAP_PAGES * PAGE_SIZE) #define ID_MAP_TABLE_SIZE (ID_MAP_PAGES * PAGE_SIZE) #define ID_MAP_SIZE (8 * SECTION_SIZE) #define PUD_ENTRY_MAP_SIZE (1 << PUD_SHIFT) #define HIGH_MAP_FIRST_START (0x0 + LINEAR_MAP_BASE) #define HIGH_MAP_FIRST_END (0x3B400000 + LINEAR_MAP_BASE) #define HIGH_MAP_SECOND_START (0x40000000 + LINEAR_MAP_BASE) #define HIGH_MAP_SECOND_END (0x80000000 + LINEAR_MAP_BASE) #define HIGH_MAP_THIRD_START (0x80000000 + LINEAR_MAP_BASE) #define HIGH_MAP_THIRD_END (0xC0000000 + LINEAR_MAP_BASE) #define HIGH_MAP_FOURTH_START (0xC0000000 + LINEAR_MAP_BASE) #define HIGH_MAP_FOURTH_END (0xFC000000 + LINEAR_MAP_BASE) #define HIGH_MAP_DEVICE_START (0xFC000000 + LINEAR_MAP_BASE) #define HIGH_MAP_DEVICE_END (0x100000000 + LINEAR_MAP_BASE) #define FIRST_START (0x0) #define FIRST_END (0x3B400000) #define SECOND_START (0x40000000) #define SECOND_END (0x80000000) #define THIRD_START (0x80000000) #define THIRD_END (0xC0000000) #define FOURTH_START (0xC0000000) #define FOURTH_END (0xFC000000) #define DEVICE_START (0xFC000000) #define DEVICE_END (0x100000000) /* BCM2711 oscillator: armstub uses 54 MHz for Pi 4. QEMU does not * preset CNTFRQ_EL0, so the generic timer would otherwise read 0. */ #define BOOT_OSC_FREQ 54000000 /* Pi 4 enters at EL3 (armstub) or EL2 (raspi4b QEMU) — never at * EL1 — so drop_to_el1 has no EL1 fast path. Empty macro keeps * boot.S byte-identical to baseline. */ .macro check_el1_already el_reg .endm /* Pi-specific identity-map population: 1 PGD + 1 PUD + 1 PMD, * mapping VA 0..ID_MAP_SIZE → PA 0..ID_MAP_SIZE (16 MiB at index 0). * Body matches the previous inline form in boot.S map_identity, so * the macro expansion produces byte-identical output. Entry contract * matches boot.S map_identity: x0 = PGD page, x1 = PUD page. */ .macro map_identity_regions eor x4, x4, x4 create_table_entry x0, x1, x4, PGD_SHIFT, TD_KERNEL_TABLE_FLAGS, x2, x3 add x0, x0, #PAGE_SIZE add x1, x1, #PAGE_SIZE create_table_entry x0, x1, x4, PUD_SHIFT, TD_KERNEL_TABLE_FLAGS, x2, x3 mov x0, x1 eor x2, x2, x2 ldr x3, =ID_MAP_SIZE eor x4, x4, x4 create_block_map x0, x2, x3, x4, .Ltd_kernel_block_flags, x5 .endm /* Board-specific stack-base setup. Pi 4's LOW_MEMORY (0x400000) * fits the AArch64 `mov sp, #imm12, lsl shift` and * `add Xd, Xn, #imm12, lsl shift` immediate forms, so each macro * expands to a single instruction — byte-identical to the * pre-macro inline form. virt's larger LOW_MEMORY (0x40800000) * needs an explicit `ldr` first, hence the second template lives * in src/board/virt/board_asm_defs.inc. */ .macro mov_sp_low_memory tmp mov sp, #LOW_MEMORY .endm .macro add_low_memory dst, src, tmp add \dst, \src, #LOW_MEMORY .endm /* Board-specific high-memory mapping. Called from boot.S map_high * after the PGD entry for the linear-map base has been installed. * * Expects on entry: * x0 = address of the PUD page in high_pg_dir * x1 = address of the first PMD page in high_pg_dir * * Pi 4 layout: four 1 GiB PUD slots covering 0..0x100000000, with * the last PMD shared between the upper RAM block and the BCM2711 * device window at 0xFC000000..0x100000000. Five create_block_map * invocations (4 RAM + 1 device) populate the four PMDs. * * Literal labels (.Lhigh_map_*_end, .Ltd_kernel_block_flags, * .Ltd_device_block_flags) live in boot.S .text.boot.literals and * are resolved by the linker; they exist for both the inline use * inside boot.S and inside this macro expansion. */ .macro map_high_regions /* x4 = address of va we map (pud) */ ldr x4, =LINEAR_MAP_BASE ldr x5, =PUD_ENTRY_MAP_SIZE /* install first PUD entry */ create_table_entry x0, x1, x4, PUD_SHIFT, TD_KERNEL_TABLE_FLAGS, x2, x3 add x1, x1, #PAGE_SIZE add x4, x4, x5 create_table_entry x0, x1, x4, PUD_SHIFT, TD_KERNEL_TABLE_FLAGS, x2, x3 add x1, x1, #PAGE_SIZE add x4, x4, x5 create_table_entry x0, x1, x4, PUD_SHIFT, TD_KERNEL_TABLE_FLAGS, x2, x3 add x1, x1, #PAGE_SIZE add x4, x4, x5 create_table_entry x0, x1, x4, PUD_SHIFT, TD_KERNEL_TABLE_FLAGS, x2, x3 /* load some values */ /* `=LIT` for values GAS movzs inline; explicit labels for the ones * that go in the pool. Where two source-level constants share a * value (HIGH_MAP_SECOND_END == HIGH_MAP_THIRD_START etc.), both * use the first label so GAS-style dedup is preserved. */ ldr x10, =HIGH_MAP_FIRST_START ldr x11, .Lhigh_map_first_end ldr x12, .Lhigh_map_second_start ldr x13, .Lhigh_map_second_end ldr x14, .Lhigh_map_second_end ldr x15, .Lhigh_map_third_end ldr x16, .Lhigh_map_third_end ldr x17, .Lhigh_map_fourth_end ldr x18, .Lhigh_map_fourth_end ldr x19, .Lhigh_map_device_end ldr x20, =FIRST_START ldr x21, =SECOND_START ldr x22, =THIRD_START ldr x23, =FOURTH_START ldr x24, =DEVICE_START /* map first high part */ add x0, x0, #PAGE_SIZE mov x2, x10 mov x3, x11 mov x4, x20 create_block_map x0, x2, x3, x4, .Ltd_kernel_block_flags, x5 /* map second high part */ add x0, x0, #PAGE_SIZE mov x2, x12 mov x3, x13 mov x4, x21 create_block_map x0, x2, x3, x4, .Ltd_kernel_block_flags, x5 /* map third high part */ add x0, x0, #PAGE_SIZE mov x2, x14 mov x3, x15 mov x4, x22 create_block_map x0, x2, x3, x4, .Ltd_kernel_block_flags, x5 /* map fourth high part */ add x0, x0, #PAGE_SIZE mov x2, x16 mov x3, x17 mov x4, x23 create_block_map x0, x2, x3, x4, .Ltd_kernel_block_flags, x5 /* map device */ mov x2, x18 mov x3, x19 mov x4, x24 create_block_map x0, x2, x3, x4, .Ltd_device_block_flags, x5 .endm /* Crash-stamp UART macros for entry.S `show_invalid_entry_raw`. * Pi expansion is the movz/movk/ldr/tbz sequence for the BCM2711 * mini-UART (AUX_MU_IO_REG=0xFE215040, AUX_MU_LSR_REG=0xFE215054, * LSR bit 5 = TX-empty → poll until set with `tbz`). Byte-identical * to the hard-coded reference form. */ .macro err_uart_load_io reg movz \reg, #0x5040 movk \reg, #0xFE21, lsl #16 movk \reg, #0xFFFF, lsl #48 .endm .macro err_uart_load_lsr reg movz \reg, #0x5054 movk \reg, #0xFE21, lsl #16 movk \reg, #0xFFFF, lsl #48 .endm .macro err_uart_wait_tx_ready scratch, lsr_reg, lbl \lbl\(): ldr \scratch, [\lsr_reg] tbz \scratch, #5, \lbl\()b .endm /* Pi 4 firmware (GPU bootloader / armstub8) does not pass a DTB * pointer in x0 — the platform is fully described by the BCM2711 * board files baked into the kernel. Empty macro keeps boot.S * byte-identical to baseline. */ .macro save_dtb_pa src .endm /* On real HW armstub8.S already writes CPACR_EL1 (FPEN + ZEN) before * dropping to EL1, but QEMU `-M raspi4b -kernel` skips armstub and * lands directly in the kernel — leaving CPACR with FPEN trapping. * The ELF magic check (ehdr.e_ident[0..4]) lets the Zig * compiler load 4 bytes via `ldr s0, [x0]`, which then traps with * EC=0x07 on QEMU. Re-writing CPACR is idempotent on the HW path * (armstub already set the same bits at EL3) and necessary on the * QEMU path. */ .macro enable_fp_simd_el1 mrs x0, CPACR_EL1 orr x0, x0, #(3 << 20) msr CPACR_EL1, x0 isb .endm #endif /* BOARD_ASM_DEFS_INC */