public inbox for linux-arm-kernel@lists.infradead.org
 help / color / mirror / Atom feed
* [PATCH v2 00/16] KVM: arm64: First batch of vgic-v5 related fixes
@ 2026-04-01 10:35 Marc Zyngier
  2026-04-01 10:35 ` [PATCH v2 01/16] KVM: arm64: vgic: Don't reset cpuif/redist addresses at finalize time Marc Zyngier
                   ` (16 more replies)
  0 siblings, 17 replies; 19+ messages in thread
From: Marc Zyngier @ 2026-04-01 10:35 UTC (permalink / raw)
  To: kvmarm, kvm, linux-arm-kernel
  Cc: Joey Gouly, Suzuki K Poulose, Oliver Upton, Zenghui Yu,
	Sascha Bischoff, Mark Brown

This is the second revision of this series attempting to fix a number
of issues reported on the vgic-v5 PPI series.

* From v1 [1]:

  - Partially reverted the effective priority mask fix, as Sascha
    pointed out the crucial difference in the way GICv5 manages the
    PCR compared to GICv[234]'s PMR.

  - Added a fix for dealing with the pending HW-backed PPIs.

  - Added a workaround for the set_id_regs selftest, already posted
    separately, but included here for completeness (and ease of
    merging).

Patches on top of my kvm-arm64/vgic-v5-ppi branch.

[1] https://lore.kernel.org/r/20260326153530.3981879-1-maz@kernel.org

Marc Zyngier (16):
  KVM: arm64: vgic: Don't reset cpuif/redist addresses at finalize time
  KVM: arm64: Don't skip per-vcpu NV initialisation
  arm64: Fix field references for ICH_PPI_DVIR[01]_EL2
  KVM: arm64: Fix writeable mask for ID_AA64PFR2_EL1
  KVM: arm64: Account for RESx bits in __compute_fgt()
  KVM: arm64: vgic-v5: Hold config_lock while finalizing GICv5 PPIs
  KVM: arm64: vgic-v5: Transfer edge pending state to ICH_PPI_PENDRx_EL2
  KVM: arm64: vgic-v5: Cast vgic_apr to u32 to avoid undefined
    behaviours
  KVM: arm64: vgic-v5: Make the effective priority mask a strict limit
  KVM: arm64: vgic-v5: Correctly set dist->ready once initialised
  KVM: arm64: Kill arch_timer_context::direct field
  KVM: arm64: Remove evaluation of timer state in
    kvm_cpu_has_pending_timer()
  KVM: arm64: Move GICv5 timer PPI validation into
    timer_irqs_are_valid()
  KVM: arm64: Correctly plumb ID_AA64PFR2_EL1 into pkvm idreg handling
  KVM: arm64: Don't advertises GICv3 in ID_PFR1_EL1 if AArch32 isn't
    supported
  KVM: arm64: set_id_regs: Allow GICv3 support to be set at runtime

 arch/arm64/kvm/arch_timer.c                   | 32 +++++-------
 arch/arm64/kvm/config.c                       |  4 +-
 arch/arm64/kvm/hyp/nvhe/sys_regs.c            |  2 +-
 arch/arm64/kvm/sys_regs.c                     | 20 +++----
 arch/arm64/kvm/vgic/vgic-init.c               | 32 ++++++++----
 arch/arm64/kvm/vgic/vgic-v5.c                 | 24 +++++++--
 arch/arm64/tools/sysreg                       |  4 +-
 include/kvm/arm_arch_timer.h                  |  3 --
 .../testing/selftests/kvm/arm64/set_id_regs.c | 52 ++++++++++++++++---
 9 files changed, 115 insertions(+), 58 deletions(-)


base-commit: ce29261ec6482de54320c03398eb30e9615aee40
-- 
2.47.3



^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v2 01/16] KVM: arm64: vgic: Don't reset cpuif/redist addresses at finalize time
  2026-04-01 10:35 [PATCH v2 00/16] KVM: arm64: First batch of vgic-v5 related fixes Marc Zyngier
@ 2026-04-01 10:35 ` Marc Zyngier
  2026-04-01 10:35 ` [PATCH v2 02/16] KVM: arm64: Don't skip per-vcpu NV initialisation Marc Zyngier
                   ` (15 subsequent siblings)
  16 siblings, 0 replies; 19+ messages in thread
From: Marc Zyngier @ 2026-04-01 10:35 UTC (permalink / raw)
  To: kvmarm, kvm, linux-arm-kernel
  Cc: Joey Gouly, Suzuki K Poulose, Oliver Upton, Zenghui Yu,
	Sascha Bischoff, Mark Brown

Although we are OK with rewriting idregs at finalize time, resetting
the guest's cpuif (GICv3) or redistributor (GICv3) addresses once
we start running the guest is a pretty bad idea.

Move back this initialisation to vgic creation time.

Reviewed-by: Sascha Bischoff <sascha.bischoff@arm.com>
Fixes: a258a383b9177 ("KVM: arm64: gic-v5: Sanitize ID_AA64PFR2_EL1.GCIE")
Link: https://patch.msgid.link/20260323174713.3183111-1-maz@kernel.org
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/kvm/vgic/vgic-init.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
index 47169604100f2..fd872079f2a24 100644
--- a/arch/arm64/kvm/vgic/vgic-init.c
+++ b/arch/arm64/kvm/vgic/vgic-init.c
@@ -147,6 +147,15 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
 	kvm->arch.vgic.implementation_rev = KVM_VGIC_IMP_REV_LATEST;
 	kvm->arch.vgic.vgic_dist_base = VGIC_ADDR_UNDEF;
 
+	switch (type) {
+	case KVM_DEV_TYPE_ARM_VGIC_V2:
+		kvm->arch.vgic.vgic_cpu_base = VGIC_ADDR_UNDEF;
+		break;
+	case KVM_DEV_TYPE_ARM_VGIC_V3:
+		INIT_LIST_HEAD(&kvm->arch.vgic.rd_regions);
+		break;
+	}
+	
 	/*
 	 * We've now created the GIC. Update the system register state
 	 * to accurately reflect what we've created.
@@ -684,10 +693,8 @@ void kvm_vgic_finalize_idregs(struct kvm *kvm)
 
 	switch (type) {
 	case KVM_DEV_TYPE_ARM_VGIC_V2:
-		kvm->arch.vgic.vgic_cpu_base = VGIC_ADDR_UNDEF;
 		break;
 	case KVM_DEV_TYPE_ARM_VGIC_V3:
-		INIT_LIST_HEAD(&kvm->arch.vgic.rd_regions);
 		aa64pfr0 |= SYS_FIELD_PREP_ENUM(ID_AA64PFR0_EL1, GIC, IMP);
 		pfr1 |= SYS_FIELD_PREP_ENUM(ID_PFR1_EL1, GIC, GICv3);
 		break;
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v2 02/16] KVM: arm64: Don't skip per-vcpu NV initialisation
  2026-04-01 10:35 [PATCH v2 00/16] KVM: arm64: First batch of vgic-v5 related fixes Marc Zyngier
  2026-04-01 10:35 ` [PATCH v2 01/16] KVM: arm64: vgic: Don't reset cpuif/redist addresses at finalize time Marc Zyngier
