hw/intc/arm_gic: GICV_HPPIR drops the virtual SGI source CPUID that GICV_IAR reports
Host environment
-
Operating system: macOS 14.8.7 (build 23J520)
-
OS/kernel version: Darwin 23.6.0 arm64
-
Architecture: ARM (aarch64, Apple silicon)
-
QEMU flavor: qemu-system-aarch64
-
QEMU version: 11.1.50 (v11.1.0-907-ga925240509), built from git master
-
QEMU command line:
qemu-system-aarch64 -M virt,gic-version=2,virtualization=on \ -cpu cortex-a57 -smp 2 -accel qtest -display none -qtest stdio
Emulated/Virtualized environment
- Operating system: none, qtest only
- OS/kernel version: n/a
- Architecture: ARM (GICv2 virtual CPU interface)
Description of problem
Disclosure: AI-assisted tooling helped prepare this report. I ran and verified the tests below.
For SGIs, bits [12:10] of IAR and HPPIR hold the source CPUID. On the virtual CPU interface the two registers disagree: GICV_IAR returns the CPUID from the List Register, GICV_HPPIR zeroes it. Same interrupt, two different sources.
With List Register 0 holding a pending SGI, INTID 5 from CPUID 1 (GICH_LR0 = 0x12000405):
readl 0x08040018 # GICV_HPPIR -> 0x00000005 (CPUID lost)
readl 0x0804000c # GICV_IAR -> 0x00000405 (CPUID present)Both should read 0x405.
Arm IHI 0048B.b defines the contract: 5.3.8 (GICV_IAR), 5.5.4 (the List Register CPUID field) and above all 5.5.7, which specifies the virtual HPPIR as reporting the same interrupt the next IAR read would return.
Steps to reproduce
-
Build qemu-system-aarch64 from master.
-
Run it with no kernel, disk or guest code, feeding the qtest commands on stdin. QEMU exits at EOF:
qemu-system-aarch64 -M virt,gic-version=2,virtualization=on \ -cpu cortex-a57 -smp 2 -accel qtest -display none -qtest stdiowritel 0x08040000 0x00000001 # GICV_CTLR: enable the virtual CPU interface writel 0x08040004 0x000000ff # GICV_PMR: allow all priorities writel 0x08030000 0x00000001 # GICH_HCR: enable the virtual interface writel 0x08030100 0x12000405 # GICH_LR0: pending SGI, INTID 5, CPUID 1 readl 0x08040018 # GICV_HPPIR readl 0x0804000c # GICV_IAR -
GICV_HPPIR reads 0x5, GICV_IAR reads 0x405.
Additional information
Varying only the LR CPUID field, measured with -smp 8 so every CPUID below is a real source CPU:
| GICH_LR0 | LR CPUID | GICV_HPPIR | GICV_IAR | agree |
|---|---|---|---|---|
| 0x12000005 | 0 | 0x5 | 0x5 | yes |
| 0x12000405 | 1 | 0x5 | 0x405 | no |
| 0x12001c05 | 7 | 0x5 | 0x1c05 | no |
This is generic GICv2 code, not board code, so any machine with a GICv2 virtual CPU interface is affected. Reproduced above on virt; also on -M raspi4b under TCG with a bare-metal EL2 payload, where the EL1 guest sees 0x005 instead of 0x405.
Reproduced on master a9252405 (2026-09-02) and on 11.0.2.