/* * Common assembly-level constants — board-independent. * Memory-layout addresses live in board_asm_defs.inc per board. */ #ifndef ASM_DEFS_COMMON_INC #define ASM_DEFS_COMMON_INC /* ---- mm ---- */ #define PAGE_SHIFT 12 #define TABLE_SHIFT 9 #define SECTION_SHIFT (PAGE_SHIFT + TABLE_SHIFT) #define PAGE_SIZE (1 << PAGE_SHIFT) #define SECTION_SIZE (1 << SECTION_SHIFT) #define ID_MAP_PAGES 3 #define ENTRIES_PER_TABLE 512 #define PGD_SHIFT (PAGE_SHIFT + 3 * TABLE_SHIFT) #define PUD_SHIFT (PAGE_SHIFT + 2 * TABLE_SHIFT) #define PMD_SHIFT (PAGE_SHIFT + TABLE_SHIFT) #define LINEAR_MAP_BASE 0xFFFF000000000000 /* ---- mmu / translation table descriptors ---- */ #define TD_VALID (1 << 0) #define TD_BLOCK (0 << 1) #define TD_PAGE (1 << 1) #define TD_TABLE (1 << 1) #define TD_ACCESS (1 << 10) #define TD_KERNEL_PERMS (1 << 54) #define TD_USER_PERMS (1 << 6) #define TD_INNER_SHARABLE (3 << 8) #define MATTR_DEVICE_nGnRnE 0x0 #define MATTR_NORMAL_NC 0x44 #define MATTR_DEVICE_nGnRnE_INDEX 0 #define MATTR_NORMAL_NC_INDEX 1 #define TD_KERNEL_TABLE_FLAGS \ (TD_TABLE | TD_VALID) #define TD_KERNEL_BLOCK_FLAGS \ (TD_ACCESS | TD_INNER_SHARABLE | TD_KERNEL_PERMS \ | (MATTR_NORMAL_NC_INDEX << 2) | TD_BLOCK | TD_VALID) #define TD_DEVICE_BLOCK_FLAGS \ (TD_ACCESS | TD_INNER_SHARABLE | TD_KERNEL_PERMS \ | (MATTR_DEVICE_nGnRnE_INDEX << 2) | TD_BLOCK | TD_VALID) /* ---- sysregs (only what the kernel .S files reference) ---- */ #define SCTLR_EL1_MMU_ENABLED (1 << 0) /* TCR_EL1: 4 KiB granule both halves, 48-bit VA, 40-bit PA, IS, WB-WA walks. * Pi armstub leaves TCR usable; QEMU's -kernel shim does not — boot.S must * write this before MMU enable or the first translation walk faults. */ #define TCR_T0SZ (16) /* bits [5:0] 48-bit VA */ #define TCR_IRGN0_WBWA (1 << 8) #define TCR_ORGN0_WBWA (1 << 10) #define TCR_SH0_IS (3 << 12) #define TCR_TG0_4K (0 << 14) #define TCR_T1SZ (16 << 16) #define TCR_IRGN1_WBWA (1 << 24) #define TCR_ORGN1_WBWA (1 << 26) #define TCR_SH1_IS (3 << 28) #define TCR_TG1_4K (2 << 30) /* TG1 4 KiB encoding != TG0 */ #define TCR_IPS_40BIT (2UL << 32) #define TCR_EL1_VAL \ (TCR_T0SZ | TCR_IRGN0_WBWA | TCR_ORGN0_WBWA | TCR_SH0_IS | TCR_TG0_4K \ | TCR_T1SZ | TCR_IRGN1_WBWA | TCR_ORGN1_WBWA | TCR_SH1_IS | TCR_TG1_4K \ | TCR_IPS_40BIT) /* sanity: TCR_EL1_VAL == 0x2B5103510 */ /* MAIR_EL1: idx 0 = Device-nGnRnE, idx 1 = Normal-NC. Compose from the * MATTR_* bytes above; the indices already match TD_DEVICE_BLOCK_FLAGS * and TD_KERNEL_BLOCK_FLAGS. */ #define MAIR_EL1_VAL \ ((MATTR_NORMAL_NC << 8) | MATTR_DEVICE_nGnRnE) /* sanity: MAIR_EL1_VAL == 0x4400 */ /* Self-sufficient EL3 → EL1 drop in boot.S. The values mirror what * armstub8.S sets up; redoing them in the kernel makes it bootable * directly from QEMU's `-kernel` (which enters at EL3 without running * armstub). On real hardware armstub has already written these, and * the second write of the same value is harmless. */ #define BIT(x) (1 << (x)) #define SCR_RW BIT(10) #define SCR_HCE BIT(8) #define SCR_SMD BIT(7) #define SCR_RES1_5 BIT(5) #define SCR_RES1_4 BIT(4) #define SCR_NS BIT(0) #define SCR_EL3_VAL \ (SCR_RW | SCR_HCE | SCR_SMD | SCR_RES1_5 | SCR_RES1_4 | SCR_NS) #define SPSR_EL3_D BIT(9) #define SPSR_EL3_A BIT(8) #define SPSR_EL3_I BIT(7) #define SPSR_EL3_F BIT(6) #define SPSR_EL3_MODE_EL1H 5 #define SPSR_EL3_VAL \ (SPSR_EL3_D | SPSR_EL3_A | SPSR_EL3_I | SPSR_EL3_F | SPSR_EL3_MODE_EL1H) #define HCR_EL2_RW BIT(31) #define HCR_EL2_VAL HCR_EL2_RW #define CPACR_EL1_FPEN (BIT(21) | BIT(20)) #define CPACR_EL1_ZEN (BIT(17) | BIT(16)) #define CPACR_EL1_VAL (CPACR_EL1_FPEN | CPACR_EL1_ZEN) #define SCTLR_EL1_RESERVED ((3 << 28) | (3 << 22) | (1 << 20) | (1 << 11)) #define SCTLR_EL1_VAL_MMU_DISABLED SCTLR_EL1_RESERVED #define SCTLR_EL1_VAL_MMU_ENABLED (SCTLR_EL1_RESERVED | SCTLR_EL1_MMU_ENABLED) #define ESR_ELx_EC_SHIFT 26 #define ESR_ELx_EC_SVC64 0x15 #define ESR_ELx_EC_DA_LOW 0x24 /* Instruction abort from a lower EL (EL0). Same fault class as a data abort but on an instruction fetch — a jump to a non-executable (UXN) or unmapped UVA. handle_sync_el0_64 routes it to el0_ia so a bad EL0 jump zombies the task instead of err_hanging the core. */ #define ESR_ELx_EC_IA_LOW 0x20 /* ---- exception entry constants ---- */ #define SYNC_INVALID_EL1t 0 #define IRQ_INVALID_EL1t 1 #define FIQ_INVALID_EL1t 2 #define SERROR_INVALID_EL1t 3 #define SYNC_INVALID_EL1h 4 #define IRQ_INVALID_EL1h 5 #define FIQ_INVALID_EL1h 6 #define SERROR_INVALID_EL1h 7 #define SYNC_INVALID_EL0_64 8 #define IRQ_INVALID_EL0_64 9 #define FIQ_INVALID_EL0_64 10 #define SERROR_INVALID_EL0_64 11 #define SYNC_INVALID_EL0_32 12 #define IRQ_INVALID_EL0_32 13 #define FIQ_INVALID_EL0_32 14 #define SERROR_INVALID_EL0_32 15 #define SYNC_ERROR 16 #define SYSCALL_ERROR 17 #define DATA_ABORT_ERROR 18 /* EL1 exception-frame size. MUST equal @sizeOf(KeRegs) in src/task_layout.zig — a comptime assert there pins the reciprocal, so bump both together if the saved-register frame layout changes. */ #define S_FRAME_SIZE 272 /* ---- syscalls ---- */ /* Highest user-facing slot id +1 (entry.S `b.hs` cap). Slots 7..11 are * reserved file stubs that fall inside the dispatch range but return * immediately; brk/sbrk live at 12/13. The pipe ABI * lives at 18 + 27..29; the console ABI fills * slots 23..26, the debug-only SYS_CONSOLE_INJECT lives at 30, and * SYS_EXECVE = 31 lands the path-resolved ELF loader. The * unified fd-table ABI appends SYS_READ/WRITE/CLOSE/DUP2 at * 32..35, SYS_CHDIR at 36 and SYS_READDIR at 37. * SYS_KLOG_READ at 38, then the process-credential ABI * SYS_GETUID..SYS_SETGID at 39..44, SYS_AUTHENTICATE at 45, * SYS_PASSWD at 46, SYS_REBOOT at 47, and SYS_GETCWD at 48. The * hardware-monitoring ABI then appends SYS_MEMTOTAL/UPTIME/CPU_TEMP/ * CPU_FREQ at 49..52, and the FAT32 metadata ABI SYS_CREATE/UNLINK/ * RENAME at 53..55, so the cap is now 56. * See lib/syscall_defs.flash. */ #define NR_SYSCALLS 56 /* ---- sched ---- */ #define CORE_CONTEXT_OFFSET 0 #endif /* ASM_DEFS_COMMON_INC */