@ 2026-04-01 10:35 ` Marc Zyngier
  2026-04-01 10:35 ` [PATCH v2 03/16] arm64: Fix field references for ICH_PPI_DVIR[01]_EL2 Marc Zyngier
                   ` (14 subsequent siblings)
  16 siblings, 0 replies; 19+ messages in thread
From: Marc Zyngier @ 2026-04-01 10:35 UTC (permalink / raw)
  To: kvmarm, kvm, linux-arm-kernel
  Cc: Joey Gouly, Suzuki K Poulose, Oliver Upton, Zenghui Yu,
	Sascha Bischoff, Mark Brown

Some GICv5-related rework have resulted in the NV sanitisation of
registers being skipped for secondary vcpus, which is a pretty bad
idea.

Hoist the NV init early so that it is always executed.

Reviewed-by: Sascha Bischoff <sascha.bischoff@arm.com>
Fixes: cbd8c958be54a ("KVM: arm64: Return early from kvm_finalize_sys_regs() if guest has run")
Link: https://sashiko.dev/#/patchset/20260319154937.3619520-1-sascha.bischoff%40arm.com
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/kvm/sys_regs.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index e1001544d4f40..18e2d2fccedb8 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -5772,6 +5772,12 @@ int kvm_finalize_sys_regs(struct kvm_vcpu *vcpu)
 
 	guard(mutex)(&kvm->arch.config_lock);
 
+	if (vcpu_has_nv(vcpu)) {
+		int ret = kvm_init_nv_sysregs(vcpu);
+		if (ret)
+			return ret;
+	}
+
 	if (kvm_vm_has_ran_once(kvm))
 		return 0;
 
@@ -5820,12 +5826,6 @@ int kvm_finalize_sys_regs(struct kvm_vcpu *vcpu)
 		kvm_vgic_finalize_idregs(kvm);
 	}
 
-	if (vcpu_has_nv(vcpu)) {
-		int ret = kvm_init_nv_sysregs(vcpu);
-		if (ret)
-			return ret;
-	}
-
 	return 0;
 }
 
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v2 03/16] arm64: Fix field references for ICH_PPI_DVIR[01]_EL2
  2026-04-01 10:35 [PATCH v2 00/16] KVM: arm64: First batch of vgic-v5 related fixes Marc Zyngier
  2026-04-01 10:35 ` [PATCH v2 01/16] KVM: arm64: vgic: Don't reset cpuif/redist addresses at finalize time Marc Zyngier
  2026-04-01 10:35 ` [PATCH v2 02/16] KVM: arm64: Don't skip per-vcpu NV initialisation Marc Zyngier
@ 2026-04-01 10:35 ` Marc Zyngier
  2026-04-01 10:35 ` [PATCH v2 04/16] KVM: arm64: Fix writeable mask for ID_AA64PFR2_EL1 Marc Zyngier
                   ` (13 subsequent siblings)
  16 siblings, 0 replies; 19+ messages in thread
From: Marc Zyngier @ 2026-04-01 10:35 UTC (permalink / raw)
  To: kvmarm, kvm, linux-arm-kernel
  Cc: Joey Gouly, Suzuki K Poulose, Oliver Upton, Zenghui Yu,
	Sascha Bischoff, Mark Brown

The ICH_PPI_DVIR[01]_EL2 registers should refer to the ICH_PPI_DVIRx_EL2
fields, instead of ICH_PPI_DVIx_EL2.

Reviewed-by: Sascha Bischoff <sascha.bischoff@arm.com>
Fixes: 2808a8337078f ("arm64/sysreg: Add remaining GICv5 ICC_ & ICH_ sysregs for KVM support")
Link: https://sashiko.dev/#/patchset/20260319154937.3619520-1-sascha.bischoff%40arm.com
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/tools/sysreg | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/tools/sysreg b/arch/arm64/tools/sysreg
index 51dcca5b2fa6e..3b57cb692c5be 100644
--- a/arch/arm64/tools/sysreg
+++ b/arch/arm64/tools/sysreg
@@ -4888,11 +4888,11 @@ Field	0	DVI0
 EndSysregFields
 
 Sysreg	ICH_PPI_DVIR0_EL2	3	4	12	10	0
-Fields ICH_PPI_DVIx_EL2
+Fields ICH_PPI_DVIRx_EL2
 EndSysreg
 
 Sysreg	ICH_PPI_DVIR1_EL2	3	4	12	10	1
-Fields ICH_PPI_DVIx_EL2
+Fields ICH_PPI_DVIRx_EL2
 EndSysreg
 
 SysregFields	ICH_PPI_ENABLERx_EL2
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v2 04/16] KVM: arm64: Fix writeable mask for ID_AA64PFR2_EL1
  2026-04-01 10:35 [PATCH v2 00/16] KVM: arm64: First batch of vgic-v5 related fixes Marc Zyngier
                   ` (2 preceding siblings ...)
  2026-04-01 10:35 ` [PATCH v2 03/16] arm64: Fix field references for ICH_PPI_DVIR[01]_EL2 Marc Zyngier
@ 2026-04-01 10:35 ` Marc Zyngier
  2026-04-01 10:36 ` [PATCH v2 05/16] KVM: arm64: Account for RESx bits in __compute_fgt() Marc Zyngier
                   ` (12 subsequent siblings)
  16 siblings, 0 replies; 19+ messages in thread
From: Marc Zyngier @ 2026-04-01 10:35 UTC (permalink / raw)
  To: kvmarm, kvm, linux-arm-kernel
  Cc: Joey Gouly, Suzuki K Poulose, Oliver Upton, Zenghui Yu,
	Sascha Bischoff, Mark Brown

The writeable mask for fields in ID_AA64PFR2_EL1 has been accidentally
inverted, which isn't a very good idea.

Restore the expected polarity.

Reviewed-by: Sascha Bischoff <sascha.bischoff@arm.com>
Fixes: a258a383b9177 ("KVM: arm64: gic-v5: Sanitize ID_AA64PFR2_EL1.GCIE")
Link: https://sashiko.dev/#/patchset/20260319154937.3619520-1-sascha.bischoff%40arm.com
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/kvm/sys_regs.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 18e2d2fccedb8..6a96cb7ba9a3c 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -3304,10 +3304,10 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 				       ID_AA64PFR1_EL1_MPAM_frac |
 				       ID_AA64PFR1_EL1_MTE)),
 	ID_FILTERED(ID_AA64PFR2_EL1, id_aa64pfr2_el1,
-		    ~(ID_AA64PFR2_EL1_FPMR |
-		      ID_AA64PFR2_EL1_MTEFAR |
-		      ID_AA64PFR2_EL1_MTESTOREONLY |
-		      ID_AA64PFR2_EL1_GCIE)),
+		    (ID_AA64PFR2_EL1_FPMR		|
+		     ID_AA64PFR2_EL1_MTEFAR		|
+		     ID_AA64PFR2_EL1_MTESTOREONLY	|
+		     ID_AA64PFR2_EL1_GCIE)),
 	ID_UNALLOCATED(4,3),
 	ID_WRITABLE(ID_AA64ZFR0_EL1, ~ID_AA64ZFR0_EL1_RES0),
 	ID_HIDDEN(ID_AA64SMFR0_EL1),
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v2 05/16] KVM: arm64: Account for RESx bits in __compute_fgt()
  2026-04-01 10:35 [PATCH v2 00/16] KVM: arm64: First batch of vgic-v5 related fixes Marc Zyngier
                   ` (3 preceding siblings ...)
  2026-04-01 10:35 ` [PATCH v2 04/16] KVM: arm64: Fix writeable mask for ID_AA64PFR2_EL1 Marc Zyngier
@ 2026-04-01 10:36 ` Marc Zyngier
  2026-04-01 10:36 ` [PATCH v2 06/16] KVM: arm64: vgic-v5: Hold config_lock while finalizing GICv5 PPIs Marc Zyngier
                   ` (11 subsequent siblings)
  16 siblings, 0 replies; 19+ messages in thread
From: Marc Zyngier @ 2026-04-01 10:36 UTC (permalink / raw)
  To: kvmarm, kvm, linux-arm-kernel
  Cc: Joey Gouly, Suzuki K Poulose, Oliver Upton, Zenghui Yu,
	Sascha Bischoff, Mark Brown, stable

When computing Fine Grained Traps, it is preferable to account for
the reserved bits. The HW will most probably ignore them, unless the
bits have been repurposed to do something else.

Use caution, and fold our view of the reserved bits in,

Reviewed-by: Sascha Bischoff <sascha.bischoff@arm.com>
Fixes: c259d763e6b09 ("KVM: arm64: Account for RES1 bits in DECLARE_FEAT_MAP() and co")
Link: https://sashiko.dev/#/patchset/20260319154937.3619520-1-sascha.bischoff%40arm.com
Signed-off-by: Marc Zyngier <maz@kernel.org>
Cc: stable@vger.kernel.org
---
 arch/arm64/kvm/config.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
