From 6b3fcc0def1e173c76943682dcf3cba6edcd3b55 Mon Sep 17 00:00:00 2001 From: Bradley Morgan Date: Sat, 3 Oct 2026 22:12:35 +0000 Subject: tashaboot: VMSAv8-64 identity map at EL1 and EL2 The bootloader now builds its own stage 1 translation tables instead of only tearing firmware state down. one L0 table, one L1 under it, device nGnRE block for the low 1GB, normal writeback 2MB blocks for RAM. the descriptors, attribute encodings, MAIR and TCR settings come straight from the manual, level 0/1/2 and level 3 formats at D5-2444 and D5-2447, stage 1 attribute fields at D5-2451, MAIR region attributes at D5-2476, the PA size from ID_AA64MMFR0_EL1.PARange per D5-2399. The tables are EL aware, TTBR0/TCR/MAIR at whichever regime the entry left us in, EL2 or EL1, and the self test translates through AT S1E2R or AT S1E1R per the exception level and checks PAR_EL1 for the identity result: mmu: mmio 0x09000000 (uart) ok, pa 9000000 mmu: mmio 0x00000000 ok, pa 0 mmu: ram 0x40200000 (load) ok, pa 40200000 mmu: ram 0x41000000 ok, pa 41000000 mmu: self 0x40080000 ok, pa 40080000 mmu: identity map on The map is torn down again before the payload, the kernel wants the architecture state at entry, not ours. Two bugs the self test caught on the way. T0SZ was 25 for a 39-bit VA, but with the 4KB granule a 39-bit VA starts the walk at level 1, and the L0 indexed structure was misread one level over, every descriptor landed in the wrong slot and all fetches past the first 2MB faulted level 1. T0SZ is 16 now, the walk starts at level 0 and the three level structure matches. The second, the mmio table was orphaned, the l0 entry was written twice and the second write won, so the device block was never reachable and AT on the uart address faulted. the mmio block now lives at l1[0] in the same L1 table as RAM. The stack also moved to its own region above the bss in the linker script. the tables are bss objects, a stack growing down from the bss end shares their address space and a deep call chain writes into the top table. Signed-off-by: Bradley Morgan --- arch/arm64/include/asm/mmu.h | 51 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 arch/arm64/include/asm/mmu.h (limited to 'arch/arm64/include/asm') diff --git a/arch/arm64/include/asm/mmu.h b/arch/arm64/include/asm/mmu.h new file mode 100644 index 0000000..342a2ff --- /dev/null +++ b/arch/arm64/include/asm/mmu.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __ASM_MMU_H +#define __ASM_MMU_H + +/* + * VMSAv8-64 stage 1 translation at EL2. descriptor layouts and + * attribute fields per the ARM ARM (DDI 0487), block and table + * descriptors D5-2444, page descriptors D5-2447, stage 1 attribute + * fields D5-2451, MAIR region attributes D5-2476. + */ + +#include + +/* descriptor bits[1:0]: 0b01 block (page at level 3), 0b11 table */ +#define TB_DESC_FAULT 0ULL +#define TB_DESC_BLOCK 1ULL +#define TB_DESC_TABLE 3ULL + +/* lower block/page attribute bits, D5-2451 */ +#define TB_DESC_AF (1ULL << 10) /* access flag, set by hand */ +#define TB_DESC_SH_IS (3ULL << 8) /* inner shareable */ +#define TB_DESC_XN (1ULL << 54) /* XN at EL2, no execute */ + +/* MAIR_ELx attribute indices used by the maps below */ +#define TB_ATTR_NORMAL 0 /* writeback, read allocate */ +#define TB_ATTR_DEVICE 1 /* device nGnRE */ + +/* + * TCR setup, 4KB granule. T0SZ 16 gives a 48-bit VA and the walk + * starts at level 0 (Address size configuration, D5-2399), which is + * what the three level table structure below assumes. a 39-bit VA + * (T0SZ 25) would start the walk at level 1 and misread the whole + * table. + */ +#define TB_TCR_T0SZ_48 16 +#define TB_TCR_SH0_IS (3ULL << 12) +#define TB_TCR_TG0_4K (0ULL << 14) +#define TB_TCR_IRGN0_WB (1ULL << 8) +#define TB_TCR_ORGN0_WB (1ULL << 10) +#define TB_TCR_IPS(x) ((uint64_t)(x) << 16) /* PA size from PARange */ + +/* the map itself, PA == VA everywhere, identity */ +#define TB_MAP_MMIO_BASE 0x00000000ULL +#define TB_MAP_MMIO_SIZE (1ULL << 30) /* low 1GB, devices live here */ +#define TB_MAP_RAM_BASE 0x40000000ULL +#define TB_MAP_RAM_SIZE (128ULL << 20) /* qemu virt default, 128MB */ + +int tb_mmu_enable(void); +void tb_mmu_disable(void); + +#endif /* __ASM_MMU_H */ -- cgit v1.2.3