6

I am new to ARMv8 architecture. I have following basic questions on my mind:

  1. How do I know what is the current execution mode AArch32 or AArch64? Should I read CPSR or SPSR to ascertain this?

  2. What is the current Exception level, EL0/1/2/3?

  3. Once an exception comes, can i read any register to determine whether I am in Serror/Synchronous/IRQ/FIQ exception handler.

TIA.

crazzy
  • 149
  • 2
  • 13
  • 2
    "How do I know what is the current execution mode AArch32 or AArch64?" - I figure if the the code trying to check the mode is compiled for 64-bit, the mode is 64-bit; if it's compiled for 32-bit the mode is 32-bit. – JimmyB Aug 03 '15 at 12:59

2 Answers2

9
  1. The assembly instructions and their binary encoding are entirely different for 32 and 64 bit. So the information what mode you are currently in is something that you/ the compiler already needs to know during compilation. checking for them at runtime doesn't make sense. For C, C++ checking can be done at compile time (#ifdef) through compiler provided macros like the ones provided by armclang: __aarch64__ for 64 bit, __arm__ for 32 bit
  2. depends on the execution mode:
    • aarch32: MRS <Rn>, CPSR read the current state into register number n. Then extract bits 3:0 that contain the current mode.
    • aarch64: MRS <Xn>, CurrentEL read the current EL into register number n
  3. short answer: you can't. long answer: the assumption is that by the structure of the code and the state of any user defined variables, you already know what you are doing. i.e. whether you came to a position in code through regular code or through an exception.
Martin Keßler
  • 776
  • 1
  • 7
  • 10
  • 1
    For the 2nd point I am able to find the current mode when I am in EL1, EL2, or EL3 mode by reading through CPSR register. However, if I am in EL0 mode reading cpsr causes exception. – crazzy May 04 '16 at 09:00
  • @chetan: "if I am in EL0 mode reading cpsr causes exception." AFAIK, that of course is the whole point! EL0 is the unprivileged 'app' mode; apps cannot/must not have access to info like this..So, my understanding is, write a kernel module to read register values. It should work as it runs in EL1, if not EL2. – kaiwan Jul 27 '17 at 06:30
4

aarch64 C code:

register uint64_t x0 __asm__ ("x0");
__asm__ ("mrs x0, CurrentEL;" : : : "%x0");
printf("EL = %" PRIu64 "\n", x0 >> 2);

arm C code:

register uint32_t r0 __asm__ ("r0");
__asm__ ("mrs r0, CPSR" : : : "%r0");
printf("EL = %" PRIu32 "\n", r0 & 0x1F);

CurrentEL however is not readable from EL0 as shown on the ARMv8 manual C5.2.1 "CurrentEL, Current Exception Level" section "Accessibility". Trying to run it in Linux userland raises SIGILL. You could catch that signal however I suppose...

CPSR is readable from EL0 however.

Tested on QEMU and gem5 with this setup.

Ciro Santilli
  • 3,693
  • 1
  • 18
  • 44
  • Hi, if I use gdb, can I just read the register like "info reg currentel"? this doesn't work. Is there any register I can read for this? I tried CPSR (it's lowest 4 bits) but it's not exactly EL value. – Chan Kim Mar 08 '21 at 09:02
  • @ChanKim I'm not sure about this, what I would look for is the GDB XML which determines what is exposed or not, e.g. on QEMU see aarch64 entries under: https://github.com/qemu/qemu/tree/master/gdb-xml – Ciro Santilli Mar 08 '21 at 13:55
  • 1
    within a kernel module it is possible to read the `CurrentEL` with `u64 el = read_sysreg(CurrentEL);` – dafnahaktana Nov 27 '21 at 15:44