Skip to content

fix(armv8/vgic): correct addressing of forwarded register writes - #394

Open
josecm wants to merge 5 commits into
bao-project:mainfrom
josecm:fix/vgic-set-reg-vgicr-id
Open

fix(armv8/vgic): correct addressing of forwarded register writes#394
josecm wants to merge 5 commits into
bao-project:mainfrom
josecm:fix/vgic-set-reg-vgicr-id

Conversation

@josecm

@josecm josecm commented Aug 21, 2026

Copy link
Copy Markdown
Member

Four bugs in the vgic register emulation, plus a preparatory refactor of the message encoding.

  • ref(armv8/vgic): pack vgic ipi messages in a bitfield union. Replaces the VGIC_MSG_* shift/mask macros with a union type. No functional change.
  • fix(armv8/vgic): carry the redistributor id in forwarded register writes. The message hardcoded vgicr id 0, so a write to a private interrupt register of another vcpu's redistributor was applied to vcpu 0's interrupt instead of the intended one.
  • fix(armv8/vgic): update the route at the emulation site. The router emulation merged partial word writes against a route value that could be behind an in-flight forward to a remote interrupt owner, so the second half of a split 64-bit guest write (all aarch32 guests write IROUTER in two 32-bit halves) could resurrect the old route and the update was silently lost. It also truncated the forwarded value to the 8-bit message val field, losing the IRM bit and any affinity above Aff0. The route and the physical routing are now updated at the access site under the interrupt lock, where merges always see the current value, and the message to the owner becomes a data-less request to re-evaluate the routing.
  • fix(armv8/vgic): return the full 64-bit route on irouter reads. A doubleword read of IROUTER returned only the low word, truncating Aff3.
  • fix(armv8/vgic): pin private interrupt ownership to its vcpu. On GICv3 private interrupts were initialized without an owner and the owner could later be yielded back to none, so a core emulating a write to another vcpu's redistributor could take ownership and handle the access in place, manipulating another vcpu's banked interrupt state from the wrong core. The owner is now set at init and never yielded, as already on GICv2, so remote redistributor writes are always forwarded to the owning core, where the vgicr id fix above makes them land on the right interrupt.

The forwarding fixes trigger whenever the written interrupt is owned by a vcpu on another cpu, which with the ownership pinning now includes every write to another vcpu's private interrupt registers. Build-tested for GICv3 and GICv2 on qemu-aarch64-virt, and GICv3 on mps3-an536 (aarch32). The route update path is exercised at runtime by a guest test that cycles an SPI's route across all cpus and verifies each delivery lands on the routed cpu.

josecm added 2 commits August 20, 2026 16:47
Signed-off-by: Jose Martins <josemartins90@gmail.com>
The message sent to the interrupt owner's cpu hardcoded vgicr id 0, so a
write to a private interrupt register of another vcpu's redistributor was
applied to vcpu 0's interrupt instead of the intended one.

Signed-off-by: Jose Martins <josemartins90@gmail.com>
josecm added 2 commits August 21, 2026 19:23
The router emulation merged partial word writes against a route value
that could be behind an in-flight forward to a remote interrupt owner,
so the second half of a split 64-bit guest write could resurrect the
old route and the update was silently lost. It also truncated the
forwarded value to the 8-bit message val field. Update the route and
the physical routing at the access site under the interrupt lock,
where merges always see the current value, and reduce the message to
the owner to a data-less request to re-evaluate the routing.

Signed-off-by: Jose Martins <josemartins90@gmail.com>
A doubleword read of IROUTER returned only the low word, truncating
Aff3.

Signed-off-by: Jose Martins <josemartins90@gmail.com>
@josecm
josecm force-pushed the fix/vgic-set-reg-vgicr-id branch from e75b26a to bae2acf Compare August 21, 2026 18:23
@danielRep
danielRep self-requested a review August 28, 2026 09:52
@danielRep danielRep self-assigned this Aug 28, 2026
On GICv3 private interrupts were initialized without an owner and
vgic_yield_ownership could clear the owner again, so a core emulating a
write to another vcpu's redistributor could take ownership and handle
the access in place, manipulating another vcpu's banked interrupt state
from the wrong core. Initialize the owner to the vcpu, as already done
for GICv2, and never yield it, so remote accesses are always forwarded
to the owning core.

Signed-off-by: Jose Martins <josemartins90@gmail.com>
@josecm

josecm commented Aug 31, 2026

Copy link
Copy Markdown
Member Author

Pushed one more fix in 54a6eb4: on GICv3, private interrupts were initialized without an owner, so a core emulating a write to another vcpu's redistributor could take ownership and handle the access in place instead of forwarding it to the owning core. Private interrupt ownership is now pinned to the vcpu, as already on GICv2, so those writes always go through the owning core, where the vgicr id fix makes them land on the right interrupt.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants