I'm working on a bare-metal interrupt controller. The underlying architecture is Virt, with QEMU, and a CPU Arm Cortex-72, aarch64. As an example, I provide you an excerpt of the Makefile:
run:
$(MAKE) kernel.elf
qemu-system-aarch64 -machine virt -cpu cortex-a72 -nographic -kernel kernel.elf
I defined an exception handler that is called everytime an exception occurs. This is an excerpt (output is written on a UART):
void common_trap_handler(exception_frame *exc)
{
uart_puts("\nException Handler! (");
uint32_t val = raw_read_current_el();
uart_puts("\n\tCurrent EL = ");
uart_puthex(val);
uart_puts("\t");
uart_puts("exc_type : ");
uart_puthex(exc->exc_type);
val = raw_read_icc_iar1_el1();
uart_puts("\n\tICC IAR1 EL1 = ");
uart_puthex(val);
// rest of the exception handler
}
Accesses to registers are done through assembly code. Reading the current exception level works:
uint32_t raw_read_current_el(void)
{
uint32_t current_el;
__asm__ __volatile__("mrs %0, CurrentEL\n\t" : "=r" (current_el) : : "memory");
return current_el;
}
Reading ICC_IAR1_EL1
register does not (more details below):
uint32_t raw_read_icc_iar1_el1(void)
{
uint32_t icc_iar1_el1 = 0;
__asm__ __volatile__("mrs %0, s3_0_c12_c12_0\n\t" : "=r" (icc_iar1_el1) : : "memory");
return icc_iar1_el1;
}
Where s3_0_c12_c12_0
is the ID of ICC_IAR1_EL1
according to arm specifications, since it is defined as a "register without an architectural name".
Getting access to ICC_IAR1_EL1
triggers a limitless number of other exceptions. This is an excerpt of the output (repeated several times):
Exception Handler! (
Current EL = 0x00000000 00000004 exc_type : 0x00000000 00000011
Exception Handler! (
Current EL = 0x00000000 00000004 exc_type : 0x00000000 00000011
Exception Handler! (
Current EL = 0x00000000 00000004 exc_type : 0x00000000 00000011
I can't understand why. According to the name of the register ICC_IAR1_EL1
, this register should be accessed with a minimum privilege of EL1. This is verified by the output Current EL = 0x00000000 00000004
. Do you know how can I read the content of ICC_IAR1_EL1
register? Unfortunately, the official ARM guide did not help me
You need to specify that you want your qemu-virt machine to use a GICv3 in order to be able to use the register interface to the GIC, and not a GICv2 with a memory-mapped interface, which is the version of the GIC used by default by the qem-virt machine.
The following command is working fine:
qemu-system-aarch64 -machine virt,gic-version=3 -cpu cortex-a72 -nographic -kernel kernel.elf
My test program:
.title minimal-aarch64.s
.arch armv8-a
.text
.section .text.startup,"ax"
.globl _start
.weak test
_start:
ldr x0, =__StackTop
mov sp, x0
bl test
wait: wfe
b wait
test:
mrs x0, s3_0_c12_c12_0
ret
.end
Using your command or
qemu-system-aarch64 -machine virt,gic-version=2 -cpu cortex-a72 -nographic -kernel kernel.elf
Does result in an exception being raised before the program returning from the test
subroutine, which is the behaviour you observed:
Breakpoint 2, test () at minimal-aarch64.s:15
0x0000000000000200 in ?? ()