index e14685343191b..f35b8dddd7c1f 100644
--- a/arch/arm64/kvm/config.c
+++ b/arch/arm64/kvm/config.c
@@ -1663,8 +1663,8 @@ static __always_inline void __compute_fgt(struct kvm_vcpu *vcpu, enum vcpu_sysre
 		clear |= ~nested & m->nmask;
 	}
 
-	val |= set;
-	val &= ~clear;
+	val |= set | m->res1;
+	val &= ~(clear | m->res0);
 	*vcpu_fgt(vcpu, reg) = val;
 }
 
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v2 06/16] KVM: arm64: vgic-v5: Hold config_lock while finalizing GICv5 PPIs
  2026-04-01 10:35 [PATCH v2 00/16] KVM: arm64: First batch of vgic-v5 related fixes Marc Zyngier
                   ` (4 preceding siblings ...)
  2026-04-01 10:36 ` [PATCH v2 05/16] KVM: arm64: Account for RESx bits in __compute_fgt() Marc Zyngier
@ 2026-04-01 10:36 ` Marc Zyngier
  2026-04-01 10:36 ` [PATCH v2 07/16] KVM: arm64: vgic-v5: Transfer edge pending state to ICH_PPI_PENDRx_EL2 Marc Zyngier
                   ` (10 subsequent siblings)
  16 siblings, 0 replies; 19+ messages in thread
From: Marc Zyngier @ 2026-04-01 10:36 UTC (permalink / raw)
  To: kvmarm, kvm, linux-arm-kernel
  Cc: Joey Gouly, Suzuki K Poulose, Oliver Upton, Zenghui Yu,
	Sascha Bischoff, Mark Brown

Finalizing the PPI state is done without holding any lock, which
means that two vcpus can race against each other and have one zeroing
the state while another one is setting it, or even maybe using it.

Fixing this is done by:

- holding the config lock while performing the initialisation

- checking if SW_PPI has already been advertised, meaning that
  we have already completed the initialisation once

Reviewed-by: Sascha Bischoff <sascha.bischoff@arm.com>
Fixes: 8f1fbe2fd2792 ("KVM: arm64: gic-v5: Finalize GICv5 PPIs and generate mask")
Link: https://sashiko.dev/#/patchset/20260319154937.3619520-1-sascha.bischoff%40arm.com
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/kvm/vgic/vgic-v5.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/arch/arm64/kvm/vgic/vgic-v5.c b/arch/arm64/kvm/vgic/vgic-v5.c
index 2b6cd5c3f9c2f..119d7d01d0e77 100644
--- a/arch/arm64/kvm/vgic/vgic-v5.c
+++ b/arch/arm64/kvm/vgic/vgic-v5.c
@@ -172,6 +172,16 @@ int vgic_v5_finalize_ppi_state(struct kvm *kvm)
 	if (!vgic_is_v5(kvm))
 		return 0;
 
+	guard(mutex)(&kvm->arch.config_lock);
+
+	/*
+	 * If SW_PPI has been advertised, then we know we already
+	 * initialised the whole thing, and we can return early. Yes,
+	 * this is pretty hackish as far as state tracking goes...
+	 */
+	if (test_bit(GICV5_ARCH_PPI_SW_PPI, kvm->arch.vgic.gicv5_vm.vgic_ppi_mask))
+		return 0;
+
 	/* The PPI state for all VCPUs should be the same. Pick the first. */
 	vcpu0 = kvm_get_vcpu(kvm, 0);
 
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v2 07/16] KVM: arm64: vgic-v5: Transfer edge pending state to ICH_PPI_PENDRx_EL2
  2026-04-01 10:35 [PATCH v2 00/16] KVM: arm64: First batch of vgic-v5 related fixes Marc Zyngier
                   ` (5 preceding siblings ...)
  2026-04-01 10:36 ` [PATCH v2 06/16] KVM: arm64: vgic-v5: Hold config_lock while finalizing GICv5 PPIs Marc Zyngier
@ 2026-04-01 10:36 ` Marc Zyngier
  2026-04-01 16:24   ` Sascha Bischoff
  2026-04-01 10:36 ` [PATCH v2 08/16] KVM: arm64: vgic-v5: Cast vgic_apr to u32 to avoid undefined behaviours Marc Zyngier
                   ` (9 subsequent siblings)
  16 siblings, 1 reply; 19+ messages in thread
From: Marc Zyngier @ 2026-04-01 10:36 UTC (permalink / raw)
  To: kvmarm, kvm, linux-arm-kernel
  Cc: Joey Gouly, Suzuki K Poulose, Oliver Upton, Zenghui Yu,
	Sascha Bischoff, Mark Brown

While it is perfectly correct to leave the pending state of a level
interrupt as is when queuing it (it is, after all, only driven by
the line), edge pending state must be transfered, as nothing will
lower it.

Reviewed-by: Sascha Bischoff <sascha.bischoff@arm.com>
Fixes: 4d591252bacb2 ("KVM: arm64: gic-v5: Implement PPI interrupt injection")
Link: https://sashiko.dev/#/patchset/20260319154937.3619520-1-sascha.bischoff%40arm.com
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/kvm/vgic/vgic-v5.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kvm/vgic/vgic-v5.c b/arch/arm64/kvm/vgic/vgic-v5.c
index 119d7d01d0e77..422741c86c6a8 100644
--- a/arch/arm64/kvm/vgic/vgic-v5.c
+++ b/arch/arm64/kvm/vgic/vgic-v5.c
@@ -445,8 +445,11 @@ void vgic_v5_flush_ppi_state(struct kvm_vcpu *vcpu)
 
 		irq = vgic_get_vcpu_irq(vcpu, intid);
 
-		scoped_guard(raw_spinlock_irqsave, &irq->irq_lock)
+		scoped_guard(raw_spinlock_irqsave, &irq->irq_lock) {
 			__assign_bit(i, pendr, irq_is_pending(irq));
+			if (irq->config == VGIC_CONFIG_EDGE)
+				irq->pending_latch = false;
+		}
 
 		vgic_put_irq(vcpu->kvm, irq);
 	}
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v2 08/16] KVM: arm64: vgic-v5: Cast vgic_apr to u32 to avoid undefined behaviours
  2026-04-01 10:35 [PATCH v2 00/16] KVM: arm64: First batch of vgic-v5 related fixes Marc Zyngier
                   ` (6 preceding siblings ...)
  2026-04-01 10:36 ` [PATCH v2 07/16] KVM: arm64: vgic-v5: Transfer edge pending state to ICH_PPI_PENDRx_EL2 Marc Zyngier
@ 2026-04-01 10:36 ` Marc Zyngier
  2026-04-01 10:36 ` [PATCH v2 09/16] KVM: arm64: vgic-v5: Make the effective priority mask a strict limit Marc Zyngier
                   ` (8 subsequent siblings)
  16 siblings, 0 replies; 19+ messages in thread
From: Marc Zyngier @ 2026-04-01 10:36 UTC (permalink / raw)
  To: kvmarm, kvm, linux-arm-kernel
  Cc: Joey Gouly, Suzuki K Poulose, Oliver Upton, Zenghui Yu,
	Sascha Bischoff, Mark Brown

Passing a u64 to __builtin_ctz() is odd, and requires some digging to
figure out why this construct is indeed safe as long as the HW is
correct.

But it is much easier to make it clear to the compiler by casting
the u64 into an intermediate u32, and be done with the UD.

