I am learning ARM baremetal development using QEMU as emulator. I am following this github repo as example.
The vectors are defined for EL1 :
vectors:
ventry sync_invalid_el1t // Synchronous EL1t
ventry irq_invalid_el1t // IRQ EL1t
ventry fiq_invalid_el1t // FIQ EL1t
ventry error_invalid_el1t // Error EL1t
ventry sync_invalid_el1h // Synchronous EL1h
ventry el1_irq // IRQ EL1h
ventry fiq_invalid_el1h // FIQ EL1h
ventry error_invalid_el1h // Error EL1h
ventry sync_invalid_el0_64 // Synchronous 64-bit EL0
ventry irq_invalid_el0_64 // IRQ 64-bit EL0
ventry fiq_invalid_el0_64 // FIQ 64-bit EL0
ventry error_invalid_el0_64 // Error 64-bit EL0
ventry sync_invalid_el0_32 // Synchronous 32-bit EL0
ventry irq_invalid_el0_32 // IRQ 32-bit EL0
ventry fiq_invalid_el0_32 // FIQ 32-bit EL0
ventry error_invalid_el0_32 // Error 32-bit EL0
.globl irq_vector_init
irq_vector_init:
adr x0, vectors // load VBAR_EL1 with virtual
msr vbar_el1, x0 // vector table address
ret
and setup well :
void enable_interrupt_controller()
{
put32(ENABLE_IRQS_1, SYSTEM_TIMER_IRQ_1);
}
The handler is defined like this :
el1_irq:
kernel_entry
bl handle_irq
kernel_exit
Following is timer handler :
void handle_irq(void)
{
unsigned int irq = get32(IRQ_PENDING_1);
switch (irq) {
case (SYSTEM_TIMER_IRQ_1):
handle_timer_irq();
break;
default:
printf("Unknown pending irq: %x\r\n", irq);
}
}
I am launching the binary using the following command, but I am not getting the timer handler prints, though other prints are working and binary works fine for me :
$ qemu-system-aarch64 -M raspi3 -device loader,file=./kernel8.img,addr=0x0 -serial null -serial stdio -display none
EDIT
Environment details :
naveen@workstation:~$ qemu-system-aarch64 --version
QEMU emulator version 4.2.1 (Debian 1:4.2-3ubuntu6.18)
Copyright (c) 2003-2019 Fabrice Bellard and the QEMU Project developers
naveen@workstation:~$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 20.04.3 LTS
Release: 20.04
Codename: focal
CodePudding user response:
A start for debugging this is to turn on the tracing in QEMU of events related to the bcm2835 system timer, which I think is what your code is using. You can do that with the command line option -d trace:bcm2835_systmr*
. In particular the "timer #1 expired" (or whatever timer number it is) messages indicate that the timer has raised its interrupt. If the timer isn't raising the interrupt then you've programmed the timer wrongly; if it is then you've probably not set up the interrupt controller correctly.
You should probably also double-check that you're really executing in EL1 as you expect.
Older versions of QEMU supported the raspi3 board but did not implement this particular system timer device; so if you don't see timer expiry tracing then it's worth checking your QEMU is new enough. 6.2.0 definitely has this device implemented.