Search code examples
exceptionassemblyinterruptqemuarm64

How to handle exceptions and interrupts in aarch64?


I have a trivial bare-metal app that I launch in Qemu by the next command:

qemu-system-aarch64 -M virt \
    -cpu cortex-a72 \
    -bios "$(QEMU_PATH)/share/qemu/edk2-aarch64-code.fd" \
    -m 128M \
    -nographic \
    -device loader,file=$(BUILD_DIR)/kernel.elf \
    -device loader,addr=0x40100000,cpu-num=0

Now I'm trying to handle exceptions and interrupts but, unfortunately, the more I read about this topic the less I understand how to handle them.

Well, aarch64 offers us 4 levels: EL3 -> EL0. I've checked my app is launched in Qemu at EL1 level, okay, OS level, everything is right.

Next, various tutorials in the Internet show us a something as below:

.text
.global vector_table
.balign 2048
vector_table:
    b .
.balign 0x80
    b .
.balign 0x80
    b .
.balign 0x80
    b .
...

adr x0, vector_table
msr VBAR_EL2, x0

From this listing I got that I need to load address of my vector_table into VBAR_EL1 register (cuz my app works at EL1 level).

As I understand the CPU will use VBAR_EL1 register to find an address of the suitable handler and execute it.

That's all, unfortunately! My understanding finishes at this moment and there are only questions next...

  1. Why does the author align table at 2048?
  2. Why does he offset entrypoints by 0x80 although there are other offsets on the official table? Screenshot
  3. Which exceptions and interrupts should I handle at EL1 level?

If someone can explain in simple words I will be very grateful.


Solution

    1. Why does the author align table at 2048?

    Because the manual says the lower 11 bits are RES0, so the table has to be aligned to 0x800 bytes:

    VBAR_EL1 register field descriptions

    1. Why does he offset entrypoints by 0x80 although there are other offsets on the official table?

    Because 0x80+0x80 = 0x100, 0x80+0x80+0x80 = 0x180, etc.

    1. Which exceptions and interrupts should I handle at EL1 level?

    All of them?
    If you don't expect to get any exceptions ever, you should at the very least make all exception handlers invoke some sort of "fatal" action (kernel panic, trapping to debugger, or possibly just spinning indefinitely), just so you'll be made aware of violated assumptions. As long as you're not making active use of interrupts, EL0, page faults, etc., you can run entirely without causing exceptions. As you start making use of more CPU features, you'll have to add exception handlers one by one. You'll then have to check ESR_EL1 for the specific exceptions you want to handle, and dispatch them to your handler functions, but those will become obvious once you get there.