[Project Name] / Manual
🔍

ARM64 Register Reference

Quick reference for the ARM64 registers we use in our kernel. Refer to this when writing assembly code, exception handlers, or context switching routines.

General-Purpose Registers

ARM64 has 31 general-purpose 64-bit registers (x0-x30). The lower 32 bits are accessible as w0-w30. Writing to wN zero-extends to the upper 32 bits of xN.

RegisterRole (AAPCS64)Who saves it?
x0Argument 1 / return valueCaller
x1-x7Arguments 2-8Caller
x8-x15Temporary (scratch)Caller
x16-x17Intra-procedure (IP0, IP1)Caller
x18Platform register (do not use)N/A
x19-x28Callee-saved temporariesCallee must save/restore
x29Frame Pointer (FP)Callee must save/restore
x30Link Register (LR) / return addressCallee must save (if it calls other functions)

Special-Purpose Registers

RegisterNameNotes
SPStack PointerShares register number 31 with XZR. Context determines whether it refers to SP or XZR.
PCProgram CounterCannot be written directly. Changed by branches, exceptions, and ERET.
XZRZero RegisterAlways reads as 0. Writes are ignored. Register number 31.

Exception System Registers

RegisterAccessPurpose
CurrentELEL0+Read current exception level (bits 3:2). 0b00=EL0, 0b01=EL1, 0b10=EL2, 0b11=EL3.
SPSR_EL1EL1+Saved PSTATE when an exception occurred. The ERET instruction restores from here.
ELR_EL1EL1+Exception return address. The ERET instruction branches to this address.
ESR_EL1EL1+Exception Syndrome Register. Describes why the exception happened.

Memory Management Registers

RegisterAccessPurpose
TTBR0_EL1EL1+Page table base for user space (EL0) addresses. Points to level-0 table.
TTBR1_EL1EL1+Page table base for kernel space addresses. Points to level-0 table.
TCR_EL1EL1+Translation Control Register. Page size, address size, cache policy for table walks.
MAIR_EL1EL1+Memory Attribute Indirection Register. Maps 8 attribute indices to memory types (normal, device, etc.).
SCTLR_EL1EL1+System Control Register. Enables MMU (bit 0), data cache (bit 2), instruction cache (bit 12), etc.

Stack Pointer Selection

ARM64 has two stack pointers: SP_EL0 and SP_EL1. The SPSel register (bit 0 of PSTATE) selects which one is active:

  • SPSel = 0: Use SP_EL0 (even when running at EL1)
  • SPSel = 1: Use SP_EL1 (each exception level has its own SP)

Our kernel uses SPSel = 1 at EL1 (kernel uses SP_EL1) and SPSel = 0 at EL0 (user uses SP_EL0). This gives each mode a separate stack.

/* Set SP_EL1 as the current stack pointer */
msr SPSel, #1

/* Now 'mov sp, x0' modifies SP_EL1 */

PSTATE (Processor State) Fields

FieldDescription
NNegative condition flag (result was negative)
ZZero condition flag (result was zero)
CCarry condition flag (unsigned overflow)
VOverflow condition flag (signed overflow)
DDebug mask (0 = debug exceptions enabled)
ASError mask (0 = SError interrupts enabled)
IIRQ mask (0 = IRQ interrupts enabled)
FFIQ mask (0 = FIQ interrupts enabled)
M[3:0]Current exception level and execution state

The DAIF bits (D, A, I, F) control which interrupts are masked. Our kernel uses MSR DAIFSet, #2 to mask IRQs (set bit I) during critical sections.

Calling Convention Quick Rules

  • Arguments 1-8: x0-x7
  • Arguments 9+: on the stack (growing downward)
  • Return value: x0
  • Callee must save x19-x29 and x30 (if it modifies them)
  • Stack must be 16-byte aligned at function call boundary
  • SP must never be misaligned
/* Function prologue (if using frame pointer) */
my_function:
    stp x29, x30, [sp, #-16]!   /* save FP and LR */
    mov x29, sp                   /* set new frame pointer */
    ...
    ldp x29, x30, [sp], #16      /* restore FP and LR */
    ret

/* Function prologue (no frame pointer, just save what we use) */
my_function:
    stp x19, x20, [sp, #-16]!   /* save callee-saved regs we modify */
    ...
    ldp x19, x20, [sp], #16     /* restore */
    ret

Reading System Registers

/* Read */
mrs x0, CurrentEL
mrs x0, SCTLR_EL1
mrs x0, TTBR0_EL1

/* Write */
msr SCTLR_EL1, x0
msr TTBR0_EL1, x0

/* After modifying system registers, synchronize */
isb

MRS and MSR are only available at the appropriate exception level. Accessing an EL1 register at EL0 causes an exception.

Instruction Quick Reference

InstructionExampleMeaning
ADDadd x0, x1, x2x0 = x1 + x2
SUBsub x0, x1, #16x0 = x1 - 16
MULmul x0, x1, x2x0 = x1 * x2
LDRldr x0, [x1]x0 = memory[x1]
STRstr x0, [x1]memory[x1] = x0
STPstp x0, x1, [sp, #-16]!Push x0, x1 to stack
LDPldp x0, x1, [sp], #16Pop x0, x1 from stack
BLbl funcCall func; save return address in x30
RETretReturn to x30
CBZcbz x0, labelBranch to label if x0 == 0
CBNZcbnz x0, labelBranch to label if x0 != 0
SVCsvc #0Trigger system call (EL0 -> EL1)
ERETeretReturn from exception (EL1 -> EL0)
WFIwfiWait for interrupt (low power)
NOPnopNo operation

See the Assembly Guide chapter for detailed instruction explanations and patterns.

Further Reading

  • ARM Architecture Reference Manual ARMv8-A, sections C5 (A64 instruction set) and D1 (system registers)
  • Procedure Call Standard for the ARM 64-bit Architecture (AAPCS64)
  • aarch64-none-elf-objdump -d kernel.elf to disassemble and verify your code