Jason Xu 9c5c2813a0 Update QEMU command in all README and Makefile 2 years ago
..
Makefile 426205e2a3 Added makefiles for LLVM Clang 5 years ago
Makefile.clang 9c5c2813a0 Update QEMU command in all README and Makefile 2 years ago
Makefile.gcc 9c5c2813a0 Update QEMU command in all README and Makefile 2 years ago
OLVASSEL.md 9c5c2813a0 Update QEMU command in all README and Makefile 2 years ago
README.md 9c5c2813a0 Update QEMU command in all README and Makefile 2 years ago
exc.c 2fc348ba46 Fixed typos and more tutorials 6 years ago
gpio.h 2fc348ba46 Fixed typos and more tutorials 6 years ago
kernel8.img 8ce0f75b47 Recompiled with latest gcc 4 years ago
link.ld 2fc348ba46 Fixed typos and more tutorials 6 years ago
main.c 2fc348ba46 Fixed typos and more tutorials 6 years ago
mbox.c 214885df63 compute the mailbox cmd only once 6 years ago
mbox.h 2fc348ba46 Fixed typos and more tutorials 6 years ago
mmu.c 1cc441850b no further cast to "(unsigned long)" needed 6 years ago
mmu.h 2fc348ba46 Fixed typos and more tutorials 6 years ago
start.S ea4691947c Improve comments wrt stack setup 3 years ago
uart.c c59ad439f4 Enable UART0 FIFOs 3 years ago
uart.h 2fc348ba46 Fixed typos and more tutorials 6 years ago

README.md

Tutorial 11 - Exceptions

Last time we have used a very simple translation scheme, but in real life you often need more. And it is not easy to write the table blindly, so we're going to add exception handlers this time. This will print out some system registers to identify the problem with our translation tables.

$ qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial stdio
Synchronous: Data abort, same EL, Translation fault at level 2:
  ESR_EL1 0000000096000006 ELR_EL1 0000000000080D7C
 SPSR_EL1 00000000200003C4 FAR_EL1 FFFFFFFFFF000000

Here ESR_EL1 tells us that it was a Data Abort, caused by a translation table error at level 2. The instruction triggered it is at address 0x80D7C which tried to access memory at 0xFFFFFFFFFF000000.

The vector is very similar to AMD64's IDT, with two exceptions: first, there's no special instruction (like sidt), but a system register stores the address. Second, we don't pass a table with addresses rather the address of the actual code. Therefore each "entry" of the vector table is bigger, small stubs so that you can set up arguments and jump to a common handler.

On AMD64 you have 32 entry points for each exception. On AArch, you only have one, and you can read the excpetion code from a system register. Considering that all OS sets a code for the exception and jumps to a common handler, this makes life easier.

Exc.c

exc_handler() a simple exception handler that dumps registers and decodes ESR_EL1 (partially). We simply stop the CPU for now, as we have no means to recover from an exception yet. The full comprehensive description of Exception Syndrome Register can be found in ARM DDI0487B_b chapter D10.2.28.

Start

Before we switch to supervisor mode, we set up vbar_el1. All handlers must be properly aligned. Qemu is not so picky, but real hardware is.

_vectors the exception handler's vector table with small assembly stubs, each calling exc_handler() in C.

Main

We set up page translations, and then we deliberatly reference an unmapped address to trigger an exception.