读取ICC_IAR1_EL1寄存器导致几个异常?



我正在研究裸机中断控制器。底层架构是带有QEMU的Virt, CPU是Arm Cortex-72,即aarch64。作为示例,我提供了Makefile的摘录:

run:
$(MAKE) kernel.elf
qemu-system-aarch64 -machine virt -cpu cortex-a72 -nographic -kernel kernel.elf

我定义了一个异常处理程序,每次发生异常时调用它。这是一个摘录(输出写入UART):

void common_trap_handler(exception_frame *exc)
{ 
uart_puts("nException Handler! (");
uint32_t val = raw_read_current_el();
uart_puts("ntCurrent EL = ");
uart_puthex(val);
uart_puts("t");
uart_puts("exc_type : ");
uart_puthex(exc->exc_type);

val = raw_read_icc_iar1_el1();
uart_puts("ntICC IAR1 EL1 = ");
uart_puthex(val); 
// rest of the exception handler
}

对寄存器的访问是通过汇编代码完成的。读取当前异常级别工作:

uint32_t raw_read_current_el(void)
{
uint32_t current_el;
__asm__ __volatile__("mrs %0, CurrentELnt" : "=r" (current_el) :  : "memory");
return current_el;
}

不读取ICC_IAR1_EL1寄存器(详细信息如下):

uint32_t raw_read_icc_iar1_el1(void)
{
uint32_t icc_iar1_el1 = 0;
__asm__ __volatile__("mrs %0, s3_0_c12_c12_0nt" : "=r" (icc_iar1_el1) :  : "memory");
return icc_iar1_el1; 
}

其中s3_0_c12_c12_0ICC_IAR1_EL1的ID,根据arm规范,因为它被定义为"没有体系结构名称的寄存器"。

访问ICC_IAR1_EL1会触发无限数量的其他异常。这是输出的摘录(重复了几次):

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

我不明白为什么。根据寄存器ICC_IAR1_EL1的名称,应该以最小权限EL1访问该寄存器。这可以通过输出Current EL = 0x00000000 00000004来验证。你知道如何读取ICC_IAR1_EL1寄存器的内容吗?不幸的是,官方的ARM指南并没有帮助我

您需要指定您希望您的qemu-virt机器使用GICv3以便能够使用寄存器接口到GIC,而不是使用具有内存映射接口的GICv2,这是qemu-virt机器默认使用的GIC版本。

下面的命令运行正常:

qemu-system-aarch64 -machine virt,gic-version=3 -cpu cortex-a72 -nographic -kernel kernel.elf
我的测试程序:
.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

使用命令或

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

确实会导致在程序从test子例程返回之前引发异常,这是您观察到的行为:

Breakpoint 2, test () at minimal-aarch64.s:15
0x0000000000000200 in ?? ()

最新更新