Inconsistent reads from GICD_ITARGETSR0-7 on a real GIC-400
Posted: Mon Jul 12, 2021 1:02 pm
Hi!
Recently I've been trying to get managarm running on the Raspberry Pi 4, but when trying to get SMP working I noticed that reads from the GIC's GICD_ITARGETSR0-7 registers return inconsistent values (on CPU0 the read returns either 0x00000000, 0x01010101, or 0x02020202, on CPU1 it returns 0x00000000, 0x01010101, 0x02020202, or 0x04040404). As per the GICv2 specification, these registers are read only, and reading from them indicates the CPU interface number for the CPU that the read originated from. These inconsistent CPU interface numbers also seem to affect sending SGIs (with GICD_SGIR.TargetListFilter=1), since sometimes it seems that wrong CPUs receive the SGI (CPU 0 sends SGI to everyone but itself, yet it receives it).
I've confirmed the issue only happens under managarm, since if I run "for i in 0 1 2 3; do taskset -c $i devmem2 0xFF841800 w; done" in Linux, it always prints the expected result (and Linux probably would've panicked during initialization if the results were inconsistent), but despite this, I was unable to find the reason why this happens. The GIC registers are mapped as outer-shareable device nGnRnE memory, and whether the reads are relaxed or not does not seem to matter (Linux only does relaxed I/O to the GIC). I suspect this is some system register misconfiguration, but I have no clue at how to continue debugging this.
The code for the GIC driver can be found here: https://github.com/qookei/managarm/blob ... rm/gic.cpp and https://github.com/qookei/managarm/blob ... ch/gic.hpp. The code that reads the IRQ target regs starts at line 252. Do note that the code makes use of C++ features like operator overloading for accessing register fields etc.
Example output on CPU 0 (before entering the SMP code) from that function:
Any help would be greatly appreciated.
qookie
Recently I've been trying to get managarm running on the Raspberry Pi 4, but when trying to get SMP working I noticed that reads from the GIC's GICD_ITARGETSR0-7 registers return inconsistent values (on CPU0 the read returns either 0x00000000, 0x01010101, or 0x02020202, on CPU1 it returns 0x00000000, 0x01010101, 0x02020202, or 0x04040404). As per the GICv2 specification, these registers are read only, and reading from them indicates the CPU interface number for the CPU that the read originated from. These inconsistent CPU interface numbers also seem to affect sending SGIs (with GICD_SGIR.TargetListFilter=1), since sometimes it seems that wrong CPUs receive the SGI (CPU 0 sends SGI to everyone but itself, yet it receives it).
I've confirmed the issue only happens under managarm, since if I run "for i in 0 1 2 3; do taskset -c $i devmem2 0xFF841800 w; done" in Linux, it always prints the expected result (and Linux probably would've panicked during initialization if the results were inconsistent), but despite this, I was unable to find the reason why this happens. The GIC registers are mapped as outer-shareable device nGnRnE memory, and whether the reads are relaxed or not does not seem to matter (Linux only does relaxed I/O to the GIC). I suspect this is some system register misconfiguration, but I have no clue at how to continue debugging this.
The code for the GIC driver can be found here: https://github.com/qookei/managarm/blob ... rm/gic.cpp and https://github.com/qookei/managarm/blob ... ch/gic.hpp. The code that reads the IRQ target regs starts at line 252. Do note that the code makes use of C++ features like operator overloading for accessing register fields etc.
Example output on CPU 0 (before entering the SMP code) from that function:
Code: Select all
thor: zero v at i = 4? ignoring
thor: zero v at i = 5? ignoring
thor: bad v = 2020202 at i = 1, prev mask = 1
qookie