Reviewed-by: Sascha Bischoff <sascha.bischoff@arm.com>
Fixes: 933e5288fa971 ("KVM: arm64: gic-v5: Check for pending PPIs")
Link: https://sashiko.dev/#/patchset/20260319154937.3619520-1-sascha.bischoff%40arm.com
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/kvm/vgic/vgic-v5.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/vgic/vgic-v5.c b/arch/arm64/kvm/vgic/vgic-v5.c
index 422741c86c6a8..0f269321ece4b 100644
--- a/arch/arm64/kvm/vgic/vgic-v5.c
+++ b/arch/arm64/kvm/vgic/vgic-v5.c
@@ -212,7 +212,7 @@ int vgic_v5_finalize_ppi_state(struct kvm *kvm)
 static u32 vgic_v5_get_effective_priority_mask(struct kvm_vcpu *vcpu)
 {
 	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
-	u32 highest_ap, priority_mask;
+	u32 highest_ap, priority_mask, apr;
 
 	/*
 	 * If the guest's CPU has not opted to receive interrupts, then the
@@ -227,7 +227,8 @@ static u32 vgic_v5_get_effective_priority_mask(struct kvm_vcpu *vcpu)
 	 * priority. Explicitly use the 32-bit version here as we have 32
 	 * priorities. 32 then means that there are no active priorities.
 	 */
-	highest_ap = cpu_if->vgic_apr ? __builtin_ctz(cpu_if->vgic_apr) : 32;
+	apr = cpu_if->vgic_apr;
+	highest_ap = apr ? __builtin_ctz(apr) : 32;
 
 	/*
 	 * An interrupt is of sufficient priority if it is equal to or
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v2 09/16] KVM: arm64: vgic-v5: Make the effective priority mask a strict limit
  2026-04-01 10:35 [PATCH v2 00/16] KVM: arm64: First batch of vgic-v5 related fixes Marc Zyngier
                   ` (7 preceding siblings ...)
  2026-04-01 10:36 ` [PATCH v2 08/16] KVM: arm64: vgic-v5: Cast vgic_apr to u32 to avoid undefined behaviours Marc Zyngier
@ 2026-04-01 10:36 ` Marc Zyngier
  2026-04-01 10:36 ` [PATCH v2 10/16] KVM: arm64: vgic-v5: Correctly set dist->ready once initialised Marc Zyngier
                   ` (7 subsequent siblings)
  16 siblings, 0 replies; 19+ messages in thread
From: Marc Zyngier @ 2026-04-01 10:36 UTC (permalink / raw)
  To: kvmarm, kvm, linux-arm-kernel
  Cc: Joey Gouly, Suzuki K Poulose, Oliver Upton, Zenghui Yu,
	Sascha Bischoff, Mark Brown

The way the effective priority mask is compared to the priority of
an interrupt to decide whether to wake-up or not, is slightly odd,
and breaks at the limits.

This could result in spurious wake-ups that are undesirable.

Make the computed priority mask comparison a strict inequality, so
that interrupts that have the same priority as the mask are not
signalled.

Fixes: 933e5288fa971 ("KVM: arm64: gic-v5: Check for pending PPIs")
Link: https://sashiko.dev/#/patchset/20260319154937.3619520-1-sascha.bischoff%40arm.com
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/kvm/vgic/vgic-v5.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/kvm/vgic/vgic-v5.c b/arch/arm64/kvm/vgic/vgic-v5.c
index 0f269321ece4b..31040cfb61fc7 100644
--- a/arch/arm64/kvm/vgic/vgic-v5.c
+++ b/arch/arm64/kvm/vgic/vgic-v5.c
@@ -367,7 +367,7 @@ bool vgic_v5_has_pending_ppi(struct kvm_vcpu *vcpu)
 
 		scoped_guard(raw_spinlock_irqsave, &irq->irq_lock)
 			has_pending = (irq->enabled && irq_is_pending(irq) &&
-				       irq->priority <= priority_mask);
+				       irq->priority < priority_mask);
 
 		vgic_put_irq(vcpu->kvm, irq);
 
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v2 10/16] KVM: arm64: vgic-v5: Correctly set dist->ready once initialised
  2026-04-01 10:35 [PATCH v2 00/16] KVM: arm64: First batch of vgic-v5 related fixes Marc Zyngier
                   ` (8 preceding siblings ...)
  2026-04-01 10:36 ` [PATCH v2 09/16] KVM: arm64: vgic-v5: Make the effective priority mask a strict limit Marc Zyngier
@ 2026-04-01 10:36 ` Marc Zyngier
  2026-04-01 10:36 ` [PATCH v2 11/16] KVM: arm64: Kill arch_timer_context::direct field Marc Zyngier
                   ` (6 subsequent siblings)
  16 siblings, 0 replies; 19+ messages in thread
From: Marc Zyngier @ 2026-04-01 10:36 UTC (permalink / raw)
  To: kvmarm, kvm, linux-arm-kernel
  Cc: Joey Gouly, Suzuki K Poulose, Oliver Upton, Zenghui Yu,
	Sascha Bischoff, Mark Brown

kvm_vgic_map_resources() targetting a v5 model results in vgic->dist_ready
never being set. This doesn't result in anything really bad, only
some more heavy locking as we go and re-init something for no good reason.

Rejig the code to correctly set the ready flag in all non-failing
cases.

Reviewed-by: Sascha Bischoff <sascha.bischoff@arm.com>
Fixes: f4d37c7c35769 ("KVM: arm64: gic-v5: Create and initialise vgic_v5")
Link: https://sashiko.dev/#/patchset/20260319154937.3619520-1-sascha.bischoff%40arm.com
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/kvm/vgic/vgic-init.c | 18 +++++++++++-------
 1 file changed, 11 insertions(+), 7 deletions(-)

diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
index fd872079f2a24..ecb0aea180327 100644
--- a/arch/arm64/kvm/vgic/vgic-init.c
+++ b/arch/arm64/kvm/vgic/vgic-init.c
@@ -657,16 +657,20 @@ int kvm_vgic_map_resources(struct kvm *kvm)
 		needs_dist = false;
 	}
 
-	if (ret || !needs_dist)
+	if (ret)
 		goto out;
 
-	dist_base = dist->vgic_dist_base;
-	mutex_unlock(&kvm->arch.config_lock);
+	if (needs_dist) {
+		dist_base = dist->vgic_dist_base;
+		mutex_unlock(&kvm->arch.config_lock);
 
-	ret = vgic_register_dist_iodev(kvm, dist_base, type);
-	if (ret) {
-		kvm_err("Unable to register VGIC dist MMIO regions\n");
-		goto out_slots;
+		ret = vgic_register_dist_iodev(kvm, dist_base, type);
+		if (ret) {
+			kvm_err("Unable to register VGIC dist MMIO regions\n");
+			goto out_slots;
+		}
+	} else {
+		mutex_unlock(&kvm->arch.config_lock);
 	}
 
 	smp_store_release(&dist->ready, true);
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v2 11/16] KVM: arm64: Kill arch_timer_context::direct field
  2026-04-01 10:35 [PATCH v2 00/16] KVM: arm64: First batch of vgic-v5 related fixes Marc Zyngier
                   ` (9 preceding siblings ...)
  2026-04-01 10:36 ` [PATCH v2 10/16] KVM: arm64: vgic-v5: Correctly set dist->ready once initialised Marc Zyngier
@ 2026-04-01 10:36 ` Marc Zyngier
  2026-04-01 10:36 ` [PATCH v2 12/16] KVM: arm64: Remove evaluation of timer state in kvm_cpu_has_pending_timer() Marc Zyngier
                   ` (5 subsequent siblings)
  16 siblings, 0 replies; 19+ messages in thread
From: Marc Zyngier @ 2026-04-01 10:36 UTC (permalink / raw)
  To: kvmarm, kvm, linux-arm-kernel
  Cc: Joey Gouly, Suzuki K Poulose, Oliver Upton, Zenghui Yu,
	Sascha Bischoff, Mark Brown

The newly introduced arch_timer_context::direct field is a bit pointless,
as it is always set on timers that are... err... direct, while
we already have a way to get to that by doing a get_map() operation.

Additionally, this field is:

- only set when get_map() is called

- never cleared

and the single point where it is actually checked doesn't call get_map()
at all.

At this stage, it is probably better to just kill it, and rely on
get_map() to give us the correct information.

Reviewed-by: Sascha Bischoff <sascha.bischoff@arm.com>
Fixes: 9491c63b6cd7b ("KVM: arm64: gic-v5: Enlighten arch timer for GICv5")
Link: https://sashiko.dev/#/patchset/20260319154937.3619520-1-sascha.bischoff%40arm.com
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/kvm/arch_timer.c  | 15 +++++++++------
 include/kvm/arm_arch_timer.h |  3 ---
 2 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/arch/arm64/kvm/arch_timer.c b/arch/arm64/kvm/arch_timer.c
index 67b989671b410..37279f8748695 100644
--- a/arch/arm64/kvm/arch_timer.c
+++ b/arch/arm64/kvm/arch_timer.c
@@ -183,10 +183,6 @@ void get_timer_map(struct kvm_vcpu *vcpu, struct timer_map *map)
 		map->emul_ptimer = vcpu_ptimer(vcpu);
 	}
 
-	map->direct_vtimer->direct = true;
-	if (map->direct_ptimer)
-		map->direct_ptimer->direct = true;
-
 	trace_kvm_get_timer_map(vcpu->vcpu_id, map);
 }
 
@@ -462,8 +458,15 @@ static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level,
 		return;
 
 	/* Skip injecting on GICv5 for directly injected (DVI'd) timers */
-	if (vgic_is_v5(vcpu->kvm) && timer_ctx->direct)
-		return;
+	if (vgic_is_v5(vcpu->kvm)) {
+		struct timer_map map;
+
+		get_timer_map(vcpu, &map);
+
+		if (map.direct_ptimer == timer_ctx ||
+		    map.direct_vtimer == timer_ctx)
+			return;
+	}
 
 	kvm_vgic_inject_irq(vcpu->kvm, vcpu,
 			    timer_irq(timer_ctx),
diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
index a7754e0a2ef41..bf8cc9589bd09 100644
--- a/include/kvm/arm_arch_timer.h
+++ b/include/kvm/arm_arch_timer.h
@@ -76,9 +76,6 @@ struct arch_timer_context {
 
 	/* Duplicated state from arch_timer.c for convenience */
 	u32				host_timer_irq;
-
-	/* Is this a direct timer? */
-	bool				direct;
 };
 
 struct timer_map {
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v2 12/16] KVM: arm64: Remove evaluation of timer state in kvm_cpu_has_pending_timer()
  2026-04-01 10:35 [PATCH v2 00/16] KVM: arm64: First batch of vgic-v5 related fixes Marc Zyngier
                   ` (10 preceding siblings ...)
  2026-04-01 10:36 ` [PATCH v2 11/16] KVM: arm64: Kill arch_timer_context::direct field Marc Zyngier
@ 2026-04-01 10:36 ` Marc Zyngier
  2026-04-01 10:36 ` [PATCH v2 13/16] KVM: arm64: Move GICv5 timer PPI validation into timer_irqs_are_valid() Marc Zyngier
                   ` (4 subsequent siblings)
  16 siblings, 0 replies; 19+ messages in thread
From: Marc Zyngier @ 2026-04-01 10:36 UTC (permalink / raw)
  To: kvmarm, kvm, linux-arm-kernel
  Cc: Joey Gouly, Suzuki K Poulose, Oliver Upton, Zenghui Yu,
	Sascha Bischoff, Mark Brown

The vgic-v5 code added some evaluations of the timers in a helper funtion
(kvm_cpu_has_pending_timer()) that is called to determine whether
the vcpu can wake-up.

But looking at the timer there is wrong:

- we want to see timers that are signalling an interrupt to the
  vcpu, and not just that have a pending interrupt

- we already have kvm_arch_vcpu_runnable() that evaluates the
  state of interrupts

- kvm_cpu_has_pending_timer() really is about WFIT, as the timeout
  does not generate an interrupt, and is therefore distinct from
  the point above

As a consequence, revert these changes and teach vgic_v5_has_pending_ppi()
about checking for pending HW interrupts instead.

Fixes: 9491c63b6cd7b ("KVM: arm64: gic-v5: Enlighten arch timer for GICv5")
Link: https://sashiko.dev/#/patchset/20260319154937.3619520-1-sascha.bischoff%40arm.com
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/kvm/arch_timer.c   | 6 +-----
 arch/arm64/kvm/vgic/vgic-v5.c | 4 ++--
 2 files changed, 3 insertions(+), 7 deletions(-)

diff --git a/arch/arm64/kvm/arch_timer.c b/arch/arm64/kvm/arch_timer.c
index 37279f8748695..6608c47d1f628 100644
--- a/arch/arm64/kvm/arch_timer.c
+++ b/arch/arm64/kvm/arch_timer.c
@@ -402,11 +402,7 @@ static bool kvm_timer_should_fire(struct arch_timer_context *timer_ctx)
 
 int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
 {
-	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
-	struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
-
-	return kvm_timer_should_fire(vtimer) || kvm_timer_should_fire(ptimer) ||
-	       (vcpu_has_wfit_active(vcpu) && wfit_delay_ns(vcpu) == 0);
+	return vcpu_has_wfit_active(vcpu) && wfit_delay_ns(vcpu) == 0;
 }
 
 /*
diff --git a/arch/arm64/kvm/vgic/vgic-v5.c b/arch/arm64/kvm/vgic/vgic-v5.c
index 31040cfb61fc7..8680a8354db9d 100644
--- a/arch/arm64/kvm/vgic/vgic-v5.c
+++ b/arch/arm64/kvm/vgic/vgic-v5.c
@@ -366,8 +366,8 @@ bool vgic_v5_has_pending_ppi(struct kvm_vcpu *vcpu)
 		irq = vgic_get_vcpu_irq(vcpu, intid);
 
 		scoped_guard(raw_spinlock_irqsave, &irq->irq_lock)
-			has_pending = (irq->enabled && irq_is_pending(irq) &&
-				       irq->priority < priority_mask);
+			if (irq->enabled && irq->priority < priority_mask)
+				has_pending = irq->hw ? vgic_get_phys_line_level(irq) : irq_is_pending(irq);
 
 		vgic_put_irq(vcpu->kvm, irq);
 
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v2 13/16] KVM: arm64: Move GICv5 timer PPI validation into timer_irqs_are_valid()
  2026-04-01 10:35 [PATCH v2 00/16] KVM: arm64: First batch of vgic-v5 related fixes Marc Zyngier
                   ` (11 preceding siblings ...)
  2026-04-01 10:36 ` [PATCH v2 12/16] KVM: arm64: Remove evaluation of timer state in kvm_cpu_has_pending_timer() Marc Zyngier
@ 2026-04-01 10:36 ` Marc Zyngier
  2026-04-01 10:36 ` [PATCH v2 14/16] KVM: arm64: Correctly plumb ID_AA64PFR2_EL1 into pkvm idreg handling Marc Zyngier
                   ` (3 subsequent siblings)
  16 siblings, 0 replies; 19+ messages in thread
From: Marc Zyngier @ 2026-04-01 10:36 UTC (permalink / raw)
  To: kvmarm, kvm, linux-arm-kernel
  Cc: Joey Gouly, Suzuki K Poulose, Oliver Upton, Zenghui Yu,
	Sascha Bischoff, Mark Brown

Userspace can set the timer PPI numbers way before a GIC has been
created, leading to odd behaviours on GICv5 as we'd accept non
architectural PPI numbers.

Move the v5 check into timer_irqs_are_valid(), which aligns the
behaviour with the pre-v5 GICs, and is also guaranteed to run
only once a GIC has been configured.

Reviewed-by: Sascha Bischoff <sascha.bischoff@arm.com>
Fixes: 9491c63b6cd7b ("KVM: arm64: gic-v5: Enlighten arch timer for GICv5")
Link: https://sashiko.dev/#/patchset/20260319154937.3619520-1-sascha.bischoff%40arm.com
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/kvm/arch_timer.c | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/arch/arm64/kvm/arch_timer.c b/arch/arm64/kvm/arch_timer.c
index 6608c47d1f628..cbea4d9ee9552 100644
--- a/arch/arm64/kvm/arch_timer.c
+++ b/arch/arm64/kvm/arch_timer.c
@@ -1543,6 +1543,10 @@ static bool timer_irqs_are_valid(struct kvm_vcpu *vcpu)
 		if (kvm_vgic_set_owner(vcpu, irq, ctx))
 			break;
 
+		/* With GICv5, the default PPI is what you get -- nothing else */
+		if (vgic_is_v5(vcpu->kvm) && irq != get_vgic_ppi(vcpu->kvm, default_ppi[i]))
+			break;
+
 		/*
 		 * We know by construction that we only have PPIs, so all values
 		 * are less than 32 for non-GICv5 VGICs. On GICv5, they are
@@ -1678,13 +1682,6 @@ int kvm_arm_timer_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
 		return -ENXIO;
 	}
 
-	/*
-	 * The PPIs for the Arch Timers are architecturally defined for
-	 * GICv5. Reject anything that changes them from the specified value.
-	 */
-	if (vgic_is_v5(vcpu->kvm) && vcpu->kvm->arch.timer_data.ppi[idx] != irq)
-		return -EINVAL;
-
 	/*
 	 * We cannot validate the IRQ unicity before we run, so take it at
 	 * face value. The verdict will be given on first vcpu run, for each
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v2 14/16] KVM: arm64: Correctly plumb ID_AA64PFR2_EL1 into pkvm idreg handling
  2026-04-01 10:35 [PATCH v2 00/16] KVM: arm64: First batch of vgic-v5 related fixes Marc Zyngier
                   ` (12 preceding siblings ...)
  2026-04-01 10:36 ` [PATCH v2 13/16] KVM: arm64: Move GICv5 timer PPI validation into timer_irqs_are_valid() Marc Zyngier
@ 2026-04-01 10:36 ` Marc Zyngier
  2026-04-01 10:36 ` [PATCH v2 15/16] KVM: arm64: Don't advertises GICv3 in ID_PFR1_EL1 if AArch32 isn't supported Marc Zyngier
                   ` (2 subsequent siblings)
  16 siblings, 0 replies; 19+ messages in thread
From: Marc Zyngier @ 2026-04-01 10:36 UTC (permalink / raw)
  To: kvmarm, kvm, linux-arm-kernel
  Cc: Joey Gouly, Suzuki K Poulose, Oliver Upton, Zenghui Yu,
	Sascha Bischoff, Mark Brown

While we now compute ID_AA64PFR2_EL1 to a glorious 0, we never use
that data and instead return the 0 that corresponds to an allocated
idreg. Not a big deal, but we might as well be consistent.

Reviewed-by: Sascha Bischoff <sascha.bischoff@arm.com>
Fixes: 5aefaf11f9af5 ("KVM: arm64: gic: Hide GICv5 for protected guests")
Link: https://sashiko.dev/#/patchset/20260319154937.3619520-1-sascha.bischoff%40arm.com
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/kvm/hyp/nvhe/sys_regs.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/kvm/hyp/nvhe/sys_regs.c b/arch/arm64/kvm/hyp/nvhe/sys_regs.c
index b40fd01ebf329..be6f420388a14 100644
--- a/arch/arm64/kvm/hyp/nvhe/sys_regs.c
+++ b/arch/arm64/kvm/hyp/nvhe/sys_regs.c
@@ -439,7 +439,7 @@ static const struct sys_reg_desc pvm_sys_reg_descs[] = {
 	/* CRm=4 */
 	AARCH64(SYS_ID_AA64PFR0_EL1),
 	AARCH64(SYS_ID_AA64PFR1_EL1),
-	ID_UNALLOCATED(4,2),
+	AARCH64(SYS_ID_AA64PFR2_EL1),
 	ID_UNALLOCATED(4,3),
 	AARCH64(SYS_ID_AA64ZFR0_EL1),
 	ID_UNALLOCATED(4,5),
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v2 15/16] KVM: arm64: Don't advertises GICv3 in ID_PFR1_EL1 if AArch32 isn't supported
  2026-04-01 10:35 [PATCH v2 00/16] KVM: arm64: First batch of vgic-v5 related fixes Marc Zyngier
                   ` (13 preceding siblings ...)
  2026-04-01 10:36 ` [PATCH v2 14/16] KVM: arm64: Correctly plumb ID_AA64PFR2_EL1 into pkvm idreg handling Marc Zyngier
@ 2026-04-01 10:36 ` Marc Zyngier
  2026-04-01 10:36 ` [PATCH v2 16/16] KVM: arm64: set_id_regs: Allow GICv3 support to be set at runtime Marc Zyngier
  2026-04-01 15:30 ` [PATCH v2 00/16] KVM: arm64: First batch of vgic-v5 related fixes Marc Zyngier
  16 siblings, 0 replies; 19+ messages in thread
From: Marc Zyngier @ 2026-04-01 10:36 UTC (permalink / raw)
  To: kvmarm, kvm, linux-arm-kernel
  Cc: Joey Gouly, Suzuki K Poulose, Oliver Upton, Zenghui Yu,
	Sascha Bischoff, Mark Brown

Although the AArch32 ID regs are architecturally UNKNOWN when AArch32
isn't supported at any EL, KVM makes a point in making them RAZ.

Therefore, advertising GICv3 in ID_PFR1_EL1 must be gated on AArch32
being supported at least at EL0.

Reviewed-by: Sascha Bischoff <sascha.bischoff@arm.com>
Fixes: a258a383b9177 ("KVM: arm64: gic-v5: Sanitize ID_AA64PFR2_EL1.GCIE")
Reported-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/kvm/vgic/vgic-init.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
index ecb0aea180327..5c684ecf79e66 100644
--- a/arch/arm64/kvm/vgic/vgic-init.c
+++ b/arch/arm64/kvm/vgic/vgic-init.c
@@ -700,7 +700,8 @@ void kvm_vgic_finalize_idregs(struct kvm *kvm)
 		break;
 	case KVM_DEV_TYPE_ARM_VGIC_V3:
 		aa64pfr0 |= SYS_FIELD_PREP_ENUM(ID_AA64PFR0_EL1, GIC, IMP);
-		pfr1 |= SYS_FIELD_PREP_ENUM(ID_PFR1_EL1, GIC, GICv3);
+		if (kvm_supports_32bit_el0())
+			pfr1 |= SYS_FIELD_PREP_ENUM(ID_PFR1_EL1, GIC, GICv3);
 		break;
 	case KVM_DEV_TYPE_ARM_VGIC_V5:
 		aa64pfr2 |= SYS_FIELD_PREP_ENUM(ID_AA64PFR2_EL1, GCIE, IMP);
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v2 16/16] KVM: arm64: set_id_regs: Allow GICv3 support to be set at runtime
  2026-04-01 10:35 [PATCH v2 00/16] KVM: arm64: First batch of vgic-v5 related fixes Marc Zyngier
                   ` (14 preceding siblings ...)
  2026-04-01 10:36 ` [PATCH v2 15/16] KVM: arm64: Don't advertises GICv3 in ID_PFR1_EL1 if AArch32 isn't supported Marc Zyngier
@ 2026-04-01 10:36 ` Marc Zyngier
  2026-04-01 15:30 ` [PATCH v2 00/16] KVM: arm64: First batch of vgic-v5 related fixes Marc Zyngier
  16 siblings, 0 replies; 19+ messages in thread
From: Marc Zyngier @ 2026-04-01 10:36 UTC (permalink / raw)
  To: kvmarm, kvm, linux-arm-kernel
  Cc: Joey Gouly, Suzuki K Poulose, Oliver Upton, Zenghui Yu,
	Sascha Bischoff, Mark Brown

set_id_regs creates a GIC3 guest when possible, and then proceeds
to write the ID registers as if they were not affected by the presence
of a GIC. As it turns out, ID_AA64PFR1_EL1 is the proof of the
contrary.

KVM now makes a point in exposing the GIC support to the guest,
no matter what userspace says (userspace such as QEMU is known to
write silly things at times).

Accommodate for this level of nonsense by teaching set_id_regs about
fields that are mutable, and only compare registers that have been
re-sanitised first.

Reported-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 .../testing/selftests/kvm/arm64/set_id_regs.c | 52 ++++++++++++++++---
 1 file changed, 45 insertions(+), 7 deletions(-)

diff --git a/tools/testing/selftests/kvm/arm64/set_id_regs.c b/tools/testing/selftests/kvm/arm64/set_id_regs.c
index 73de5be58bab0..7899d557c70b6 100644
--- a/tools/testing/selftests/kvm/arm64/set_id_regs.c
+++ b/tools/testing/selftests/kvm/arm64/set_id_regs.c
@@ -37,6 +37,9 @@ struct reg_ftr_bits {
 	 * For FTR_LOWER_SAFE, safe_val is used as the minimal safe value.
 	 */
 	int64_t safe_val;
+
+	/* Allowed to be changed by the host after run */
+	bool mutable;
 };
 
 struct test_feature_reg {
@@ -44,7 +47,7 @@ struct test_feature_reg {
 	const struct reg_ftr_bits *ftr_bits;
 };
 
-#define __REG_FTR_BITS(NAME, SIGNED, TYPE, SHIFT, MASK, SAFE_VAL)	\
+#define __REG_FTR_BITS(NAME, SIGNED, TYPE, SHIFT, MASK, SAFE_VAL, MUT)	\
 	{								\
 		.name = #NAME,						\
 		.sign = SIGNED,						\
@@ -52,15 +55,20 @@ struct test_feature_reg {
 		.shift = SHIFT,						\
 		.mask = MASK,						\
 		.safe_val = SAFE_VAL,					\
+		.mutable = MUT,						\
 	}
 
 #define REG_FTR_BITS(type, reg, field, safe_val) \
 	__REG_FTR_BITS(reg##_##field, FTR_UNSIGNED, type, reg##_##field##_SHIFT, \
-		       reg##_##field##_MASK, safe_val)
+		       reg##_##field##_MASK, safe_val, false)
+
+#define REG_FTR_BITS_MUTABLE(type, reg, field, safe_val) \
+	__REG_FTR_BITS(reg##_##field, FTR_UNSIGNED, type, reg##_##field##_SHIFT, \
+		       reg##_##field##_MASK, safe_val, true)
 
 #define S_REG_FTR_BITS(type, reg, field, safe_val) \
 	__REG_FTR_BITS(reg##_##field, FTR_SIGNED, type, reg##_##field##_SHIFT, \
-		       reg##_##field##_MASK, safe_val)
+		       reg##_##field##_MASK, safe_val, false)
 
 #define REG_FTR_END					\
 	{						\
@@ -134,7 +142,8 @@ static const struct reg_ftr_bits ftr_id_aa64pfr0_el1[] = {
 	REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64PFR0_EL1, CSV2, 0),
 	REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64PFR0_EL1, DIT, 0),
 	REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64PFR0_EL1, SEL2, 0),
-	REG_FTR_BITS(FTR_EXACT, ID_AA64PFR0_EL1, GIC, 0),
+	/* GICv3 support will be forced at run time if available */
+	REG_FTR_BITS_MUTABLE(FTR_EXACT, ID_AA64PFR0_EL1, GIC, 0),
 	REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64PFR0_EL1, EL3, 1),
 	REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64PFR0_EL1, EL2, 1),
 	REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64PFR0_EL1, EL1, 1),
@@ -634,12 +643,38 @@ static void test_user_set_mte_reg(struct kvm_vcpu *vcpu)
 		ksft_test_result_pass("ID_AA64PFR1_EL1.MTE_frac no longer 0xF\n");
 }
 
+static uint64_t reset_mutable_bits(uint32_t id, uint64_t val)
+{
+	struct test_feature_reg *reg = NULL;
+
+	for (int i = 0; i < ARRAY_SIZE(test_regs); i++) {
+		if (test_regs[i].reg == id) {
+			reg = &test_regs[i];
+			break;
+		}
+	}
+
+	if (!reg)
+		return val;
+
+	for (const struct reg_ftr_bits *bits = reg->ftr_bits; bits->type != FTR_END; bits++) {
+		if (bits->mutable) {
+			val &= ~bits->mask;
+			val |= bits->safe_val << bits->shift;
+		}
+	}
+
+	return val;
+}
+
 static void test_guest_reg_read(struct kvm_vcpu *vcpu)
 {
 	bool done = false;
 	struct ucall uc;
 
 	while (!done) {
+		uint64_t val;
+
 		vcpu_run(vcpu);
 
 		switch (get_ucall(vcpu, &uc)) {
@@ -647,9 +682,11 @@ static void test_guest_reg_read(struct kvm_vcpu *vcpu)
 			REPORT_GUEST_ASSERT(uc);
 			break;
 		case UCALL_SYNC:
+			val = test_reg_vals[encoding_to_range_idx(uc.args[2])];
+			val = reset_mutable_bits(uc.args[2], val);
+
 			/* Make sure the written values are seen by guest */
-			TEST_ASSERT_EQ(test_reg_vals[encoding_to_range_idx(uc.args[2])],
-				       uc.args[3]);
+			TEST_ASSERT_EQ(val, reset_mutable_bits(uc.args[2], uc.args[3]));
 			break;
 		case UCALL_DONE:
 			done = true;
@@ -740,7 +777,8 @@ static void test_assert_id_reg_unchanged(struct kvm_vcpu *vcpu, uint32_t encodin
 	uint64_t observed;
 
 	observed = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(encoding));
-	TEST_ASSERT_EQ(test_reg_vals[idx], observed);
+	TEST_ASSERT_EQ(reset_mutable_bits(encoding, test_reg_vals[idx]),
+		       reset_mutable_bits(encoding, observed));
 }
 
 static void test_reset_preserves_id_regs(struct kvm_vcpu *vcpu)
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 00/16] KVM: arm64: First batch of vgic-v5 related fixes
  2026-04-01 10:35 [PATCH v2 00/16] KVM: arm64: First batch of vgic-v5 related fixes Marc Zyngier
                   ` (15 preceding siblings ...)
  2026-04-01 10:36 ` [PATCH v2 16/16] KVM: arm64: set_id_regs: Allow GICv3 support to be set at runtime Marc Zyngier
@ 2026-04-01 15:30 ` Marc Zyngier
  16 siblings, 0 replies; 19+ messages in thread
From: Marc Zyngier @ 2026-04-01 15:30 UTC (permalink / raw)
  To: kvmarm, kvm, linux-arm-kernel, Marc Zyngier
  Cc: Joey Gouly, Suzuki K Poulose, Oliver Upton, Zenghui Yu,
	Sascha Bischoff, Mark Brown

On Wed, 01 Apr 2026 11:35:55 +0100, Marc Zyngier wrote:
> This is the second revision of this series attempting to fix a number
> of issues reported on the vgic-v5 PPI series.
> 
> * From v1 [1]:
> 
>   - Partially reverted the effective priority mask fix, as Sascha
>     pointed out the crucial difference in the way GICv5 manages the
>     PCR compared to GICv[234]'s PMR.
> 
> [...]

Applied to next, thanks!

[01/16] KVM: arm64: vgic: Don't reset cpuif/redist addresses at finalize time
        commit: ecc7f02499544ae879716be837af78260a6a10f7
[02/16] KVM: arm64: Don't skip per-vcpu NV initialisation
        commit: d82d09d5ba4be0b5eb053b2ba2bc0e82c49cf2c8
[03/16] arm64: Fix field references for ICH_PPI_DVIR[01]_EL2
        commit: 77acae60be60adddf33e4c7e9cf73291f64fb9e8
[04/16] KVM: arm64: Fix writeable mask for ID_AA64PFR2_EL1
        commit: 76efe94b1c5cc9b5fac7c5c1096d03f1596c7267
[05/16] KVM: arm64: Account for RESx bits in __compute_fgt()
        commit: d70d4323dd9636e35696639f6b4c2b2735291516
[06/16] KVM: arm64: vgic-v5: Hold config_lock while finalizing GICv5 PPIs
        commit: e63d0a32e7368f3eb935755db87add1bf000ea90
[07/16] KVM: arm64: vgic-v5: Transfer edge pending state to ICH_PPI_PENDRx_EL2
        commit: 170a77b4185a87cc7e02e404d22b9bf3f9923884
[08/16] KVM: arm64: vgic-v5: Cast vgic_apr to u32 to avoid undefined behaviours
        commit: 42d7eac8291d2724b3897141ab2f226c69b7923e
[09/16] KVM: arm64: vgic-v5: Make the effective priority mask a strict limit
        commit: a4a645584793dbbb4e5a1a876800654a8883326e
[10/16] KVM: arm64: vgic-v5: Correctly set dist->ready once initialised
        commit: 848fa8373a53b0e5d871560743e13278da56fabc
[11/16] KVM: arm64: Kill arch_timer_context::direct field
        commit: 8fe30434a81d36715ab83fdb4a5e6c967d2e3ecf
[12/16] KVM: arm64: Remove evaluation of timer state in kvm_cpu_has_pending_timer()
        commit: fbcbf259d97d340376a176de20bdc04687356949
[13/16] KVM: arm64: Move GICv5 timer PPI validation into timer_irqs_are_valid()
        commit: 06c85b58e0b13e67f4e56cbba346201bfe95ad00
[14/16] KVM: arm64: Correctly plumb ID_AA64PFR2_EL1 into pkvm idreg handling
        commit: be46a408f376df31762e8a9914dc6d082755e686
[15/16] KVM: arm64: Don't advertises GICv3 in ID_PFR1_EL1 if AArch32 isn't supported
        commit: f4626281c6bb563ef5ad9d3a59a1449b45a3dc30
[16/16] KVM: arm64: set_id_regs: Allow GICv3 support to be set at runtime
        commit: b3265a1b2bd00335308f27477cecb7702f4bb615

Cheers,

	M.
-- 
Without deviation from the norm, progress is not possible.




^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 07/16] KVM: arm64: vgic-v5: Transfer edge pending state to ICH_PPI_PENDRx_EL2
  2026-04-01 10:36 ` [PATCH v2 07/16] KVM: arm64: vgic-v5: Transfer edge pending state to ICH_PPI_PENDRx_EL2 Marc Zyngier
@ 2026-04-01 16:24   ` Sascha Bischoff
  0 siblings, 0 replies; 19+ messages in thread
