我无法重置 GICv3 相关寄存器的值?

问题描述

我正在研究一个裸机中断控制器,GIC 版本 3。底层架构是 Virt,带有 QEMU,和一个 cpu Arm Cortex-72,aarch64。我使用以下命令运行我的项目:

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

我无法重置 GIC_GICC_BPR1_EL1 的值,但我可以将其设置为任何其他值。我在下面准备了一个测试函数

void test(void) {
    uint64_t state = 0;

    // set Binary point to 0x07
    SysReg_write_ICC_BPR1_EL1(0x07);
    // read Binary point    
    state = SysReg_read_ICC_BPR1_EL1();
    uart_puts("TEST - ICC_BPR1_EL1 (expected 0x7): ");
    uart_puthex(state);
    uart_puts("\n");

    // set Binary point to 0
    SysReg_write_ICC_BPR1_EL1(0x00);

    // read Binary point    
    state = SysReg_read_ICC_BPR1_EL1();
    uart_puts("TEST - ICC_BPR1_EL1 (expected 0): ");
    uart_puthex(state);
    uart_puts("\n");  
}

读取和设置的功能是:

uint64_t SysReg_read_ICC_BPR1_EL1(void)
{
    uint64_t val;
    asm volatile("mrs %0,s3_0_c12_c12_3" : "=r" (val));
    return val;
}

// write system register  ICC_BPR1_EL1 (s3_0_c12_c12_3) with specified value.
// source: /home/user/git/preprocessor/arm/SysReg_xml_v87A-2020-09/AArch64-icc_bpr1_el1.xml
void SysReg_write_ICC_BPR1_EL1(uint64_t val)
{
    asm volatile("msr s3_0_c12_c12_3,%0" : : "r" (val));
}

其中 s3_0_c12_c12_3 是根据 arm 规范的寄存器 ID,因为 GICC 相关寄存器被定义为“没有架构名称的寄存器”。

这个例子的输出是:

TEST - ICC_BPR1_EL1 (expected 0x7): 0x00000000 00000007
TEST - ICC_BPR1_EL1 (expected 0): 0x00000000 00000001

我使用的是 uart,但您也可以使用 gdb,方法获取 void test(void) 函数的汇编代码并使用标签

所以,我不能以任何方式将其设置为 0。 你知道我错在哪里吗?

解决方法

我无法重现您的问题,您的功能在我的设置中运行良好。但是,我可能有一组不同的 gcc/qemu-sytem-aarch64/gdb。

minimal-aarch64.c:

#include <stdint.h>

uint64_t raw_read_gic_gicc_bpr1_el1(void) {
    uint64_t gicc_bpr1_el1 = 0;
    __asm__ __volatile__("mrs %0,s3_0_c12_c12_3\n\t" : "=r" (gicc_bpr1_el1) :  : "memory");
    return gicc_bpr1_el1; 
}

void set_gic_gicc_bpr1_el1(uint64_t value)
{
    __asm__ __volatile__("msr s3_0_c12_c12_3,%0\n\t" : : "r" (value) : "memory");
}

int main(int argc,char** argv)
{
    uint64_t state = 0;

    set_gic_gicc_bpr1_el1(0x00);
    state = raw_read_gic_gicc_bpr1_el1();   
    
    set_gic_gicc_bpr1_el1(0x07);
    state = raw_read_gic_gicc_bpr1_el1();   
}

编译:

/opt/arm/10/gcc-arm-10.2-2020.11-x86_64-aarch64-none-elf/bin/aarch64-none-elf-gcc -g --specs=rdimon.specs -o minimal-aarch64.elf minimal-aarch64.c

启动 QEMU:

/opt/qemu-5.2.0/bin/qemu-system-aarch64 -semihosting -m 1M -nographic -serial telnet::4444,server,nowait -machine virt,gic-version=3,secure=on,virtualization=off -S -gdb tcp::1234,ipv4 -cpu cortex-a72 -kernel minimal-aarch64.elf

启动 GDB:

/opt/gdb/gdb-10.1-aarch64-elf-x86_64-linux-gnu/bin/aarch64-elf-gdb -tui --quiet -nx -ex 'target remote localhost:1234' -ex 'load' --ex 'b main'  minimal-aarch64.elf

GDG 会议:

remote Thread 1.1 In: main                                                                                                                                                                                                                                  L23   PC: 0x400360 
Loading section .text,size 0x3894 lma 0x400040
Loading section .fini,size 0x34 lma 0x4038d4
Loading section .rodata,size 0x74 lma 0x403908
Loading section .eh_frame,size 0x4 lma 0x40397c
Loading section .init_array,size 0x8 lma 0x413980
Loading section .fini_array,size 0x8 lma 0x413988
Loading section .data,size 0x10c8 lma 0x413990
Start address 0x0000000000400178,load size 19020
Transfer rate: 1326 KB/sec,1118 bytes/write.
Breakpoint 1 at 0x400338: file minimal-aarch64.c,line 16.
(gdb) c
Continuing.

Breakpoint 1,main (argc=1,argv=0x400fffe0) at minimal-aarch64.c:16
(gdb) p/x state
$1 = 0x0
(gdb) step
set_gic_gicc_bpr1_el1 (value=0) at minimal-aarch64.c:11
main (argc=1,argv=0x400fffe0) at minimal-aarch64.c:19
(gdb) p/x state
$2 = 0x0
(gdb) step
raw_read_gic_gicc_bpr1_el1 () at minimal-aarch64.c:4
main (argc=1,argv=0x400fffe0) at minimal-aarch64.c:21
set_gic_gicc_bpr1_el1 (value=7) at minimal-aarch64.c:11
main (argc=1,argv=0x400fffe0) at minimal-aarch64.c:22
raw_read_gic_gicc_bpr1_el1 () at minimal-aarch64.c:4
main (argc=1,argv=0x400fffe0) at minimal-aarch64.c:23
(gdb) p/x state
$3 = 0x7
(gdb) 

请注意,某些值可能无效,至少根据 Arm Cortex-A78C Core Technical Reference Manual Revision r0p1(我在 A72 文档中找不到该信息):

The minimum value implemented of ICC_BPR1_EL1 Secure register is 0x2.

The minimum value implemented of ICC_BPR1_EL1 Non-secure register is 0x3.

但根据 Arm Architecture System Registers document 版本 2020-12:

enter image description here

这可以解释为什么不能在 ICC-BPR1-EL1 中写入 0 值。