I'm working on a bare-metal interrupt controller, GIC version 3. The underlying architecture is Virt, with QEMU, and a CPU Arm Cortex-72, aarch64. I run my project with the following command:
qemu-system-aarch64 -machine virt,gic-version=3 -cpu cortex-a72 -nographic -kernel kernel.elf
I can't reset the value of GIC_GICC_BPR1_EL1, but I can set it to any other value. I prepared a test function just below:
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");
}
Functions for reading and setting are:
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));
}
Where s3_0_c12_c12_3
is the ID of the register according to arm specifications, since GICC-related registers are defined as a "registers without an architectural name".
The output of this example is:
TEST - ICC_BPR1_EL1 (expected 0x7): 0x00000000 00000007
TEST - ICC_BPR1_EL1 (expected 0): 0x00000000 00000001
I used an uart, but you can use gdb as well, by taking the assembly code of void test(void) function and using labels.
So, I can't set it to 0 in any way. Do you know where am I wrong?
I was unable to reproduce your problem, your functions are working fine on my setup. However, I may have a different set of 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();
}
Compiling:
/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
Starting 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
Starting 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 session:
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)
Please note that some values may be invalid, at least according to the Arm Cortex-A78C Core Technical Reference Manual Revision r0p1 (I could not find the information in the A72 documentation):
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.
But according to the Arm Architecture System Registers document version 2020-12:
This may explain why you cannot write a 0 value in ICC-BPR1-EL1
.