The x18 register

81 occurrences across 8 files · xnu @ f6217f8 2025-10-16

editorial: x18 is reserved by Apple's arm64 ABI, and the kernel uses it in several distinct ways: (1) it is zeroed on every return to EL0 so kernel data cannot leak to userspace; (2) it serves as a tightly-scoped scratch register in a few low-level assembly routines — the kernel-stack-corruption check, TTBR0 ASID toggling, and TCR_EL1 programming — where no other register is free; (3) on devices built with __ARM_KERNEL_PROTECT__ it is used destructively as a global kernel register; and (4) it is preserved across kernel entry for threads that opt into a custom x18 ABI: tasks holding the com.apple.private.custom-x18-abi or com.apple.private.uexc (user-mode exception) entitlements, and Rosetta-translated x86_64 threads, which depend on x18. The concordance below collects every occurrence in the xnu sources apfelkern hosts.

osfmk/arm64/locore.s (54)

125 mov x18, #0 193 * This may mutate x18. 198 mrs x18, TTBR0_EL1 199 orr x18, x18, #(1 << TTBR_ASID_SHIFT) 200 msr TTBR0_EL1, x18 215 MOV64 x18, TCR_EL1_BOOT 216 msr TCR_EL1, x18 228 * This may mutate x18. 237 mrs x18, TPIDR_EL1 238 ldr x18, [x18, ACT_CPUDATAP] 239 ldr x18, [x18, CPU_EXC_VECTORS] 244 ldr x18, [x18, #($1 << 3)] 245 br x18 325 * Clobbers x18, NZCV. 329 * We need two registers to do a compare but only have x18 free without 335 mrs x18, ELR_EL1 340 cmp x18, x19 /* HS if at or above (suspect), LO if below (safe) */ 348 ccmp x18, x19, #0b0010 /* C/HS */, HS 351 msr ELR_EL1, x18 352 mov x18, #0 363 * (out) x18: The unauthenticated CPU_EXCEPSTACK_TOP used for the comparison or 370 mrs x18, TPIDR_EL1 // Get thread pointer 373 * Return zero in x18 to indicate that we failed to execute the check. 375 cbz x18, Lskip_stack_check_\@ 376 ldr x18, [x18, ACT_CPUDATAP] 377 cbz x18, \invalid_stack_label // If thread context is set, cpu data should be too 378 ldr x18, [x18, CPU_EXCEPSTACK_TOP] 379 cmp sp, x18 381 sub x18, x18, EXCEPSTACK_SIZE_NUM // Find bottom of exception stack 382 cmp sp, x18 384 add x18, x18, EXCEPSTACK_SIZE_NUM // Return stack top in x18 602 * Did we fail to execute the stack check (x18=0)? 615 ccmp x18, xzr, #0b0000 /* !Z/NE */, LO 620 * check (x18=0), something is wrong (TPIDR is corrupted?). 623 cbz x18, EXT(el1_sp1_synchronous_vector_long_spill_failed) 628 * the unauthenticated value (x18) for the stack pointer bounds check. 634 cmp x0, x18 730 mov x18, #0 // Zero x18 to avoid leaking data to user SS 904 mov x18, #0 1535 * Restore x18 only if the task has the entitlement that allows 1537 * once we use x18 for something more global. 1540 * that uses x18 as one of the global use cases (and will reset 1541 * x18 later down below). 1544 * as those are another use case, one where x18 must be preserved. 1547 mov x18, #0 1548 tbz w0, ARM_MACHINE_THREAD_PRESERVE_X18_SHIFT, Lexception_return_restore_registers 1551 ldr x18, [sp, SS64_X18] 1681 // Skip x18 - already restored or trashed above (below with __ARM_KERNEL_PROTECT__) 1706 MOV64 x18, TCR_EL1_USER 1707 msr TCR_EL1, x18 1718 mrs x18, TTBR0_EL1 1719 bic x18, x18, #(1 << TTBR_ASID_SHIFT) 1720 msr TTBR0_EL1, x18 1721 mov x18, #0

osfmk/arm64/start.s (4)

582 sub x18, x0, x23 583 sub x24, x24, x18 584 add x22, x22, x18 585 add x23, x23, x18

osfmk/arm64/sleh.c (1)

584 "\t x16: 0x%016llx x17: 0x%016llx x18: 0x%016llx x19: 0x%016llx\n"

osfmk/arm64/pcb.c (7)

495 thread->machine.arm_machine_flags &= ~(ARM_MACHINE_THREAD_PRESERVE_X18); 507 * context switch path implicitly switches x18 regardless 509 thread->machine.arm_machine_flags |= ARM_MACHINE_THREAD_PRESERVE_X18; 514 thread->machine.arm_machine_flags |= ARM_MACHINE_THREAD_PRESERVE_X18; 525 * x18 for user threads. (Except for devices with 527 * x18.) 529 thread->machine.arm_machine_flags |= ARM_MACHINE_THREAD_PRESERVE_X18;

osfmk/arm64/machine_task.c (4)

320 IOTaskHasEntitlement(task, "com.apple.private.custom-x18-abi") || 328 * Those were allowed to use x18 for their purposes on Apple Silicon. 338 * trying to use x18 on a device where that's just not 343 *error_msg = "process has entitlement that indicates custom x18 ABI usage, not available on this device";

osfmk/arm64/exception_asm.h (1)

182 stp x18, x19, [x0, SS64_X18]

osfmk/arm64/dbgwrap.c (7)

277 * we've already saved off and then store that register in the DTR. I've chosen x18 281 instr = (0x91U << 24) | (31 << 5) | 18; // mov x18, sp 283 instr = (0xD51U << 20) | (2 << 19) | (3 << 16) | (4 << 8) | 18; // msr DBGDTR0, x18 290 instr = (0xD53U << 20) | (1 << 19) | (3 << 16) | (4 << 12) | (5 << 8) | (1 << 5) | 18; // mrs x18, DLR_EL0 292 instr = (0xD51U << 20) | (2 << 19) | (3 << 16) | (4 << 8) | 18; // msr DBGDTR0, x18 298 instr = (0xD53U << 20) | (1 << 19) | (3 << 16) | (4 << 12) | (5 << 8) | 18; // mrs x18, DSPSR_EL0 300 instr = (0xD51U << 20) | (2 << 19) | (3 << 16) | (4 << 8) | 18; // msr DBGDTR0, x18

osfmk/arm64/machine_machdep.h (3)

58/* Thread is entitled to use x18, don't smash it when switching to thread. */ 60#define ARM_MACHINE_THREAD_PRESERVE_X18_SHIFT 0 61#define ARM_MACHINE_THREAD_PRESERVE_X18 (1 << ARM_MACHINE_THREAD_PRESERVE_X18_SHIFT)