Home > OS >  Not getting system timer interrupts on QEMU aarch64 emulation
Not getting system timer interrupts on QEMU aarch64 emulation

Time:02-15

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.

  • Related