33.10.1. ARM exception levels
ARM exception levels are analogous to x86 rings.
The current EL can be determined by reading from certain registers, which we do with bit disassembly at:
./run --arch arm --baremetal userland/arch/arm/dump_regs.c ./run --arch aarch64 --baremetal baremetal/arch/aarch64/dump_regs.c
The relevant bits are:
-
arm:
CPSR.M
-
aarch64:
CurrentEl.EL
. This register is not accessible from EL0 for some weird reason however.
Sources:
The instructions that find the ARM EL are explained at: https://stackoverflow.com/questions/31787617/what-is-the-current-execution-mode-exception-level-etc
The lower ELs are not mandated by the architecture, and can be controlled through command line options in QEMU and gem5.
In QEMU, you can configure the lowest EL as explained at https://stackoverflow.com/questions/42824706/qemu-system-aarch64-entering-el1-when-emulating-a53-power-up
./run --arch arm --baremetal userland/arch/arm/dump_regs.c | grep CPSR.M ./run --arch arm --baremetal userland/arch/arm/dump_regs.c -- -machine virtualization=on | grep CPSR.M ./run --arch arm --baremetal userland/arch/arm/dump_regs.c -- -machine secure=on | grep CPSR.M ./run --arch aarch64 --baremetal baremetal/arch/aarch64/dump_regs.c | grep CurrentEL.EL ./run --arch aarch64 --baremetal baremetal/arch/aarch64/dump_regs.c -- -machine virtualization=on | grep CurrentEL.EL ./run --arch aarch64 --baremetal baremetal/arch/aarch64/dump_regs.c -- -machine secure=on | grep CurrentEL.EL
outputs respectively:
CPSR.M 0x3 CPSR.M 0x3 CPSR.M 0x3 CurrentEL.EL 0x1 CurrentEL.EL 0x2 CurrentEL.EL 0x3
TODO: why is arm CPSR.M
stuck at 0x3
which equals Supervisor mode?
In gem5, you can configure the lowest EL with:
./run --arch arm --baremetal userland/arch/arm/dump_regs.c --emulator gem5 grep CPSR.M "$(./getvar --arch arm --emulator gem5 gem5_guest_terminal_file)" ./run --arch arm --baremetal userland/arch/arm/dump_regs.c --emulator gem5 -- --param 'system.have_virtualization = True' grep CPSR.M "$(./getvar --arch arm --emulator gem5 gem5_guest_terminal_file)" ./run --arch arm --baremetal userland/arch/arm/dump_regs.c --emulator gem5 -- --param 'system.have_security = True' grep CPSR.M "$(./getvar --arch arm --emulator gem5 gem5_guest_terminal_file)" ./run --arch aarch64 --baremetal baremetal/arch/aarch64/dump_regs.c --emulator gem5 grep CurrentEL.EL "$(./getvar --arch aarch64 --emulator gem5 gem5_guest_terminal_file)" ./run --arch aarch64 --baremetal baremetal/arch/aarch64/dump_regs.c --emulator gem5 -- --param 'system.have_virtualization = True' grep CurrentEL.EL "$(./getvar --arch aarch64 --emulator gem5 gem5_guest_terminal_file)" ./run --arch aarch64 --baremetal baremetal/arch/aarch64/dump_regs.c --emulator gem5 -- --param 'system.have_security = True' grep CurrentEL.EL "$(./getvar --arch aarch64 --emulator gem5 gem5_guest_terminal_file)"
output:
CPSR.M 0x3 CPSR.M 0xA CPSR.M 0x3 CurrentEL.EL 0x1 CurrentEL.EL 0x2 CurrentEL.EL 0x3
TODO: the call:
./run --arch arm --baremetal userland/arch/arm/dump_regs.c --emulator gem5 -- --param 'system.have_virtualization = True'
started failing with an exception since https://github.com/cirosantilli/linux-kernel-module-cheat/commit/add6eedb76636b8f443b815c6b2dd160afdb7ff4 at the instruction:
vmsr fpexc, r0
in baremetal/lib/arm.S. That patch however enables SIMD in baremetal, which I feel is more important.
According to ARMv7 architecture reference manual, access to that register is controlled by other registers NSACR.{CP11, CP10}
and HCPTR
so those must be turned off, but I’m lazy to investigate now, even just trying to dump those registers in userland/arch/arm/dump_regs.c also leads to exceptions…