From: Sascha Bischoff @ 2026-04-01 16:24 UTC (permalink / raw)
  To: maz@kernel.org, kvmarm@lists.linux.dev, kvm@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org
  Cc: Joey Gouly, yuzenghui@huawei.com, Suzuki Poulose,
	oupton@kernel.org, broonie@kernel.org, nd

On Wed, 2026-04-01 at 11:36 +0100, Marc Zyngier wrote:
> While it is perfectly correct to leave the pending state of a level
> interrupt as is when queuing it (it is, after all, only driven by
> the line), edge pending state must be transfered, as nothing will
> lower it.
> 
> Reviewed-by: Sascha Bischoff <sascha.bischoff@arm.com>
> Fixes: 4d591252bacb2 ("KVM: arm64: gic-v5: Implement PPI interrupt
> injection")
> Link:
> https://sashiko.dev/#/patchset/20260319154937.3619520-1-sascha.bischoff%40arm.com
> Signed-off-by: Marc Zyngier <maz@kernel.org>
> ---
>  arch/arm64/kvm/vgic/vgic-v5.c | 5 ++++-
>  1 file changed, 4 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm64/kvm/vgic/vgic-v5.c
> b/arch/arm64/kvm/vgic/vgic-v5.c
> index 119d7d01d0e77..422741c86c6a8 100644
> --- a/arch/arm64/kvm/vgic/vgic-v5.c
> +++ b/arch/arm64/kvm/vgic/vgic-v5.c
> @@ -445,8 +445,11 @@ void vgic_v5_flush_ppi_state(struct kvm_vcpu
> *vcpu)
>  
>  		irq = vgic_get_vcpu_irq(vcpu, intid);
>  
> -		scoped_guard(raw_spinlock_irqsave, &irq->irq_lock)
> +		scoped_guard(raw_spinlock_irqsave, &irq->irq_lock) {
>  			__assign_bit(i, pendr, irq_is_pending(irq));
> +			if (irq->config == VGIC_CONFIG_EDGE)
> +				irq->pending_latch = false;
> +		}
>  
>  		vgic_put_irq(vcpu->kvm, irq);
>  	}

