Re: [PATCH v5 20/49] KVM: arm64: gic-v5: Add GICv5 IRS IODEV and MMIO emulation
[email protected] Fri, 07 Aug 2026 14:34:25 +0000
| Newsgroups | dev.linux.lists.kvmarm,org.kernel.vger.kvm |
|---|---|
| Message-ID | <[email protected]> |
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider: - [High] 64-bit IRS MMIO registers lack support for 32-bit accesses, leading to unhandled MMIO aborts and broken read-modify-write behavior. - [Medium] Missing locking in the IRS IST MMIO read handler allows guests to observe logically torn register states. - [Medium] Lockless, sequential updates to GICV5_IRS_CR1 can result in a torn MMIO write. -- --- Patch [20]: [PATCH v5 20/49] KVM: arm64: gic-v5: Add GICv5 IRS IODEV and MMIO emulation --- commit e3d747ac0ec8b60b894092ad4f2dc0c7959423ef Author: Sascha Bischoff <[email protected]> KVM: arm64: gic-v5: Add GICv5 IRS IODEV and MMIO emulation In order to properly support GICv5-based VMs in KVM, emulate the CONFIG_FRAME for a virtual IRS. This emulation needs to handle guest accesses to the MMIO region and mimic the behaviour of a real IRS. > diff --git a/arch/arm64/kvm/vgic/vgic-irs-v5.c b/arch/arm64/kvm/vgic/vgic-irs-v5.c > new file mode 100644 > index 0000000000000..c6280795ab551 > --- /dev/null > +++ b/arch/arm64/kvm/vgic/vgic-irs-v5.c [ ... ] > @@ -0,0 +1,765 @@ [ ... ] > +static void vgic_v5_mmio_write_irs_misc(struct kvm_vcpu *vcpu, gpa_t addr, > + unsigned int len, unsigned long val) > +{ > + struct vgic_v5_irs *irs = vgic_v5_get_irs(vcpu); > + struct vgic_dist *vgic = vgic_v5_get_vgic(vcpu); > + const size_t offset = addr & (SZ_64K - 1); > + > + switch (offset) { [ ... ] > + case GICV5_IRS_CR1: > + irs->cr1.sh = FIELD_GET(GICV5_IRS_CR1_SH, val); > + irs->cr1.oc = FIELD_GET(GICV5_IRS_CR1_OC, val); > + irs->cr1.ic = FIELD_GET(GICV5_IRS_CR1_IC, val); > + irs->cr1.ist_ra = !!(val & GICV5_IRS_CR1_IST_RA); > + irs->cr1.ist_wa = !!(val & GICV5_IRS_CR1_IST_WA); > + irs->cr1.vmt_ra = !!(val & GICV5_IRS_CR1_VMT_RA); > + irs->cr1.vpet_ra = !!(val & GICV5_IRS_CR1_VPET_RA); > + irs->cr1.vmd_ra = !!(val & GICV5_IRS_CR1_VMD_RA); > + irs->cr1.vmd_wa = !!(val & GICV5_IRS_CR1_VMD_WA); > + irs->cr1.vped_ra = !!(val & GICV5_IRS_CR1_VPED_RA); > + irs->cr1.vped_wa = !!(val & GICV5_IRS_CR1_VPED_WA); > + return; [Severity: Medium] Since these sequential writes are performed without holding config_lock, is there a risk of data races? If multiple vCPUs concurrently write different values to GICV5_IRS_CR1, it seems like the internal KVM state for irs->cr1 could end up in a torn state combining the concurrent writes. [ ... ] > +static unsigned long vgic_v5_mmio_read_irs_ist(struct kvm_vcpu *vcpu, > + gpa_t addr, unsigned int len) > +{ > + struct vgic_v5_irs *irs = vgic_v5_get_irs(vcpu); > + const size_t offset = addr & (SZ_64K - 1); > + u64 value = 0; > + > + switch (offset) { [ ... ] > + case GICV5_IRS_IST_BASER: > + value = FIELD_PREP(GICV5_IRS_IST_BASER_ADDR_MASK, > + irs->ist_baser.addr >> GICV5_IRS_IST_BASER_ADDR_SHIFT); > + if (irs->ist_baser.valid) > + value |= GICV5_IRS_IST_BASER_VALID; > + break; [Severity: Medium] Can guests observe logically torn register states here? The write handler vgic_v5_mmio_write_irs_ist() correctly holds config_lock to sequentially update irs->ist_baser.valid and irs->ist_baser.addr, but this read handler accesses them locklessly. If a vCPU reads GICV5_IRS_IST_BASER concurrently with a write, it could see an impossible state combining the old address with the new valid bit or vice-versa. [ ... ] > +static void vgic_v5_mmio_write_irs_ist(struct kvm_vcpu *vcpu, gpa_t addr, > + unsigned int len, unsigned long val) > +{ > + struct vgic_v5_irs *irs = vgic_v5_get_irs(vcpu); > + const size_t offset = addr & (SZ_64K - 1); > + enum gicv5_vcpu_cmd cmd = LPI_VIST_MAKE_INVALID; > + > + switch (offset) { [ ... ] > + case GICV5_IRS_IST_BASER: { [Severity: High] Does this strict matching on exact offsets break read-modify-write for 32-bit accesses to the high half of the register? If a guest performs a 32-bit write to offset + 4, it looks like this switch statement drops it. Also, interpreting a 32-bit payload as a full 64-bit value without adjusting for the offset would corrupt the register state. [ ... ] > +static const struct vgic_register_region vgic_v5_irs_registers[] = { [ ... ] > + REGISTER_DESC_WITH_LENGTH(GICV5_IRS_IST_BASER, vgic_v5_mmio_read_irs_ist, > + vgic_v5_mmio_write_irs_ist, 8, > + VGIC_ACCESS_64bit), [Severity: High] Could omitting VGIC_ACCESS_32bit for this 64-bit register cause the KVM IO bus to reject valid 32-bit guest accesses? If KVM's mmio dispatcher rejects a 32-bit access, the request will fall back to userspace IO. Since userspace does not emulate the in-kernel IRS, this usually results in an unhandled data abort injected into the guest. -- Sashiko AI review ยท https://sashiko.dev/#/patchset/[email protected]?part=20