plain text 174 lines
/*
* 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 */