With this change we end up losing edges (so, actually have the opposite
problem!). I'd missed this in the previous iteration, but have just
uncovered it during testing. It was hidden by clearing TWI when we have
a single task running, and hence wasn't picked up with the GICv5 PPI
selftest until I stressed the test system more heavily.

In vgic_v5_fold_ppi_state() we detect changes in the active or pending
state on guest exit. If there is no change, i.e., the guest hasn't
consumed the edge yet, we don't end up syncing it back to the
corresponding struct vgic_irq, and lose it forever.

The detection of changes on fold was introduced in order to reduce the
overhead back when we were syncing the state for all 128 potential
PPIs. Now that we've reduced the set to the 64 architected PPIs, and
actually only use a subset of those (SW_PPI, PMUIRQ, timers - up to 4
in total currently) I'm not sure that makes sense anymore.

I think it instead makes sense to iterate over the mask of PPIs exposed
to the guest and sync only those back to KVM's vgic_irq state. This
means that we first of all avoid losing any edges, and secondly are
able to drop the extra pending state tracking.

I've just posted a patch based on this series which addresses the issue
here: 

https://lore.kernel.org/linux-arm-kernel/20260401162152.932243-1-sascha.bischoff@arm.com

Thanks,
Sascha

^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2026-04-01 16:26 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-01 10:35 [PATCH v2 00/16] KVM: arm64: First batch of vgic-v5 related fixes Marc Zyngier
2026-04-01 10:35 ` [PATCH v2 01/16] KVM: arm64: vgic: Don't reset cpuif/redist addresses at finalize time Marc Zyngier
2026-04-01 10:35 ` [PATCH v2 02/16] KVM: arm64: Don't skip per-vcpu NV initialisation Marc Zyngier
2026-04-01 10:35 ` [PATCH v2 03/16] arm64: Fix field references for ICH_PPI_DVIR[01]_EL2 Marc Zyngier
2026-04-01 10:35 ` [PATCH v2 04/16] KVM: arm64: Fix writeable mask for ID_AA64PFR2_EL1 Marc Zyngier
2026-04-01 10:36 ` [PATCH v2 05/16] KVM: arm64: Account for RESx bits in __compute_fgt() Marc Zyngier
2026-04-01 10:36 ` [PATCH v2 06/16] KVM: arm64: vgic-v5: Hold config_lock while finalizing GICv5 PPIs Marc Zyngier
2026-04-01 10:36 ` [PATCH v2 07/16] KVM: arm64: vgic-v5: Transfer edge pending state to ICH_PPI_PENDRx_EL2 Marc Zyngier
2026-04-01 16:24   ` Sascha Bischoff
2026-04-01 10:36 ` [PATCH v2 08/16] KVM: arm64: vgic-v5: Cast vgic_apr to u32 to avoid undefined behaviours Marc Zyngier
2026-04-01 10:36 ` [PATCH v2 09/16] KVM: arm64: vgic-v5: Make the effective priority mask a strict limit Marc Zyngier
2026-04-01 10:36 ` [PATCH v2 10/16] KVM: arm64: vgic-v5: Correctly set dist->ready once initialised Marc Zyngier
2026-04-01 10:36 ` [PATCH v2 11/16] KVM: arm64: Kill arch_timer_context::direct field Marc Zyngier
2026-04-01 10:36 ` [PATCH v2 12/16] KVM: arm64: Remove evaluation of timer state in kvm_cpu_has_pending_timer() Marc Zyngier
2026-04-01 10:36 ` [PATCH v2 13/16] KVM: arm64: Move GICv5 timer PPI validation into timer_irqs_are_valid() Marc Zyngier
2026-04-01 10:36 ` [PATCH v2 14/16] KVM: arm64: Correctly plumb ID_AA64PFR2_EL1 into pkvm idreg handling Marc Zyngier
2026-04-01 10:36 ` [PATCH v2 15/16] KVM: arm64: Don't advertises GICv3 in ID_PFR1_EL1 if AArch32 isn't supported Marc Zyngier
2026-04-01 10:36 ` [PATCH v2 16/16] KVM: arm64: set_id_regs: Allow GICv3 support to be set at runtime Marc Zyngier
2026-04-01 15:30 ` [PATCH v2 00/16] KVM: arm64: First batch of vgic-v5 related fixes Marc Zyngier

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox