首页 > 解决方案 > 在 arm64 GICv3 中捕获 IRQ 的步骤?

问题描述

我正在开发一个裸机中断控制器,GIC 版本 3。底层架构是 Virt,带有 QEMU,以及 CPU Arm Cortex-72,aarch64:

qemu-system-aarch64 -machine virt,gic-version=3 -cpu cortex-a72 -nographic -kernel kernel.elf

根据ARMv8-A 指南,中断组 1 启用寄存器0寄存器ICC_IGRPEN1_EL1的位负责 IRQ 的激活。这是它的摘录:

在此处输入图像描述

我指定我在非安全模式下工作。

我想从时序上下文中生成一个 IRQ。计时器运行良好,但由于任何原因,即使位设置为 1 0,也不会捕获 IRQ。ICC_IGRPEN1_EL1

由于我使用了多个标题,因此我无法为您提供最小示例。我没有办法,如果你能建议我怎么做,请做。但是,我已尽力提出一个明确的问题,所以我真的希望您能提供帮助。

这是生成 IRQ 的函数的摘录:

 void timer_init(void)
{
    uint64_t ticks, current_cnt;
 
    // Disable the timer
    disable_cntv();

    //read system frequency
    cntfrq = raw_read_cntfrq_el0();

    // Next timer IRQ is after 3 sec(s).
    ticks = 3 * cntfrq;
    
    // Get value of the current timer
    current_cnt = raw_read_cntvct_el0();
        
    // Set the interrupt in Current Time + TimerTick
    raw_write_cntv_cval_el0(current_cnt + ticks);

    // Enable the timer
    enable_cntv();

    // Enable IRQ   
    enable_irqs();
    
    while(1){
        wfi();  
    }
}

函数enable_irqs定义如下:

void enable_irqs(void) {
    set_gic_gicc_igrpen1_el1(0x1);
}

反过来,函数set_gic_gicc_igrpen1_el1是:

void set_gic_gicc_igrpen1_el1(uint64_t value)
{
    __asm__ __volatile__("msr s3_0_c12_c12_7 , %0" : : "r" (value));
}

我用 gdb 验证了所有值:定时器工作,寄存器ICC_IGRPEN1_EL1的最后一位设置为1. 您是否注意到此代码中有任何我没有收到任何 IRQ 的错误?

不完整,我提到的其他功能实现如下:

void disable_cntv(void)
{
    uint32_t cntv_ctl;

    cntv_ctl = raw_read_cntv_ctl();
    cntv_ctl &= ~CNTV_CTL_ENABLE;
    __asm__ __volatile__("msr CNTV_CTL_EL0, %0\n\t" : : "r" (cntv_ctl) : "memory");
}

void enable_cntv(void)
{
    uint32_t cntv_ctl;

    cntv_ctl = raw_read_cntv_ctl();
    cntv_ctl |= CNTV_CTL_ENABLE;
    __asm__ __volatile__("msr CNTV_CTL_EL0, %0\n\t" : : "r" (cntv_ctl) : "memory");
}

uint32_t raw_read_cntfrq_el0(void)
{
    uint32_t cntfrq_el0;

    __asm__ __volatile__("mrs %0, CNTFRQ_EL0\n\t" : "=r" (cntfrq_el0) : : "memory");
    return cntfrq_el0;
}

void raw_write_cntv_cval_el0(uint64_t cntv_cval_el0)
{
    __asm__ __volatile__("msr CNTV_CVAL_EL0, %0\n\t" : : "r" (cntv_cval_el0) : "memory");
}

    uint64_t raw_read_cntvct_el0(void)
{
    uint64_t cntvct_el0;
        __asm__ __volatile__("mrs %0, CNTVCT_EL0\n\t" : "=r" (cntvct_el0) : : "memory");
        return cntvct_el0;
}

/* Wait For Interrupt */
#define wfi()       asm volatile("wfi" : : : "memory")

CNTV_CTL_ENABLE定义如下:

#define CNTV_CTL_ENABLE     (1 << 0)    /* Enables the timer */ 

标签: armarm64bare-metal

解决方案


推荐阅读