# Linux Kernel Module Cheat

#### 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:

- baremetal/arch/arm/dump_regs.c

- baremetal/arch/aarch64/dump_regs.c

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…​

- ARM change exception level

- ARM SP0 vs SPx