linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/12] KVM: arm64: Handle the lack of GICv3 exposed to a guest
@ 2024-08-20 10:03 Marc Zyngier
  2024-08-20 10:03 ` [PATCH 01/12] KVM: arm64: Make ICC_*SGI*_EL1 undef in the absence of a vGICv3 Marc Zyngier
                   ` (11 more replies)
  0 siblings, 12 replies; 26+ messages in thread
From: Marc Zyngier @ 2024-08-20 10:03 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel, kvm
  Cc: James Morse, Suzuki K Poulose, Oliver Upton, Zenghui Yu,
	Alexander Potapenko

It recently appeared that, when running on a GICv3-equipped platform
(which is what non-ancient arm64 HW has), *not* configuring a GICv3
for the guest could result in less than desirable outcomes.

We have multiple issues to fix:

- for registers that *always* trap (the SGI registers) or that *may*
  trap (the SRE register), we need to check whether a GICv3 has been
  instantiated before acting upon the trap.

- for registers that only conditionally trap, we must actively trap
  them even in the absence of a GICv3 being instantiated, and handle
  those traps accordingly.

- finally, ID registers must reflect the absence of a GICv3, so that
  we are consistent.

This series goes through all these requirements. The main complexity
here is to apply a GICv3 configuration on the host in the absence of a
GICv3 in the guest. This is pretty hackish, but I don't have a much
better solution so far.

As part of making wider use of of the trap bits, we fully define the
trap routing as per the architecture, something that we eventually
need for NV anyway.

Note that patch #1 is a candidate for immediate merge in 6.11 as a
fix, to be backported to all stable versions. We can live without the
rest.

Finally, I have added two additional changes:

- a file-wide cleanup of sys_regs.c, unifying the way we inject an
  UNDEF from the trap handling array

- a selftest that checks for the implemented trapping behaviour (yes,
  I actually wrote a test -- hated every minute of it).

Note that the effects of this series when a GICv2 is configured on a
GICv3 host capable of emulation are imperfect: For some of the
registers, the guest may take a system register trap at EL1 (EC=0x18),
and there is nothing that KVM can do about it (this is a consequence
of ICC_SRE_EL1.SRE being 0, which GICv2 requires). But at least that's
a guest problem, not the host's.

PAtches on top of v6.11-rc4, tested on the usual lot of terrible HW:
Synquacer, TX1 and M1.

Marc Zyngier (12):
  KVM: arm64: Make ICC_*SGI*_EL1 undef in the absence of a vGICv3
  KVM: arm64: Move GICv3 trap configuration to kvm_calculate_traps()
  KVM: arm64: Force SRE traps when SRE access is not enabled
  KVM: arm64: Force GICv3 traps activa when no irqchip is configured on
    VHE
  KVM: arm64: Add helper for last ditch idreg adjustments
  KVM: arm64: Zero ID_AA64PFR0_EL1.GIC when no GICv3 is presented to the
    guest
  KVM: arm64: Add ICH_HCR_EL2 to the vcpu state
  KVM: arm64: Add trap routing information for ICH_HCR_EL2
  KVM: arm64: Honor guest requested traps in GICv3 emulation
  KVM: arm64: Make most GICv3 accesses UNDEF if they trap
  KVM: arm64: Unify UNDEF injection helpers
  KVM: arm64: Add selftest checking how the absence of GICv3 is handled

 arch/arm64/include/asm/kvm_host.h             |   2 +
 arch/arm64/kvm/arm.c                          |  10 +-
 arch/arm64/kvm/emulate-nested.c               |  77 +++++-
 arch/arm64/kvm/hyp/vgic-v3-sr.c               |  97 ++++++-
 arch/arm64/kvm/nested.c                       |  15 +-
 arch/arm64/kvm/sys_regs.c                     | 236 +++++++++++-------
 arch/arm64/kvm/sys_regs.h                     |   9 +
 arch/arm64/kvm/vgic/vgic-v3.c                 |  12 +
 arch/arm64/kvm/vgic/vgic.c                    |  14 +-
 arch/arm64/kvm/vgic/vgic.h                    |   9 +
 tools/testing/selftests/kvm/Makefile          |   1 +
 .../selftests/kvm/aarch64/no-vgic-v3.c        | 170 +++++++++++++
 12 files changed, 526 insertions(+), 126 deletions(-)
 create mode 100644 tools/testing/selftests/kvm/aarch64/no-vgic-v3.c

-- 
2.39.2



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

* [PATCH 01/12] KVM: arm64: Make ICC_*SGI*_EL1 undef in the absence of a vGICv3
  2024-08-20 10:03 [PATCH 00/12] KVM: arm64: Handle the lack of GICv3 exposed to a guest Marc Zyngier
@ 2024-08-20 10:03 ` Marc Zyngier
  2024-08-20 21:46   ` Oliver Upton
  2024-08-22  8:15   ` (subset) " Oliver Upton
  2024-08-20 10:03 ` [PATCH 02/12] KVM: arm64: Move GICv3 trap configuration to kvm_calculate_traps() Marc Zyngier
                   ` (10 subsequent siblings)
  11 siblings, 2 replies; 26+ messages in thread
From: Marc Zyngier @ 2024-08-20 10:03 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel, kvm
  Cc: James Morse, Suzuki K Poulose, Oliver Upton, Zenghui Yu,
	Alexander Potapenko, stable

On a system with a GICv3, if a guest hasn't been configured with
GICv3 and that the host is not capable of GICv2 emulation,
a write to any of the ICC_*SGI*_EL1 registers is trapped to EL2.

We therefore try to emulate the SGI access, only to hit a NULL
pointer as no private interrupt is allocated (no GIC, remember?).

The obvious fix is to give the guest what it deserves, in the
shape of a UNDEF exception.

Reported-by: Alexander Potapenko <glider@google.com>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Cc: stable@vger.kernel.org
---
 arch/arm64/kvm/sys_regs.c  | 6 ++++++
 arch/arm64/kvm/vgic/vgic.h | 7 +++++++
 2 files changed, 13 insertions(+)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index c90324060436..31e49da867ff 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -33,6 +33,7 @@
 #include <trace/events/kvm.h>
 
 #include "sys_regs.h"
+#include "vgic/vgic.h"
 
 #include "trace.h"
 
@@ -435,6 +436,11 @@ static bool access_gic_sgi(struct kvm_vcpu *vcpu,
 {
 	bool g1;
 
+	if (!kvm_has_gicv3(vcpu->kvm)) {
+		kvm_inject_undefined(vcpu);
+		return false;
+	}
+
 	if (!p->is_write)
 		return read_from_write_only(vcpu, p, r);
 
diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h
index ba8f790431bd..8532bfe3fed4 100644
--- a/arch/arm64/kvm/vgic/vgic.h
+++ b/arch/arm64/kvm/vgic/vgic.h
@@ -346,4 +346,11 @@ void vgic_v4_configure_vsgis(struct kvm *kvm);
 void vgic_v4_get_vlpi_state(struct vgic_irq *irq, bool *val);
 int vgic_v4_request_vpe_irq(struct kvm_vcpu *vcpu, int irq);
 
+static inline bool kvm_has_gicv3(struct kvm *kvm)
+{
+	return (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif) &&
+		irqchip_in_kernel(kvm) &&
+		kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3);
+}
+
 #endif
-- 
2.39.2



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

* [PATCH 02/12] KVM: arm64: Move GICv3 trap configuration to kvm_calculate_traps()
  2024-08-20 10:03 [PATCH 00/12] KVM: arm64: Handle the lack of GICv3 exposed to a guest Marc Zyngier
  2024-08-20 10:03 ` [PATCH 01/12] KVM: arm64: Make ICC_*SGI*_EL1 undef in the absence of a vGICv3 Marc Zyngier
@ 2024-08-20 10:03 ` Marc Zyngier
  2024-08-20 10:03 ` [PATCH 03/12] KVM: arm64: Force SRE traps when SRE access is not enabled Marc Zyngier
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 26+ messages in thread
From: Marc Zyngier @ 2024-08-20 10:03 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel, kvm
  Cc: James Morse, Suzuki K Poulose, Oliver Upton, Zenghui Yu,
	Alexander Potapenko

Follow the pattern introduced with vcpu_set_hcr(), and introduce
vcpu_set_ich_hcr(), which configures the GICv3 traps at the same
point.

This will allow future changes to introduce trap configuration on
a per-VM basis.

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/kvm/sys_regs.c     | 1 +
 arch/arm64/kvm/vgic/vgic-v3.c | 9 +++++++++
 arch/arm64/kvm/vgic/vgic.h    | 2 ++
 3 files changed, 12 insertions(+)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 31e49da867ff..257c8da23a4e 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -4551,6 +4551,7 @@ void kvm_calculate_traps(struct kvm_vcpu *vcpu)
 
 	mutex_lock(&kvm->arch.config_lock);
 	vcpu_set_hcr(vcpu);
+	vcpu_set_ich_hcr(vcpu);
 
 	if (cpus_have_final_cap(ARM64_HAS_HCX)) {
 		/*
diff --git a/arch/arm64/kvm/vgic/vgic-v3.c b/arch/arm64/kvm/vgic/vgic-v3.c
index 3eecdd2f4b8f..11718412921f 100644
--- a/arch/arm64/kvm/vgic/vgic-v3.c
+++ b/arch/arm64/kvm/vgic/vgic-v3.c
@@ -292,6 +292,15 @@ void vgic_v3_enable(struct kvm_vcpu *vcpu)
 
 	/* Get the show on the road... */
 	vgic_v3->vgic_hcr = ICH_HCR_EN;
+}
+
+void vcpu_set_ich_hcr(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v3_cpu_if *vgic_v3 = &vcpu->arch.vgic_cpu.vgic_v3;
+
+	if (!kvm_has_gicv3(vcpu->kvm))
+		return;
+
 	if (group0_trap)
 		vgic_v3->vgic_hcr |= ICH_HCR_TALL0;
 	if (group1_trap)
diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h
index 8532bfe3fed4..c72c38b44234 100644
--- a/arch/arm64/kvm/vgic/vgic.h
+++ b/arch/arm64/kvm/vgic/vgic.h
@@ -346,6 +346,8 @@ void vgic_v4_configure_vsgis(struct kvm *kvm);
 void vgic_v4_get_vlpi_state(struct vgic_irq *irq, bool *val);
 int vgic_v4_request_vpe_irq(struct kvm_vcpu *vcpu, int irq);
 
+void vcpu_set_ich_hcr(struct kvm_vcpu *vcpu);
+
 static inline bool kvm_has_gicv3(struct kvm *kvm)
 {
 	return (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif) &&
-- 
2.39.2



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

* [PATCH 03/12] KVM: arm64: Force SRE traps when SRE access is not enabled
  2024-08-20 10:03 [PATCH 00/12] KVM: arm64: Handle the lack of GICv3 exposed to a guest Marc Zyngier
  2024-08-20 10:03 ` [PATCH 01/12] KVM: arm64: Make ICC_*SGI*_EL1 undef in the absence of a vGICv3 Marc Zyngier
  2024-08-20 10:03 ` [PATCH 02/12] KVM: arm64: Move GICv3 trap configuration to kvm_calculate_traps() Marc Zyngier
@ 2024-08-20 10:03 ` Marc Zyngier
  2024-08-20 23:19   ` Oliver Upton
  2024-08-20 10:03 ` [PATCH 04/12] KVM: arm64: Force GICv3 traps activa when no irqchip is configured on VHE Marc Zyngier
                   ` (8 subsequent siblings)
  11 siblings, 1 reply; 26+ messages in thread
From: Marc Zyngier @ 2024-08-20 10:03 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel, kvm
  Cc: James Morse, Suzuki K Poulose, Oliver Upton, Zenghui Yu,
	Alexander Potapenko

We so far only write the ICH_HCR_EL2 config in two situations:

- when we need to emulate the GICv3 CPU interface due to HW bugs

- when we do direct injection, as the virtual CPU interface needs
  to be enabled

This is all good. But it also means that we don't do anything special
when we emulate a GICv2, or that there is no GIC at all.

What happens in this case when the guest uses the GICv3 system
registers? The *guest* gets a trap for a sysreg access (EC=0x18)
while we'd really like it to get an UNDEF.

Fixing this is a bit involved:

- we need to set all the required trap bits (TC, TALL0, TALL1, TDIR)

- for these traps to take effect, we need to (counter-intuitively)
  set ICC_SRE_EL1.SRE to 1 so that the above traps take priority.

Note that doesn't fully work when GICv2 emulation is enabled, as
we cannot set ICC_SRE_EL1.SRE to 1 (it breaks Group0 delivery as
IRQ).

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/kvm/hyp/vgic-v3-sr.c | 22 ++++++++++++++++------
 arch/arm64/kvm/vgic/vgic-v3.c   |  5 ++++-
 2 files changed, 20 insertions(+), 7 deletions(-)

diff --git a/arch/arm64/kvm/hyp/vgic-v3-sr.c b/arch/arm64/kvm/hyp/vgic-v3-sr.c
index 7b397fad26f2..a184def8f5ad 100644
--- a/arch/arm64/kvm/hyp/vgic-v3-sr.c
+++ b/arch/arm64/kvm/hyp/vgic-v3-sr.c
@@ -268,8 +268,16 @@ void __vgic_v3_activate_traps(struct vgic_v3_cpu_if *cpu_if)
 	 * starting to mess with the rest of the GIC, and VMCR_EL2 in
 	 * particular.  This logic must be called before
 	 * __vgic_v3_restore_state().
+	 *
+	 * However, if the vgic is disabled (ICH_HCR_EL2.EN==0), no GIC is
+	 * provisionned at all. In order to prevent illegal accesses to the
+	 * system registers to trap to EL1 (duh), force ICC_SRE_EL1.SRE to 1
+	 * so that the trap bits can take effect. Yes, we *loves* the GIC.
 	 */
-	if (!cpu_if->vgic_sre) {
+	if (!(cpu_if->vgic_hcr & ICH_HCR_EN)) {
+		write_gicreg(ICC_SRE_EL1_SRE, ICC_SRE_EL1);
+		isb();
+	} else if (!cpu_if->vgic_sre) {
 		write_gicreg(0, ICC_SRE_EL1);
 		isb();
 		write_gicreg(cpu_if->vgic_vmcr, ICH_VMCR_EL2);
@@ -288,8 +296,9 @@ void __vgic_v3_activate_traps(struct vgic_v3_cpu_if *cpu_if)
 	}
 
 	/*
-	 * Prevent the guest from touching the GIC system registers if
-	 * SRE isn't enabled for GICv3 emulation.
+	 * Prevent the guest from touching the ICC_SRE_EL1 system
+	 * register. Note that this may not have any effect, as
+	 * ICC_SRE_EL2.Enable being RAO/WI is a valid implementation.
 	 */
 	write_gicreg(read_gicreg(ICC_SRE_EL2) & ~ICC_SRE_EL2_ENABLE,
 		     ICC_SRE_EL2);
@@ -297,10 +306,11 @@ void __vgic_v3_activate_traps(struct vgic_v3_cpu_if *cpu_if)
 	/*
 	 * If we need to trap system registers, we must write
 	 * ICH_HCR_EL2 anyway, even if no interrupts are being
-	 * injected,
+	 * injected. Note that this also applies if we don't expect
+	 * any system register access (GICv2 or no vgic at all).
 	 */
 	if (static_branch_unlikely(&vgic_v3_cpuif_trap) ||
-	    cpu_if->its_vpe.its_vm)
+	    cpu_if->its_vpe.its_vm || !cpu_if->vgic_sre)
 		write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2);
 }
 
@@ -326,7 +336,7 @@ void __vgic_v3_deactivate_traps(struct vgic_v3_cpu_if *cpu_if)
 	 * no interrupts were being injected, and we disable it again here.
 	 */
 	if (static_branch_unlikely(&vgic_v3_cpuif_trap) ||
-	    cpu_if->its_vpe.its_vm)
+	    cpu_if->its_vpe.its_vm || !cpu_if->vgic_sre)
 		write_gicreg(0, ICH_HCR_EL2);
 }
 
diff --git a/arch/arm64/kvm/vgic/vgic-v3.c b/arch/arm64/kvm/vgic/vgic-v3.c
index 11718412921f..b217b256853c 100644
--- a/arch/arm64/kvm/vgic/vgic-v3.c
+++ b/arch/arm64/kvm/vgic/vgic-v3.c
@@ -298,8 +298,11 @@ void vcpu_set_ich_hcr(struct kvm_vcpu *vcpu)
 {
 	struct vgic_v3_cpu_if *vgic_v3 = &vcpu->arch.vgic_cpu.vgic_v3;
 
-	if (!kvm_has_gicv3(vcpu->kvm))
+	/* Hide GICv3 sysreg if necessary */
+	if (!kvm_has_gicv3(vcpu->kvm)) {
+		vgic_v3->vgic_hcr |= ICH_HCR_TALL0 | ICH_HCR_TALL1 | ICH_HCR_TC;
 		return;
+	}
 
 	if (group0_trap)
 		vgic_v3->vgic_hcr |= ICH_HCR_TALL0;
-- 
2.39.2



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

* [PATCH 04/12] KVM: arm64: Force GICv3 traps activa when no irqchip is configured on VHE
  2024-08-20 10:03 [PATCH 00/12] KVM: arm64: Handle the lack of GICv3 exposed to a guest Marc Zyngier
                   ` (2 preceding siblings ...)
  2024-08-20 10:03 ` [PATCH 03/12] KVM: arm64: Force SRE traps when SRE access is not enabled Marc Zyngier
@ 2024-08-20 10:03 ` Marc Zyngier
  2024-08-20 23:33   ` Oliver Upton
  2024-08-20 10:03 ` [PATCH 05/12] KVM: arm64: Add helper for last ditch idreg adjustments Marc Zyngier
                   ` (7 subsequent siblings)
  11 siblings, 1 reply; 26+ messages in thread
From: Marc Zyngier @ 2024-08-20 10:03 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel, kvm
  Cc: James Morse, Suzuki K Poulose, Oliver Upton, Zenghui Yu,
	Alexander Potapenko

On a VHE system, no GICv3 traps get configured when no irqchip is
present. This is not quite matching the "no GICv3" semantics that
we want to present.

Force such traps to be configured in this case.

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/kvm/vgic/vgic.c | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
index 974849ea7101..2caa64415ff3 100644
--- a/arch/arm64/kvm/vgic/vgic.c
+++ b/arch/arm64/kvm/vgic/vgic.c
@@ -917,10 +917,13 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
 
 void kvm_vgic_load(struct kvm_vcpu *vcpu)
 {
-	if (unlikely(!vgic_initialized(vcpu->kvm)))
+	if (unlikely(!irqchip_in_kernel(vcpu->kvm) || !vgic_initialized(vcpu->kvm))) {
+		if (has_vhe() && static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
+			__vgic_v3_activate_traps(&vcpu->arch.vgic_cpu.vgic_v3);
 		return;
+	}
 
-	if (kvm_vgic_global_state.type == VGIC_V2)
+	if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
 		vgic_v2_load(vcpu);
 	else
 		vgic_v3_load(vcpu);
@@ -928,10 +931,13 @@ void kvm_vgic_load(struct kvm_vcpu *vcpu)
 
 void kvm_vgic_put(struct kvm_vcpu *vcpu)
 {
-	if (unlikely(!vgic_initialized(vcpu->kvm)))
+	if (unlikely(!irqchip_in_kernel(vcpu->kvm) || !vgic_initialized(vcpu->kvm))) {
+		if (has_vhe() && static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
+			__vgic_v3_deactivate_traps(&vcpu->arch.vgic_cpu.vgic_v3);
 		return;
+	}
 
-	if (kvm_vgic_global_state.type == VGIC_V2)
+	if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
 		vgic_v2_put(vcpu);
 	else
 		vgic_v3_put(vcpu);
-- 
2.39.2



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

* [PATCH 05/12] KVM: arm64: Add helper for last ditch idreg adjustments
  2024-08-20 10:03 [PATCH 00/12] KVM: arm64: Handle the lack of GICv3 exposed to a guest Marc Zyngier
                   ` (3 preceding siblings ...)
  2024-08-20 10:03 ` [PATCH 04/12] KVM: arm64: Force GICv3 traps activa when no irqchip is configured on VHE Marc Zyngier
@ 2024-08-20 10:03 ` Marc Zyngier
  2024-08-20 10:03 ` [PATCH 06/12] KVM: arm64: Zero ID_AA64PFR0_EL1.GIC when no GICv3 is presented to the guest Marc Zyngier
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 26+ messages in thread
From: Marc Zyngier @ 2024-08-20 10:03 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel, kvm
  Cc: James Morse, Suzuki K Poulose, Oliver Upton, Zenghui Yu,
	Alexander Potapenko

We already have to perform a set of last-chance adjustments for
NV purposes. We will soon have to do the same for the GIC, so
introduce a helper for that exact purpose.

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/kvm/arm.c      | 10 +++++-----
 arch/arm64/kvm/nested.c   | 15 +++++----------
 arch/arm64/kvm/sys_regs.c | 23 +++++++++++++++++++++++
 arch/arm64/kvm/sys_regs.h |  2 ++
 4 files changed, 35 insertions(+), 15 deletions(-)

diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 9bef7638342e..fc46457d38d6 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -46,6 +46,8 @@
 #include <kvm/arm_pmu.h>
 #include <kvm/arm_psci.h>
 
+#include "sys_regs.h"
+
 static enum kvm_mode kvm_mode = KVM_MODE_DEFAULT;
 
 enum kvm_wfx_trap_policy {
@@ -821,11 +823,9 @@ int kvm_arch_vcpu_run_pid_change(struct kvm_vcpu *vcpu)
 			return ret;
 	}
 
-	if (vcpu_has_nv(vcpu)) {
-		ret = kvm_init_nv_sysregs(vcpu->kvm);
-		if (ret)
-			return ret;
-	}
+	ret = kvm_finalize_sys_regs(vcpu);
+	if (ret)
+		return ret;
 
 	/*
 	 * This needs to happen after NV has imposed its own restrictions on
diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c
index bab27f9d8cc6..e2067c594e4a 100644
--- a/arch/arm64/kvm/nested.c
+++ b/arch/arm64/kvm/nested.c
@@ -954,19 +954,16 @@ static void set_sysreg_masks(struct kvm *kvm, int sr, u64 res0, u64 res1)
 int kvm_init_nv_sysregs(struct kvm *kvm)
 {
 	u64 res0, res1;
-	int ret = 0;
 
-	mutex_lock(&kvm->arch.config_lock);
+	lockdep_assert_held(&kvm->arch.config_lock);
 
 	if (kvm->arch.sysreg_masks)
-		goto out;
+		return 0;
 
 	kvm->arch.sysreg_masks = kzalloc(sizeof(*(kvm->arch.sysreg_masks)),
 					 GFP_KERNEL_ACCOUNT);
-	if (!kvm->arch.sysreg_masks) {
-		ret = -ENOMEM;
-		goto out;
-	}
+	if (!kvm->arch.sysreg_masks)
+		return -ENOMEM;
 
 	limit_nv_id_regs(kvm);
 
@@ -1195,8 +1192,6 @@ int kvm_init_nv_sysregs(struct kvm *kvm)
 	if (!kvm_has_feat(kvm, ID_AA64PFR0_EL1, AMU, V1P1))
 		res0 |= ~(res0 | res1);
 	set_sysreg_masks(kvm, HAFGRTR_EL2, res0, res1);
-out:
-	mutex_unlock(&kvm->arch.config_lock);
 
-	return ret;
+	return 0;
 }
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 257c8da23a4e..bc2d54da3827 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -4620,6 +4620,29 @@ void kvm_calculate_traps(struct kvm_vcpu *vcpu)
 	mutex_unlock(&kvm->arch.config_lock);
 }
 
+/*
+ * Perform last adjustments to the ID registers that are implied by the
+ * configuration outside of the ID regs themselves, as well as any
+ * initialisation that directly depend on these ID registers (such as
+ * RES0/RES1 behaviours). This is not the place to configure traps though.
+ *
+ * Because this can be called once per CPU, changes must be idempotent.
+ */
+int kvm_finalize_sys_regs(struct kvm_vcpu *vcpu)
+{
+	struct kvm *kvm = vcpu->kvm;
+
+	guard(mutex)(&kvm->arch.config_lock);
+
+	if (vcpu_has_nv(vcpu)) {
+		int ret = kvm_init_nv_sysregs(kvm);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
 int __init kvm_sys_reg_table_init(void)
 {
 	bool valid = true;
diff --git a/arch/arm64/kvm/sys_regs.h b/arch/arm64/kvm/sys_regs.h
index 997eea21ba2a..7c9b4eb0baa6 100644
--- a/arch/arm64/kvm/sys_regs.h
+++ b/arch/arm64/kvm/sys_regs.h
@@ -235,6 +235,8 @@ int kvm_sys_reg_set_user(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg,
 
 bool triage_sysreg_trap(struct kvm_vcpu *vcpu, int *sr_index);
 
+int kvm_finalize_sys_regs(struct kvm_vcpu *vcpu);
+
 #define AA32(_x)	.aarch32_map = AA32_##_x
 #define Op0(_x) 	.Op0 = _x
 #define Op1(_x) 	.Op1 = _x
-- 
2.39.2



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

* [PATCH 06/12] KVM: arm64: Zero ID_AA64PFR0_EL1.GIC when no GICv3 is presented to the guest
  2024-08-20 10:03 [PATCH 00/12] KVM: arm64: Handle the lack of GICv3 exposed to a guest Marc Zyngier
                   ` (4 preceding siblings ...)
  2024-08-20 10:03 ` [PATCH 05/12] KVM: arm64: Add helper for last ditch idreg adjustments Marc Zyngier
@ 2024-08-20 10:03 ` Marc Zyngier
  2024-08-20 23:50   ` Oliver Upton
  2024-08-20 10:03 ` [PATCH 07/12] KVM: arm64: Add ICH_HCR_EL2 to the vcpu state Marc Zyngier
                   ` (5 subsequent siblings)
  11 siblings, 1 reply; 26+ messages in thread
From: Marc Zyngier @ 2024-08-20 10:03 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel, kvm
  Cc: James Morse, Suzuki K Poulose, Oliver Upton, Zenghui Yu,
	Alexander Potapenko

In order to be consistent, we shouldn't advertise a GICv3 when none
is actually usable by the guest.

Wipe the feature when these conditions apply, and allow the field
to be written from userspace.

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/kvm/sys_regs.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index bc2d54da3827..7d00d7e359e1 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -2365,7 +2365,6 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 		   ID_AA64PFR0_EL1_MPAM |
 		   ID_AA64PFR0_EL1_SVE |
 		   ID_AA64PFR0_EL1_RAS |
-		   ID_AA64PFR0_EL1_GIC |
 		   ID_AA64PFR0_EL1_AdvSIMD |
 		   ID_AA64PFR0_EL1_FP), },
 	ID_SANITISED(ID_AA64PFR1_EL1),
@@ -4634,6 +4633,11 @@ int kvm_finalize_sys_regs(struct kvm_vcpu *vcpu)
 
 	guard(mutex)(&kvm->arch.config_lock);
 
+	if (!kvm_has_gicv3(kvm)) {
+		kvm->arch.id_regs[IDREG_IDX(SYS_ID_AA64PFR0_EL1)] &= ~ID_AA64PFR0_EL1_GIC_MASK;
+		kvm->arch.id_regs[IDREG_IDX(SYS_ID_PFR1_EL1)] &= ~ID_PFR1_EL1_GIC_MASK;
+	}
+
 	if (vcpu_has_nv(vcpu)) {
 		int ret = kvm_init_nv_sysregs(kvm);
 		if (ret)
-- 
2.39.2



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

* [PATCH 07/12] KVM: arm64: Add ICH_HCR_EL2 to the vcpu state
  2024-08-20 10:03 [PATCH 00/12] KVM: arm64: Handle the lack of GICv3 exposed to a guest Marc Zyngier
                   ` (5 preceding siblings ...)
  2024-08-20 10:03 ` [PATCH 06/12] KVM: arm64: Zero ID_AA64PFR0_EL1.GIC when no GICv3 is presented to the guest Marc Zyngier
@ 2024-08-20 10:03 ` Marc Zyngier
  2024-08-20 10:03 ` [PATCH 08/12] KVM: arm64: Add trap routing information for ICH_HCR_EL2 Marc Zyngier
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 26+ messages in thread
From: Marc Zyngier @ 2024-08-20 10:03 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel, kvm
  Cc: James Morse, Suzuki K Poulose, Oliver Upton, Zenghui Yu,
	Alexander Potapenko

As we are about to describe the trap routing for ICH_HCR_EL2, add
the register to the vcpu state in its VNCR form, as well as reset

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/include/asm/kvm_host.h | 2 ++
 arch/arm64/kvm/sys_regs.c         | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index a33f5996ca9f..16cd59362b3d 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -530,6 +530,8 @@ enum vcpu_sysreg {
 	VNCR(CNTP_CVAL_EL0),
 	VNCR(CNTP_CTL_EL0),
 
+	VNCR(ICH_HCR_EL2),
+
 	NR_SYS_REGS	/* Nothing after this line! */
 };
 
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 7d00d7e359e1..c14fea3abc1b 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -2797,6 +2797,8 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	EL2_REG(RVBAR_EL2, access_rw, reset_val, 0),
 	{ SYS_DESC(SYS_RMR_EL2), trap_undef },
 
+	EL2_REG_VNCR(ICH_HCR_EL2, reset_val, 0),
+
 	EL2_REG(CONTEXTIDR_EL2, access_rw, reset_val, 0),
 	EL2_REG(TPIDR_EL2, access_rw, reset_val, 0),
 
-- 
2.39.2



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

* [PATCH 08/12] KVM: arm64: Add trap routing information for ICH_HCR_EL2
  2024-08-20 10:03 [PATCH 00/12] KVM: arm64: Handle the lack of GICv3 exposed to a guest Marc Zyngier
                   ` (6 preceding siblings ...)
  2024-08-20 10:03 ` [PATCH 07/12] KVM: arm64: Add ICH_HCR_EL2 to the vcpu state Marc Zyngier
@ 2024-08-20 10:03 ` Marc Zyngier
  2024-08-20 10:03 ` [PATCH 09/12] KVM: arm64: Honor guest requested traps in GICv3 emulation Marc Zyngier
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 26+ messages in thread
From: Marc Zyngier @ 2024-08-20 10:03 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel, kvm
  Cc: James Morse, Suzuki K Poulose, Oliver Upton, Zenghui Yu,
	Alexander Potapenko

The usual song and dance. Anything that is a trap, any register
it traps. Note that we don't handle the registers added by
FEAT_NMI for now.

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/kvm/emulate-nested.c | 77 ++++++++++++++++++++++++++++++---
 1 file changed, 72 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/kvm/emulate-nested.c b/arch/arm64/kvm/emulate-nested.c
index 05166eccea0a..63a2ce76619f 100644
--- a/arch/arm64/kvm/emulate-nested.c
+++ b/arch/arm64/kvm/emulate-nested.c
@@ -85,12 +85,17 @@ enum cgt_group_id {
 
 	CGT_HCRX_TCR2En,
 
+	CGT_ICH_HCR_TC,
+	CGT_ICH_HCR_TALL0,
+	CGT_ICH_HCR_TALL1,
+	CGT_ICH_HCR_TDIR,
+
 	/*
 	 * Anything after this point is a combination of coarse trap
 	 * controls, which must all be evaluated to decide what to do.
 	 */
 	__MULTIPLE_CONTROL_BITS__,
-	CGT_HCR_IMO_FMO = __MULTIPLE_CONTROL_BITS__,
+	CGT_HCR_IMO_FMO_ICH_HCR_TC = __MULTIPLE_CONTROL_BITS__,
 	CGT_HCR_TID2_TID4,
 	CGT_HCR_TTLB_TTLBIS,
 	CGT_HCR_TTLB_TTLBOS,
@@ -105,6 +110,8 @@ enum cgt_group_id {
 	CGT_MDCR_TDE_TDRA,
 	CGT_MDCR_TDCC_TDE_TDA,
 
+	CGT_ICH_HCR_TC_TDIR,
+
 	/*
 	 * Anything after this point requires a callback evaluating a
 	 * complex trap condition. Ugly stuff.
@@ -378,6 +385,36 @@ static const struct trap_bits coarse_trap_bits[] = {
 		.mask		= HCRX_EL2_TCR2En,
 		.behaviour	= BEHAVE_FORWARD_ANY,
 	},
+	[CGT_ICH_HCR_TC] = {
+		.index		= ICH_HCR_EL2,
+		.value		= ICH_HCR_TC,
+		.mask		= ICH_HCR_TC,
+		.behaviour	= BEHAVE_FORWARD_ANY,
+	},
+	[CGT_ICH_HCR_TALL0] = {
+		.index		= ICH_HCR_EL2,
+		.value		= ICH_HCR_TALL0,
+		.mask		= ICH_HCR_TALL0,
+		.behaviour	= BEHAVE_FORWARD_ANY,
+	},
+	[CGT_ICH_HCR_TALL1] = {
+		.index		= ICH_HCR_EL2,
+		.value		= ICH_HCR_TALL1,
+		.mask		= ICH_HCR_TALL1,
+		.behaviour	= BEHAVE_FORWARD_ANY,
+	},
+	[CGT_ICH_HCR_TALL0] = {
+		.index		= ICH_HCR_EL2,
+		.value		= ICH_HCR_TALL0,
+		.mask		= ICH_HCR_TALL0,
+		.behaviour	= BEHAVE_FORWARD_ANY,
+	},
+	[CGT_ICH_HCR_TDIR] = {
+		.index		= ICH_HCR_EL2,
+		.value		= ICH_HCR_TDIR,
+		.mask		= ICH_HCR_TDIR,
+		.behaviour	= BEHAVE_FORWARD_ANY,
+	},
 };
 
 #define MCB(id, ...)						\
@@ -387,7 +424,6 @@ static const struct trap_bits coarse_trap_bits[] = {
 		}
 
 static const enum cgt_group_id *coarse_control_combo[] = {
-	MCB(CGT_HCR_IMO_FMO,		CGT_HCR_IMO, CGT_HCR_FMO),
 	MCB(CGT_HCR_TID2_TID4,		CGT_HCR_TID2, CGT_HCR_TID4),
 	MCB(CGT_HCR_TTLB_TTLBIS,	CGT_HCR_TTLB, CGT_HCR_TTLBIS),
 	MCB(CGT_HCR_TTLB_TTLBOS,	CGT_HCR_TTLB, CGT_HCR_TTLBOS),
@@ -402,6 +438,9 @@ static const enum cgt_group_id *coarse_control_combo[] = {
 	MCB(CGT_MDCR_TDE_TDOSA,		CGT_MDCR_TDE, CGT_MDCR_TDOSA),
 	MCB(CGT_MDCR_TDE_TDRA,		CGT_MDCR_TDE, CGT_MDCR_TDRA),
 	MCB(CGT_MDCR_TDCC_TDE_TDA,	CGT_MDCR_TDCC, CGT_MDCR_TDE, CGT_MDCR_TDA),
+
+	MCB(CGT_HCR_IMO_FMO_ICH_HCR_TC,	CGT_HCR_IMO, CGT_HCR_FMO, CGT_ICH_HCR_TC),
+	MCB(CGT_ICH_HCR_TC_TDIR,	CGT_ICH_HCR_TC, CGT_ICH_HCR_TDIR),
 };
 
 typedef enum trap_behaviour (*complex_condition_check)(struct kvm_vcpu *);
@@ -536,9 +575,9 @@ static const struct encoding_to_trap_config encoding_to_cgt[] __initconst = {
 	SR_TRAP(SYS_CSSELR_EL1,		CGT_HCR_TID2_TID4),
 	SR_RANGE_TRAP(SYS_ID_PFR0_EL1,
 		      sys_reg(3, 0, 0, 7, 7), CGT_HCR_TID3),
-	SR_TRAP(SYS_ICC_SGI0R_EL1,	CGT_HCR_IMO_FMO),
-	SR_TRAP(SYS_ICC_ASGI1R_EL1,	CGT_HCR_IMO_FMO),
-	SR_TRAP(SYS_ICC_SGI1R_EL1,	CGT_HCR_IMO_FMO),
+	SR_TRAP(SYS_ICC_SGI0R_EL1,	CGT_HCR_IMO_FMO_ICH_HCR_TC),
+	SR_TRAP(SYS_ICC_ASGI1R_EL1,	CGT_HCR_IMO_FMO_ICH_HCR_TC),
+	SR_TRAP(SYS_ICC_SGI1R_EL1,	CGT_HCR_IMO_FMO_ICH_HCR_TC),
 	SR_RANGE_TRAP(sys_reg(3, 0, 11, 0, 0),
 		      sys_reg(3, 0, 11, 15, 7), CGT_HCR_TIDCP),
 	SR_RANGE_TRAP(sys_reg(3, 1, 11, 0, 0),
@@ -1108,6 +1147,34 @@ static const struct encoding_to_trap_config encoding_to_cgt[] __initconst = {
 	SR_TRAP(SYS_CNTP_CTL_EL0,	CGT_CNTHCTL_EL1PTEN),
 	SR_TRAP(SYS_CNTPCT_EL0,		CGT_CNTHCTL_EL1PCTEN),
 	SR_TRAP(SYS_CNTPCTSS_EL0,	CGT_CNTHCTL_EL1PCTEN),
+	/*
+	 * IMPDEF choice:
+	 * We treat ICC_SRE_EL2.{SRE,Enable) and ICV_SRE_EL1.SRE as
+	 * RAO/WI. We therefore never consider ICC_SRE_EL2.Enable for
+	 * ICC_SRE_EL1 access, and always handle it locally.
+	 */
+	SR_TRAP(SYS_ICC_AP0R0_EL1,	CGT_ICH_HCR_TALL0),
+	SR_TRAP(SYS_ICC_AP0R1_EL1,	CGT_ICH_HCR_TALL0),
+	SR_TRAP(SYS_ICC_AP0R2_EL1,	CGT_ICH_HCR_TALL0),
+	SR_TRAP(SYS_ICC_AP0R3_EL1,	CGT_ICH_HCR_TALL0),
+	SR_TRAP(SYS_ICC_AP1R0_EL1,	CGT_ICH_HCR_TALL1),
+	SR_TRAP(SYS_ICC_AP1R1_EL1,	CGT_ICH_HCR_TALL1),
+	SR_TRAP(SYS_ICC_AP1R2_EL1,	CGT_ICH_HCR_TALL1),
+	SR_TRAP(SYS_ICC_AP1R3_EL1,	CGT_ICH_HCR_TALL1),
+	SR_TRAP(SYS_ICC_BPR0_EL1,	CGT_ICH_HCR_TALL0),
+	SR_TRAP(SYS_ICC_BPR1_EL1,	CGT_ICH_HCR_TALL1),
+	SR_TRAP(SYS_ICC_CTLR_EL1,	CGT_ICH_HCR_TC),
+	SR_TRAP(SYS_ICC_DIR_EL1,	CGT_ICH_HCR_TC_TDIR),
+	SR_TRAP(SYS_ICC_EOIR0_EL1,	CGT_ICH_HCR_TALL0),
+	SR_TRAP(SYS_ICC_EOIR1_EL1,	CGT_ICH_HCR_TALL1),
+	SR_TRAP(SYS_ICC_HPPIR0_EL1,	CGT_ICH_HCR_TALL0),
+	SR_TRAP(SYS_ICC_HPPIR1_EL1,	CGT_ICH_HCR_TALL1),
+	SR_TRAP(SYS_ICC_IAR0_EL1,	CGT_ICH_HCR_TALL0),
+	SR_TRAP(SYS_ICC_IAR1_EL1,	CGT_ICH_HCR_TALL1),
+	SR_TRAP(SYS_ICC_IGRPEN0_EL1,	CGT_ICH_HCR_TALL0),
+	SR_TRAP(SYS_ICC_IGRPEN1_EL1,	CGT_ICH_HCR_TALL1),
+	SR_TRAP(SYS_ICC_PMR_EL1,	CGT_ICH_HCR_TC),
+	SR_TRAP(SYS_ICC_RPR_EL1,	CGT_ICH_HCR_TC),
 };
 
 static DEFINE_XARRAY(sr_forward_xa);
-- 
2.39.2



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

* [PATCH 09/12] KVM: arm64: Honor guest requested traps in GICv3 emulation
  2024-08-20 10:03 [PATCH 00/12] KVM: arm64: Handle the lack of GICv3 exposed to a guest Marc Zyngier
                   ` (7 preceding siblings ...)
  2024-08-20 10:03 ` [PATCH 08/12] KVM: arm64: Add trap routing information for ICH_HCR_EL2 Marc Zyngier
@ 2024-08-20 10:03 ` Marc Zyngier
  2024-08-20 10:03 ` [PATCH 10/12] KVM: arm64: Make most GICv3 accesses UNDEF if they trap Marc Zyngier
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 26+ messages in thread
From: Marc Zyngier @ 2024-08-20 10:03 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel, kvm
  Cc: James Morse, Suzuki K Poulose, Oliver Upton, Zenghui Yu,
	Alexander Potapenko

On platforms that require emulation of the CPU interface, we still
need to honor the traps requested by the guest (ICH_HCR_EL2 as well
as the FGTs for ICC_IGRPEN{0,1}_EL1.

Check for these bits early and lail out if any trap applies.

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/kvm/hyp/vgic-v3-sr.c | 72 +++++++++++++++++++++++++++++++++
 1 file changed, 72 insertions(+)

diff --git a/arch/arm64/kvm/hyp/vgic-v3-sr.c b/arch/arm64/kvm/hyp/vgic-v3-sr.c
index a184def8f5ad..a01138a663ae 100644
--- a/arch/arm64/kvm/hyp/vgic-v3-sr.c
+++ b/arch/arm64/kvm/hyp/vgic-v3-sr.c
@@ -1042,6 +1042,75 @@ static void __vgic_v3_write_ctlr(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
 	write_gicreg(vmcr, ICH_VMCR_EL2);
 }
 
+static bool __vgic_v3_check_trap_forwarding(struct kvm_vcpu *vcpu,
+					    u32 sysreg, bool is_read)
+{
+	u64 ich_hcr;
+
+	if (!vcpu_has_nv(vcpu) || is_hyp_ctxt(vcpu))
+		return false;
+
+	ich_hcr = __vcpu_sys_reg(vcpu, ICH_HCR_EL2);
+
+	switch (sysreg) {
+	case SYS_ICC_IGRPEN0_EL1:
+		if (is_read &&
+		    (__vcpu_sys_reg(vcpu, HFGRTR_EL2) & HFGxTR_EL2_ICC_IGRPENn_EL1))
+			return true;
+
+		if (!is_read &&
+		    (__vcpu_sys_reg(vcpu, HFGWTR_EL2) & HFGxTR_EL2_ICC_IGRPENn_EL1))
+			return true;
+
+		fallthrough;
+
+	case SYS_ICC_AP0Rn_EL1(0):
+	case SYS_ICC_AP0Rn_EL1(1):
+	case SYS_ICC_AP0Rn_EL1(2):
+	case SYS_ICC_AP0Rn_EL1(3):
+	case SYS_ICC_BPR0_EL1:
+	case SYS_ICC_EOIR0_EL1:
+	case SYS_ICC_HPPIR0_EL1:
+	case SYS_ICC_IAR0_EL1:
+		return ich_hcr & ICH_HCR_TALL0;
+
+	case SYS_ICC_IGRPEN1_EL1:
+		if (is_read &&
+		    (__vcpu_sys_reg(vcpu, HFGRTR_EL2) & HFGxTR_EL2_ICC_IGRPENn_EL1))
+			return true;
+
+		if (!is_read &&
+		    (__vcpu_sys_reg(vcpu, HFGWTR_EL2) & HFGxTR_EL2_ICC_IGRPENn_EL1))
+			return true;
+
+		fallthrough;
+
+	case SYS_ICC_AP1Rn_EL1(0):
+	case SYS_ICC_AP1Rn_EL1(1):
+	case SYS_ICC_AP1Rn_EL1(2):
+	case SYS_ICC_AP1Rn_EL1(3):
+	case SYS_ICC_BPR1_EL1:
+	case SYS_ICC_EOIR1_EL1:
+	case SYS_ICC_HPPIR1_EL1:
+	case SYS_ICC_IAR1_EL1:
+		return ich_hcr & ICH_HCR_TALL1;
+
+	case SYS_ICC_DIR_EL1:
+		if (ich_hcr & ICH_HCR_TDIR)
+			return true;
+
+		fallthrough;
+
+	case SYS_ICC_RPR_EL1:
+	case SYS_ICC_CTLR_EL1:
+	case SYS_ICC_PMR_EL1:
+		return ich_hcr & ICH_HCR_TC;
+
+	default:
+		return false;
+	}
+}
+
 int __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
 {
 	int rt;
@@ -1065,6 +1134,9 @@ int __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
 
 	is_read = (esr & ESR_ELx_SYS64_ISS_DIR_MASK) == ESR_ELx_SYS64_ISS_DIR_READ;
 
+	if (__vgic_v3_check_trap_forwarding(vcpu, sysreg, is_read))
+		return 0;
+
 	switch (sysreg) {
 	case SYS_ICC_IAR0_EL1:
 	case SYS_ICC_IAR1_EL1:
-- 
2.39.2



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

* [PATCH 10/12] KVM: arm64: Make most GICv3 accesses UNDEF if they trap
  2024-08-20 10:03 [PATCH 00/12] KVM: arm64: Handle the lack of GICv3 exposed to a guest Marc Zyngier
                   ` (8 preceding siblings ...)
  2024-08-20 10:03 ` [PATCH 09/12] KVM: arm64: Honor guest requested traps in GICv3 emulation Marc Zyngier
@ 2024-08-20 10:03 ` Marc Zyngier
  2024-08-20 10:03 ` [PATCH 11/12] KVM: arm64: Unify UNDEF injection helpers Marc Zyngier
  2024-08-20 10:03 ` [PATCH 12/12] KVM: arm64: Add selftest checking how the absence of GICv3 is handled Marc Zyngier
  11 siblings, 0 replies; 26+ messages in thread
From: Marc Zyngier @ 2024-08-20 10:03 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel, kvm
  Cc: James Morse, Suzuki K Poulose, Oliver Upton, Zenghui Yu,
	Alexander Potapenko

We don't expect to trap any GICv3 register for host handling,
apart from ICC_SRE_EL1 and the SGI registers. If they trap,
that's because the guest is playing with us despite being
told it doesn't have a GICv3.

If it does, UNDEF is what it will get.

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/kvm/hyp/vgic-v3-sr.c |  3 ++
 arch/arm64/kvm/sys_regs.c       | 74 +++++++++++++++++++++++++--------
 arch/arm64/kvm/sys_regs.h       |  7 ++++
 3 files changed, 66 insertions(+), 18 deletions(-)

diff --git a/arch/arm64/kvm/hyp/vgic-v3-sr.c b/arch/arm64/kvm/hyp/vgic-v3-sr.c
index a01138a663ae..a0291f4b0eb9 100644
--- a/arch/arm64/kvm/hyp/vgic-v3-sr.c
+++ b/arch/arm64/kvm/hyp/vgic-v3-sr.c
@@ -1120,6 +1120,9 @@ int __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
 	bool is_read;
 	u32 sysreg;
 
+	if (kern_hyp_va(vcpu->kvm)->arch.vgic.vgic_model != KVM_DEV_TYPE_ARM_VGIC_V3)
+		return 0;
+
 	esr = kvm_vcpu_get_esr(vcpu);
 	if (vcpu_mode_is_32bit(vcpu)) {
 		if (!kvm_condition_valid(vcpu)) {
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index c14fea3abc1b..ba6075973a36 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -47,6 +47,13 @@ static u64 sys_reg_to_index(const struct sys_reg_desc *reg);
 static int set_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
 		      u64 val);
 
+static bool undef_access(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+			 const struct sys_reg_desc *r)
+{
+	kvm_inject_undefined(vcpu);
+	return false;
+}
+
 static bool bad_trap(struct kvm_vcpu *vcpu,
 		     struct sys_reg_params *params,
 		     const struct sys_reg_desc *r,
@@ -484,6 +491,9 @@ static bool access_gic_sre(struct kvm_vcpu *vcpu,
 			   struct sys_reg_params *p,
 			   const struct sys_reg_desc *r)
 {
+	if (!kvm_has_gicv3(vcpu->kvm))
+		return undef_access(vcpu, p, r);
+
 	if (p->is_write)
 		return ignore_write(vcpu, p);
 
@@ -1344,14 +1354,6 @@ static int set_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
 	  .reset = reset_pmevtyper,					\
 	  .access = access_pmu_evtyper, .reg = (PMEVTYPER0_EL0 + n), }
 
-static bool undef_access(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
-			 const struct sys_reg_desc *r)
-{
-	kvm_inject_undefined(vcpu);
-
-	return false;
-}
-
 /* Macro to expand the AMU counter and type registers*/
 #define AMU_AMEVCNTR0_EL0(n) { SYS_DESC(SYS_AMEVCNTR0_EL0(n)), undef_access }
 #define AMU_AMEVTYPER0_EL0(n) { SYS_DESC(SYS_AMEVTYPER0_EL0(n)), undef_access }
@@ -2454,6 +2456,8 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	{ SYS_DESC(SYS_SPSR_EL1), access_spsr},
 	{ SYS_DESC(SYS_ELR_EL1), access_elr},
 
+	{ SYS_DESC(SYS_ICC_PMR_EL1), undef_access },
+
 	{ SYS_DESC(SYS_AFSR0_EL1), access_vm_reg, reset_unknown, AFSR0_EL1 },
 	{ SYS_DESC(SYS_AFSR1_EL1), access_vm_reg, reset_unknown, AFSR1_EL1 },
 	{ SYS_DESC(SYS_ESR_EL1), access_vm_reg, reset_unknown, ESR_EL1 },
@@ -2508,18 +2512,31 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	{ SYS_DESC(SYS_VBAR_EL1), access_rw, reset_val, VBAR_EL1, 0 },
 	{ SYS_DESC(SYS_DISR_EL1), NULL, reset_val, DISR_EL1, 0 },
 
-	{ SYS_DESC(SYS_ICC_IAR0_EL1), write_to_read_only },
-	{ SYS_DESC(SYS_ICC_EOIR0_EL1), read_from_write_only },
-	{ SYS_DESC(SYS_ICC_HPPIR0_EL1), write_to_read_only },
-	{ SYS_DESC(SYS_ICC_DIR_EL1), read_from_write_only },
-	{ SYS_DESC(SYS_ICC_RPR_EL1), write_to_read_only },
+	{ SYS_DESC(SYS_ICC_IAR0_EL1), undef_access },
+	{ SYS_DESC(SYS_ICC_EOIR0_EL1), undef_access },
+	{ SYS_DESC(SYS_ICC_HPPIR0_EL1), undef_access },
+	{ SYS_DESC(SYS_ICC_BPR0_EL1), undef_access },
+	{ SYS_DESC(SYS_ICC_AP0R0_EL1), undef_access },
+	{ SYS_DESC(SYS_ICC_AP0R1_EL1), undef_access },
+	{ SYS_DESC(SYS_ICC_AP0R2_EL1), undef_access },
+	{ SYS_DESC(SYS_ICC_AP0R3_EL1), undef_access },
+	{ SYS_DESC(SYS_ICC_AP1R0_EL1), undef_access },
+	{ SYS_DESC(SYS_ICC_AP1R1_EL1), undef_access },
+	{ SYS_DESC(SYS_ICC_AP1R2_EL1), undef_access },
+	{ SYS_DESC(SYS_ICC_AP1R3_EL1), undef_access },
+	{ SYS_DESC(SYS_ICC_DIR_EL1), undef_access },
+	{ SYS_DESC(SYS_ICC_RPR_EL1), undef_access },
 	{ SYS_DESC(SYS_ICC_SGI1R_EL1), access_gic_sgi },
 	{ SYS_DESC(SYS_ICC_ASGI1R_EL1), access_gic_sgi },
 	{ SYS_DESC(SYS_ICC_SGI0R_EL1), access_gic_sgi },
-	{ SYS_DESC(SYS_ICC_IAR1_EL1), write_to_read_only },
-	{ SYS_DESC(SYS_ICC_EOIR1_EL1), read_from_write_only },
-	{ SYS_DESC(SYS_ICC_HPPIR1_EL1), write_to_read_only },
+	{ SYS_DESC(SYS_ICC_IAR1_EL1), undef_access },
+	{ SYS_DESC(SYS_ICC_EOIR1_EL1), undef_access },
+	{ SYS_DESC(SYS_ICC_HPPIR1_EL1), undef_access },
+	{ SYS_DESC(SYS_ICC_BPR1_EL1), undef_access },
+	{ SYS_DESC(SYS_ICC_CTLR_EL1), undef_access },
 	{ SYS_DESC(SYS_ICC_SRE_EL1), access_gic_sre },
+	{ SYS_DESC(SYS_ICC_IGRPEN0_EL1), undef_access },
+	{ SYS_DESC(SYS_ICC_IGRPEN1_EL1), undef_access },
 
 	{ SYS_DESC(SYS_CONTEXTIDR_EL1), access_vm_reg, reset_val, CONTEXTIDR_EL1, 0 },
 	{ SYS_DESC(SYS_TPIDR_EL1), NULL, reset_unknown, TPIDR_EL1 },
@@ -3394,6 +3411,7 @@ static const struct sys_reg_desc cp15_regs[] = {
 	/* TTBCR2 */
 	{ AA32(HI), Op1( 0), CRn( 2), CRm( 0), Op2( 3), access_vm_reg, NULL, TCR_EL1 },
 	{ Op1( 0), CRn( 3), CRm( 0), Op2( 0), access_vm_reg, NULL, DACR32_EL2 },
+	{ CP15_SYS_DESC(SYS_ICC_PMR_EL1), undef_access },
 	/* DFSR */
 	{ Op1( 0), CRn( 5), CRm( 0), Op2( 0), access_vm_reg, NULL, ESR_EL1 },
 	{ Op1( 0), CRn( 5), CRm( 0), Op2( 1), access_vm_reg, NULL, IFSR32_EL2 },
@@ -3443,8 +3461,28 @@ static const struct sys_reg_desc cp15_regs[] = {
 	/* AMAIR1 */
 	{ AA32(HI), Op1( 0), CRn(10), CRm( 3), Op2( 1), access_vm_reg, NULL, AMAIR_EL1 },
 
-	/* ICC_SRE */
-	{ Op1( 0), CRn(12), CRm(12), Op2( 5), access_gic_sre },
+	{ CP15_SYS_DESC(SYS_ICC_IAR0_EL1), undef_access },
+	{ CP15_SYS_DESC(SYS_ICC_EOIR0_EL1), undef_access },
+	{ CP15_SYS_DESC(SYS_ICC_HPPIR0_EL1), undef_access },
+	{ CP15_SYS_DESC(SYS_ICC_BPR0_EL1), undef_access },
+	{ CP15_SYS_DESC(SYS_ICC_AP0R0_EL1), undef_access },
+	{ CP15_SYS_DESC(SYS_ICC_AP0R1_EL1), undef_access },
+	{ CP15_SYS_DESC(SYS_ICC_AP0R2_EL1), undef_access },
+	{ CP15_SYS_DESC(SYS_ICC_AP0R3_EL1), undef_access },
+	{ CP15_SYS_DESC(SYS_ICC_AP1R0_EL1), undef_access },
+	{ CP15_SYS_DESC(SYS_ICC_AP1R1_EL1), undef_access },
+	{ CP15_SYS_DESC(SYS_ICC_AP1R2_EL1), undef_access },
+	{ CP15_SYS_DESC(SYS_ICC_AP1R3_EL1), undef_access },
+	{ CP15_SYS_DESC(SYS_ICC_DIR_EL1), undef_access },
+	{ CP15_SYS_DESC(SYS_ICC_RPR_EL1), undef_access },
+	{ CP15_SYS_DESC(SYS_ICC_IAR1_EL1), undef_access },
+	{ CP15_SYS_DESC(SYS_ICC_EOIR1_EL1), undef_access },
+	{ CP15_SYS_DESC(SYS_ICC_HPPIR1_EL1), undef_access },
+	{ CP15_SYS_DESC(SYS_ICC_BPR1_EL1), undef_access },
+	{ CP15_SYS_DESC(SYS_ICC_CTLR_EL1), undef_access },
+	{ CP15_SYS_DESC(SYS_ICC_SRE_EL1), access_gic_sre },
+	{ CP15_SYS_DESC(SYS_ICC_IGRPEN0_EL1), undef_access },
+	{ CP15_SYS_DESC(SYS_ICC_IGRPEN1_EL1), undef_access },
 
 	{ Op1( 0), CRn(13), CRm( 0), Op2( 1), access_vm_reg, NULL, CONTEXTIDR_EL1 },
 
diff --git a/arch/arm64/kvm/sys_regs.h b/arch/arm64/kvm/sys_regs.h
index 7c9b4eb0baa6..dfb2ec83b284 100644
--- a/arch/arm64/kvm/sys_regs.h
+++ b/arch/arm64/kvm/sys_regs.h
@@ -250,4 +250,11 @@ int kvm_finalize_sys_regs(struct kvm_vcpu *vcpu);
 	CRn(sys_reg_CRn(reg)), CRm(sys_reg_CRm(reg)),	\
 	Op2(sys_reg_Op2(reg))
 
+#define CP15_SYS_DESC(reg)				\
+	.name = #reg,					\
+	.aarch32_map = AA32_DIRECT,			\
+	Op0(0), Op1(sys_reg_Op1(reg)),			\
+	CRn(sys_reg_CRn(reg)), CRm(sys_reg_CRm(reg)),	\
+	Op2(sys_reg_Op2(reg))
+
 #endif /* __ARM64_KVM_SYS_REGS_LOCAL_H__ */
-- 
2.39.2



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

* [PATCH 11/12] KVM: arm64: Unify UNDEF injection helpers
  2024-08-20 10:03 [PATCH 00/12] KVM: arm64: Handle the lack of GICv3 exposed to a guest Marc Zyngier
                   ` (9 preceding siblings ...)
  2024-08-20 10:03 ` [PATCH 10/12] KVM: arm64: Make most GICv3 accesses UNDEF if they trap Marc Zyngier
@ 2024-08-20 10:03 ` Marc Zyngier
  2024-08-20 10:03 ` [PATCH 12/12] KVM: arm64: Add selftest checking how the absence of GICv3 is handled Marc Zyngier
  11 siblings, 0 replies; 26+ messages in thread
From: Marc Zyngier @ 2024-08-20 10:03 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel, kvm
  Cc: James Morse, Suzuki K Poulose, Oliver Upton, Zenghui Yu,
	Alexander Potapenko

We currently have two helpers (undef_access() and trap_undef()) that
do exactly the same thing: inject an UNDEF and return 'false' (as an
indication that PC should not be incremented).

We definitely could do with one less. Given that undef_access() is
used 80ish times, while trap_undef() is only used 30 times, the
latter loses the battle and is immediately sacrificed.

We also have a large number of instances where undef_access() is
open-coded. Let's also convert those.

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/kvm/sys_regs.c | 132 +++++++++++++++-----------------------
 1 file changed, 51 insertions(+), 81 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index ba6075973a36..0976df0008cc 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -61,8 +61,7 @@ static bool bad_trap(struct kvm_vcpu *vcpu,
 {
 	WARN_ONCE(1, "Unexpected %s\n", msg);
 	print_sys_reg_instr(params);
-	kvm_inject_undefined(vcpu);
-	return false;
+	return undef_access(vcpu, params, r);
 }
 
 static bool read_from_write_only(struct kvm_vcpu *vcpu,
@@ -353,10 +352,8 @@ static bool access_dcgsw(struct kvm_vcpu *vcpu,
 			 struct sys_reg_params *p,
 			 const struct sys_reg_desc *r)
 {
-	if (!kvm_has_mte(vcpu->kvm)) {
-		kvm_inject_undefined(vcpu);
-		return false;
-	}
+	if (!kvm_has_mte(vcpu->kvm))
+		return undef_access(vcpu, p, r);
 
 	/* Treat MTE S/W ops as we treat the classic ones: with contempt */
 	return access_dcsw(vcpu, p, r);
@@ -393,10 +390,8 @@ static bool access_vm_reg(struct kvm_vcpu *vcpu,
 	u64 val, mask, shift;
 
 	if (reg_to_encoding(r) == SYS_TCR2_EL1 &&
-	    !kvm_has_feat(vcpu->kvm, ID_AA64MMFR3_EL1, TCRX, IMP)) {
-		kvm_inject_undefined(vcpu);
-		return false;
-	}
+	    !kvm_has_feat(vcpu->kvm, ID_AA64MMFR3_EL1, TCRX, IMP))
+		return undef_access(vcpu, p, r);
 
 	BUG_ON(!p->is_write);
 
@@ -443,10 +438,8 @@ static bool access_gic_sgi(struct kvm_vcpu *vcpu,
 {
 	bool g1;
 
-	if (!kvm_has_gicv3(vcpu->kvm)) {
-		kvm_inject_undefined(vcpu);
-		return false;
-	}
+	if (!kvm_has_gicv3(vcpu->kvm))
+		return undef_access(vcpu, p, r);
 
 	if (!p->is_write)
 		return read_from_write_only(vcpu, p, r);
@@ -511,14 +504,6 @@ static bool trap_raz_wi(struct kvm_vcpu *vcpu,
 		return read_zero(vcpu, p);
 }
 
-static bool trap_undef(struct kvm_vcpu *vcpu,
-		       struct sys_reg_params *p,
-		       const struct sys_reg_desc *r)
-{
-	kvm_inject_undefined(vcpu);
-	return false;
-}
-
 /*
  * ARMv8.1 mandates at least a trivial LORegion implementation, where all the
  * RW registers are RES0 (which we can implement as RAZ/WI). On an ARMv8.0
@@ -531,10 +516,8 @@ static bool trap_loregion(struct kvm_vcpu *vcpu,
 {
 	u32 sr = reg_to_encoding(r);
 
-	if (!kvm_has_feat(vcpu->kvm, ID_AA64MMFR1_EL1, LO, IMP)) {
-		kvm_inject_undefined(vcpu);
-		return false;
-	}
+	if (!kvm_has_feat(vcpu->kvm, ID_AA64MMFR1_EL1, LO, IMP))
+		return undef_access(vcpu, p, r);
 
 	if (p->is_write && sr == SYS_LORID_EL1)
 		return write_to_read_only(vcpu, p, r);
@@ -1267,10 +1250,8 @@ static bool access_pmuserenr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 			     const struct sys_reg_desc *r)
 {
 	if (p->is_write) {
-		if (!vcpu_mode_priv(vcpu)) {
-			kvm_inject_undefined(vcpu);
-			return false;
-		}
+		if (!vcpu_mode_priv(vcpu))
+			return undef_access(vcpu, p, r);
 
 		__vcpu_sys_reg(vcpu, PMUSERENR_EL0) =
 			       p->regval & ARMV8_PMU_USERENR_MASK;
@@ -1412,8 +1393,7 @@ static bool access_arch_timer(struct kvm_vcpu *vcpu,
 		break;
 	default:
 		print_sys_reg_msg(p, "%s", "Unhandled trapped timer register");
-		kvm_inject_undefined(vcpu);
-		return false;
+		return undef_access(vcpu, p, r);
 	}
 
 	if (p->is_write)
@@ -2309,7 +2289,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	// DBGDTR[TR]X_EL0 share the same encoding
 	{ SYS_DESC(SYS_DBGDTRTX_EL0), trap_raz_wi },
 
-	{ SYS_DESC(SYS_DBGVCR32_EL2), trap_undef, reset_val, DBGVCR32_EL2, 0 },
+	{ SYS_DESC(SYS_DBGVCR32_EL2), undef_access, reset_val, DBGVCR32_EL2, 0 },
 
 	{ SYS_DESC(SYS_MPIDR_EL1), NULL, reset_mpidr, MPIDR_EL1 },
 
@@ -2780,7 +2760,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	EL2_REG_VNCR(VTTBR_EL2, reset_val, 0),
 	EL2_REG_VNCR(VTCR_EL2, reset_val, 0),
 
-	{ SYS_DESC(SYS_DACR32_EL2), trap_undef, reset_unknown, DACR32_EL2 },
+	{ SYS_DESC(SYS_DACR32_EL2), undef_access, reset_unknown, DACR32_EL2 },
 	EL2_REG_VNCR(HDFGRTR_EL2, reset_val, 0),
 	EL2_REG_VNCR(HDFGWTR_EL2, reset_val, 0),
 	EL2_REG_VNCR(HAFGRTR_EL2, reset_val, 0),
@@ -2798,11 +2778,11 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	{ SYS_DESC(SYS_SPSR_fiq), .access = trap_raz_wi,
 	  .visibility = hidden_user_visibility },
 
-	{ SYS_DESC(SYS_IFSR32_EL2), trap_undef, reset_unknown, IFSR32_EL2 },
+	{ SYS_DESC(SYS_IFSR32_EL2), undef_access, reset_unknown, IFSR32_EL2 },
 	EL2_REG(AFSR0_EL2, access_rw, reset_val, 0),
 	EL2_REG(AFSR1_EL2, access_rw, reset_val, 0),
 	EL2_REG_REDIR(ESR_EL2, reset_val, 0),
-	{ SYS_DESC(SYS_FPEXC32_EL2), trap_undef, reset_val, FPEXC32_EL2, 0x700 },
+	{ SYS_DESC(SYS_FPEXC32_EL2), undef_access, reset_val, FPEXC32_EL2, 0x700 },
 
 	EL2_REG_REDIR(FAR_EL2, reset_val, 0),
 	EL2_REG(HPFAR_EL2, access_rw, reset_val, 0),
@@ -2812,7 +2792,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 
 	EL2_REG(VBAR_EL2, access_rw, reset_val, 0),
 	EL2_REG(RVBAR_EL2, access_rw, reset_val, 0),
-	{ SYS_DESC(SYS_RMR_EL2), trap_undef },
+	{ SYS_DESC(SYS_RMR_EL2), undef_access },
 
 	EL2_REG_VNCR(ICH_HCR_EL2, reset_val, 0),
 
@@ -2848,10 +2828,8 @@ static bool handle_alle1is(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 {
 	u32 sys_encoding = sys_insn(p->Op0, p->Op1, p->CRn, p->CRm, p->Op2);
 
-	if (!kvm_supported_tlbi_s12_op(vcpu, sys_encoding)) {
-		kvm_inject_undefined(vcpu);
-		return false;
-	}
+	if (!kvm_supported_tlbi_s12_op(vcpu, sys_encoding))
+		return undef_access(vcpu, p, r);
 
 	write_lock(&vcpu->kvm->mmu_lock);
 
@@ -2920,10 +2898,8 @@ static bool handle_vmalls12e1is(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 	u32 sys_encoding = sys_insn(p->Op0, p->Op1, p->CRn, p->CRm, p->Op2);
 	u64 limit, vttbr;
 
-	if (!kvm_supported_tlbi_s12_op(vcpu, sys_encoding)) {
-		kvm_inject_undefined(vcpu);
-		return false;
-	}
+	if (!kvm_supported_tlbi_s12_op(vcpu, sys_encoding))
+		return undef_access(vcpu, p, r);
 
 	vttbr = vcpu_read_sys_reg(vcpu, VTTBR_EL2);
 	limit = BIT_ULL(kvm_get_pa_bits(vcpu->kvm));
@@ -2948,10 +2924,8 @@ static bool handle_ripas2e1is(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 	u64 base, range, tg, num, scale;
 	int shift;
 
-	if (!kvm_supported_tlbi_ipas2_op(vcpu, sys_encoding)) {
-		kvm_inject_undefined(vcpu);
-		return false;
-	}
+	if (!kvm_supported_tlbi_ipas2_op(vcpu, sys_encoding))
+		return undef_access(vcpu, p, r);
 
 	/*
 	 * Because the shadow S2 structure doesn't necessarily reflect that
@@ -3019,10 +2993,8 @@ static bool handle_ipas2e1is(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 	u32 sys_encoding = sys_insn(p->Op0, p->Op1, p->CRn, p->CRm, p->Op2);
 	u64 vttbr = vcpu_read_sys_reg(vcpu, VTTBR_EL2);
 
-	if (!kvm_supported_tlbi_ipas2_op(vcpu, sys_encoding)) {
-		kvm_inject_undefined(vcpu);
-		return false;
-	}
+	if (!kvm_supported_tlbi_ipas2_op(vcpu, sys_encoding))
+		return undef_access(vcpu, p, r);
 
 	kvm_s2_mmu_iterate_by_vmid(vcpu->kvm, get_vmid(vttbr),
 				   &(union tlbi_info) {
@@ -3062,10 +3034,8 @@ static bool handle_tlbi_el1(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 
 	WARN_ON(!vcpu_is_el2(vcpu));
 
-	if (!kvm_supported_tlbi_s1e1_op(vcpu, sys_encoding)) {
-		kvm_inject_undefined(vcpu);
-		return false;
-	}
+	if (!kvm_supported_tlbi_s1e1_op(vcpu, sys_encoding))
+		return undef_access(vcpu, p, r);
 
 	kvm_s2_mmu_iterate_by_vmid(vcpu->kvm, get_vmid(vttbr),
 				   &(union tlbi_info) {
@@ -3173,14 +3143,14 @@ static struct sys_reg_desc sys_insn_descs[] = {
 	SYS_INSN(TLBI_IPAS2LE1IS, handle_ipas2e1is),
 	SYS_INSN(TLBI_RIPAS2LE1IS, handle_ripas2e1is),
 
-	SYS_INSN(TLBI_ALLE2OS, trap_undef),
-	SYS_INSN(TLBI_VAE2OS, trap_undef),
+	SYS_INSN(TLBI_ALLE2OS, undef_access),
+	SYS_INSN(TLBI_VAE2OS, undef_access),
 	SYS_INSN(TLBI_ALLE1OS, handle_alle1is),
-	SYS_INSN(TLBI_VALE2OS, trap_undef),
+	SYS_INSN(TLBI_VALE2OS, undef_access),
 	SYS_INSN(TLBI_VMALLS12E1OS, handle_vmalls12e1is),
 
-	SYS_INSN(TLBI_RVAE2IS, trap_undef),
-	SYS_INSN(TLBI_RVALE2IS, trap_undef),
+	SYS_INSN(TLBI_RVAE2IS, undef_access),
+	SYS_INSN(TLBI_RVALE2IS, undef_access),
 
 	SYS_INSN(TLBI_ALLE1IS, handle_alle1is),
 	SYS_INSN(TLBI_VMALLS12E1IS, handle_vmalls12e1is),
@@ -3192,10 +3162,10 @@ static struct sys_reg_desc sys_insn_descs[] = {
 	SYS_INSN(TLBI_IPAS2LE1, handle_ipas2e1is),
 	SYS_INSN(TLBI_RIPAS2LE1, handle_ripas2e1is),
 	SYS_INSN(TLBI_RIPAS2LE1OS, handle_ripas2e1is),
-	SYS_INSN(TLBI_RVAE2OS, trap_undef),
-	SYS_INSN(TLBI_RVALE2OS, trap_undef),
-	SYS_INSN(TLBI_RVAE2, trap_undef),
-	SYS_INSN(TLBI_RVALE2, trap_undef),
+	SYS_INSN(TLBI_RVAE2OS, undef_access),
+	SYS_INSN(TLBI_RVALE2OS, undef_access),
+	SYS_INSN(TLBI_RVAE2, undef_access),
+	SYS_INSN(TLBI_RVALE2, undef_access),
 	SYS_INSN(TLBI_ALLE1, handle_alle1is),
 	SYS_INSN(TLBI_VMALLS12E1, handle_vmalls12e1is),
 
@@ -3204,19 +3174,19 @@ static struct sys_reg_desc sys_insn_descs[] = {
 	SYS_INSN(TLBI_IPAS2LE1ISNXS, handle_ipas2e1is),
 	SYS_INSN(TLBI_RIPAS2LE1ISNXS, handle_ripas2e1is),
 
-	SYS_INSN(TLBI_ALLE2OSNXS, trap_undef),
-	SYS_INSN(TLBI_VAE2OSNXS, trap_undef),
+	SYS_INSN(TLBI_ALLE2OSNXS, undef_access),
+	SYS_INSN(TLBI_VAE2OSNXS, undef_access),
 	SYS_INSN(TLBI_ALLE1OSNXS, handle_alle1is),
-	SYS_INSN(TLBI_VALE2OSNXS, trap_undef),
+	SYS_INSN(TLBI_VALE2OSNXS, undef_access),
 	SYS_INSN(TLBI_VMALLS12E1OSNXS, handle_vmalls12e1is),
 
-	SYS_INSN(TLBI_RVAE2ISNXS, trap_undef),
-	SYS_INSN(TLBI_RVALE2ISNXS, trap_undef),
-	SYS_INSN(TLBI_ALLE2ISNXS, trap_undef),
-	SYS_INSN(TLBI_VAE2ISNXS, trap_undef),
+	SYS_INSN(TLBI_RVAE2ISNXS, undef_access),
+	SYS_INSN(TLBI_RVALE2ISNXS, undef_access),
+	SYS_INSN(TLBI_ALLE2ISNXS, undef_access),
+	SYS_INSN(TLBI_VAE2ISNXS, undef_access),
 
 	SYS_INSN(TLBI_ALLE1ISNXS, handle_alle1is),
-	SYS_INSN(TLBI_VALE2ISNXS, trap_undef),
+	SYS_INSN(TLBI_VALE2ISNXS, undef_access),
 	SYS_INSN(TLBI_VMALLS12E1ISNXS, handle_vmalls12e1is),
 	SYS_INSN(TLBI_IPAS2E1OSNXS, handle_ipas2e1is),
 	SYS_INSN(TLBI_IPAS2E1NXS, handle_ipas2e1is),
@@ -3226,14 +3196,14 @@ static struct sys_reg_desc sys_insn_descs[] = {
 	SYS_INSN(TLBI_IPAS2LE1NXS, handle_ipas2e1is),
 	SYS_INSN(TLBI_RIPAS2LE1NXS, handle_ripas2e1is),
 	SYS_INSN(TLBI_RIPAS2LE1OSNXS, handle_ripas2e1is),
-	SYS_INSN(TLBI_RVAE2OSNXS, trap_undef),
-	SYS_INSN(TLBI_RVALE2OSNXS, trap_undef),
-	SYS_INSN(TLBI_RVAE2NXS, trap_undef),
-	SYS_INSN(TLBI_RVALE2NXS, trap_undef),
-	SYS_INSN(TLBI_ALLE2NXS, trap_undef),
-	SYS_INSN(TLBI_VAE2NXS, trap_undef),
+	SYS_INSN(TLBI_RVAE2OSNXS, undef_access),
+	SYS_INSN(TLBI_RVALE2OSNXS, undef_access),
+	SYS_INSN(TLBI_RVAE2NXS, undef_access),
+	SYS_INSN(TLBI_RVALE2NXS, undef_access),
+	SYS_INSN(TLBI_ALLE2NXS, undef_access),
+	SYS_INSN(TLBI_VAE2NXS, undef_access),
 	SYS_INSN(TLBI_ALLE1NXS, handle_alle1is),
-	SYS_INSN(TLBI_VALE2NXS, trap_undef),
+	SYS_INSN(TLBI_VALE2NXS, undef_access),
 	SYS_INSN(TLBI_VMALLS12E1NXS, handle_vmalls12e1is),
 };
 
-- 
2.39.2



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

* [PATCH 12/12] KVM: arm64: Add selftest checking how the absence of GICv3 is handled
  2024-08-20 10:03 [PATCH 00/12] KVM: arm64: Handle the lack of GICv3 exposed to a guest Marc Zyngier
                   ` (10 preceding siblings ...)
  2024-08-20 10:03 ` [PATCH 11/12] KVM: arm64: Unify UNDEF injection helpers Marc Zyngier
@ 2024-08-20 10:03 ` Marc Zyngier
  2024-08-21  0:10   ` Oliver Upton
  11 siblings, 1 reply; 26+ messages in thread
From: Marc Zyngier @ 2024-08-20 10:03 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel, kvm
  Cc: James Morse, Suzuki K Poulose, Oliver Upton, Zenghui Yu,
	Alexander Potapenko

Given how tortuous and fragile the whole lack-of-GICv3 story is,
add a selftest checking that we don't regress it.

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 tools/testing/selftests/kvm/Makefile          |   1 +
 .../selftests/kvm/aarch64/no-vgic-v3.c        | 170 ++++++++++++++++++
 2 files changed, 171 insertions(+)
 create mode 100644 tools/testing/selftests/kvm/aarch64/no-vgic-v3.c

diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile
index 48d32c5aa3eb..f66b37acc0b0 100644
--- a/tools/testing/selftests/kvm/Makefile
+++ b/tools/testing/selftests/kvm/Makefile
@@ -163,6 +163,7 @@ TEST_GEN_PROGS_aarch64 += aarch64/vgic_init
 TEST_GEN_PROGS_aarch64 += aarch64/vgic_irq
 TEST_GEN_PROGS_aarch64 += aarch64/vgic_lpi_stress
 TEST_GEN_PROGS_aarch64 += aarch64/vpmu_counter_access
+TEST_GEN_PROGS_aarch64 += aarch64/no-vgic-v3
 TEST_GEN_PROGS_aarch64 += access_tracking_perf_test
 TEST_GEN_PROGS_aarch64 += arch_timer
 TEST_GEN_PROGS_aarch64 += demand_paging_test
diff --git a/tools/testing/selftests/kvm/aarch64/no-vgic-v3.c b/tools/testing/selftests/kvm/aarch64/no-vgic-v3.c
new file mode 100644
index 000000000000..27169afc94c6
--- /dev/null
+++ b/tools/testing/selftests/kvm/aarch64/no-vgic-v3.c
@@ -0,0 +1,170 @@
+// SPDX-License-Identifier: GPL-2.0
+
+// Check that, on a GICv3 system, not configuring GICv3 correctly
+// results in all of the sysregs generating an UNDEF exception.
+
+#include <test_util.h>
+#include <kvm_util.h>
+#include <processor.h>
+
+static volatile bool handled;
+
+#define __check_sr_read(r)					\
+	do {							\
+		uint64_t val;					\
+								\
+		handled = false;				\
+		dsb(sy);					\
+		val = read_sysreg_s(SYS_ ## r);			\
+		(void)val;					\
+	} while(0)
+
+#define __check_sr_write(r)					\
+	do {							\
+		handled = false;				\
+		dsb(sy);					\
+		write_sysreg_s(0, SYS_ ## r);			\
+		isb();						\
+	} while(0)
+
+/* Fatal checks */
+#define check_sr_read(r)					\
+	do {							\
+		__check_sr_read(r);				\
+		__GUEST_ASSERT(handled, #r " no read trap");	\
+	} while(0)
+
+#define check_sr_write(r)					\
+	do {							\
+		__check_sr_write(r);				\
+		__GUEST_ASSERT(handled, #r " no write trap");	\
+	} while(0)
+
+#define check_sr_rw(r)				\
+	do {					\
+		check_sr_read(r);		\
+		check_sr_write(r);		\
+	} while(0)
+
+/* Non-fatal checks */
+#define check_sr_read_maybe(r)						\
+	do {								\
+		__check_sr_read(r);					\
+		if (!handled)						\
+			GUEST_PRINTF(#r " read not trapping (OK)\n");	\
+	} while(0)
+
+#define check_sr_write_maybe(r)						\
+	do {								\
+		__check_sr_write(r);					\
+		if (!handled)						\
+			GUEST_PRINTF(#r " write not trapping (OK)\n");	\
+	} while(0)
+
+static void guest_code(void)
+{
+	/*
+	 * Check that we advertise that ID_AA64PFR0_EL1.GIC == 0, having
+	 * hidden the feature at runtime without any other userspace action.
+	 */
+	__GUEST_ASSERT(FIELD_GET(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_GIC),
+				 read_sysreg(id_aa64pfr0_el1)) == 0,
+		       "GICv3 wrongly advertised");
+
+	/*
+	 * Access all GICv3 registers, and fail if we don't get an UNDEF.
+	 * Note that we happily access all the APxRn registers without
+	 * checking their existance, as all we want to see is a failure.
+	 */
+	check_sr_rw(ICC_PMR_EL1);
+	check_sr_read(ICC_IAR0_EL1);
+	check_sr_write(ICC_EOIR0_EL1);
+	check_sr_rw(ICC_HPPIR0_EL1);
+	check_sr_rw(ICC_BPR0_EL1);
+	check_sr_rw(ICC_AP0R0_EL1);
+	check_sr_rw(ICC_AP0R1_EL1);
+	check_sr_rw(ICC_AP0R2_EL1);
+	check_sr_rw(ICC_AP0R3_EL1);
+	check_sr_rw(ICC_AP1R0_EL1);
+	check_sr_rw(ICC_AP1R1_EL1);
+	check_sr_rw(ICC_AP1R2_EL1);
+	check_sr_rw(ICC_AP1R3_EL1);
+	check_sr_write(ICC_DIR_EL1);
+	check_sr_read(ICC_RPR_EL1);
+	check_sr_write(ICC_SGI1R_EL1);
+	check_sr_write(ICC_ASGI1R_EL1);
+	check_sr_write(ICC_SGI0R_EL1);
+	check_sr_read(ICC_IAR1_EL1);
+	check_sr_write(ICC_EOIR1_EL1);
+	check_sr_rw(ICC_HPPIR1_EL1);
+	check_sr_rw(ICC_BPR1_EL1);
+	check_sr_rw(ICC_CTLR_EL1);
+	check_sr_rw(ICC_IGRPEN0_EL1);
+	check_sr_rw(ICC_IGRPEN1_EL1);
+
+	/*
+	 * ICC_SRE_EL1 may not be trappable, as ICC_SRE_EL2.Enable can
+	 * be RAO/WI
+	 */
+	check_sr_read_maybe(ICC_SRE_EL1);
+	check_sr_write_maybe(ICC_SRE_EL1);
+
+	GUEST_DONE();
+}
+
+static void guest_undef_handler(struct ex_regs *regs)
+{
+	/* Success, we've gracefully exploded! */
+	handled = true;
+	regs->pc += 4;
+}
+
+static void test_guest_no_gicv3(void)
+{
+	struct kvm_vcpu *vcpu;
+	struct kvm_vm *vm;
+	struct ucall uc;
+
+	/* Create a VM without a GICv3 */
+	vm = vm_create_with_one_vcpu(&vcpu, guest_code);
+
+	vm_init_descriptor_tables(vm);
+	vcpu_init_descriptor_tables(vcpu);
+
+	vm_install_sync_handler(vm, VECTOR_SYNC_CURRENT,
+				ESR_EC_UNKNOWN, guest_undef_handler);
+again:
+	vcpu_run(vcpu);
+
+	switch (get_ucall(vcpu, &uc)) {
+	case UCALL_ABORT:
+		REPORT_GUEST_ASSERT(uc);
+		break;
+	case UCALL_PRINTF:
+		printf("%s", uc.buffer);
+		goto again;
+	case UCALL_DONE:
+		break;
+	default:
+		TEST_FAIL("Unknown ucall %lu", uc.cmd);
+	}
+
+	kvm_vm_free(vm);
+}
+
+int main(int argc, char *argv[])
+{
+	struct kvm_vcpu *vcpu;
+	struct kvm_vm *vm;
+	uint64_t pfr0;
+
+	vm = vm_create_with_one_vcpu(&vcpu, NULL);
+	vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_ID_AA64PFR0_EL1), &pfr0);
+	__TEST_REQUIRE(FIELD_GET(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_GIC), pfr0),
+		       "GICv3 not supported.");
+	kvm_vm_free(vm);
+
+	test_guest_no_gicv3();
+
+	return 0;
+}
-- 
2.39.2



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

* Re: [PATCH 01/12] KVM: arm64: Make ICC_*SGI*_EL1 undef in the absence of a vGICv3
  2024-08-20 10:03 ` [PATCH 01/12] KVM: arm64: Make ICC_*SGI*_EL1 undef in the absence of a vGICv3 Marc Zyngier
@ 2024-08-20 21:46   ` Oliver Upton
  2024-08-21 10:59     ` Marc Zyngier
  2024-08-22  8:15   ` (subset) " Oliver Upton
  1 sibling, 1 reply; 26+ messages in thread
From: Oliver Upton @ 2024-08-20 21:46 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: kvmarm, linux-arm-kernel, kvm, James Morse, Suzuki K Poulose,
	Zenghui Yu, Alexander Potapenko, stable

On Tue, Aug 20, 2024 at 11:03:38AM +0100, Marc Zyngier wrote:
> On a system with a GICv3, if a guest hasn't been configured with
> GICv3 and that the host is not capable of GICv2 emulation,
> a write to any of the ICC_*SGI*_EL1 registers is trapped to EL2.
> 
> We therefore try to emulate the SGI access, only to hit a NULL
> pointer as no private interrupt is allocated (no GIC, remember?).
> 
> The obvious fix is to give the guest what it deserves, in the
> shape of a UNDEF exception.
> 
> Reported-by: Alexander Potapenko <glider@google.com>
> Signed-off-by: Marc Zyngier <maz@kernel.org>
> Cc: stable@vger.kernel.org

LGTM, and just as an FYI I do plan on grabbing this for 6.11

-- 
Thanks,
Oliver


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

* Re: [PATCH 03/12] KVM: arm64: Force SRE traps when SRE access is not enabled
  2024-08-20 10:03 ` [PATCH 03/12] KVM: arm64: Force SRE traps when SRE access is not enabled Marc Zyngier
@ 2024-08-20 23:19   ` Oliver Upton
  2024-08-21 11:05     ` Marc Zyngier
  0 siblings, 1 reply; 26+ messages in thread
From: Oliver Upton @ 2024-08-20 23:19 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: kvmarm, linux-arm-kernel, kvm, James Morse, Suzuki K Poulose,
	Zenghui Yu, Alexander Potapenko

Hey,

On Tue, Aug 20, 2024 at 11:03:40AM +0100, Marc Zyngier wrote:
> We so far only write the ICH_HCR_EL2 config in two situations:
> 
> - when we need to emulate the GICv3 CPU interface due to HW bugs
> 
> - when we do direct injection, as the virtual CPU interface needs
>   to be enabled
> 
> This is all good. But it also means that we don't do anything special
> when we emulate a GICv2, or that there is no GIC at all.
> 
> What happens in this case when the guest uses the GICv3 system
> registers? The *guest* gets a trap for a sysreg access (EC=0x18)
> while we'd really like it to get an UNDEF.
> 
> Fixing this is a bit involved:
> 
> - we need to set all the required trap bits (TC, TALL0, TALL1, TDIR)
> 
> - for these traps to take effect, we need to (counter-intuitively)
>   set ICC_SRE_EL1.SRE to 1 so that the above traps take priority.
> 
> Note that doesn't fully work when GICv2 emulation is enabled, as
> we cannot set ICC_SRE_EL1.SRE to 1 (it breaks Group0 delivery as
> IRQ).

Just to make sure I'm following completely, GICv2-on-GICv3 guest sees
the (barf) architected behavior of sysreg traps going to EL1.

> Signed-off-by: Marc Zyngier <maz@kernel.org>
> ---
>  arch/arm64/kvm/hyp/vgic-v3-sr.c | 22 ++++++++++++++++------
>  arch/arm64/kvm/vgic/vgic-v3.c   |  5 ++++-
>  2 files changed, 20 insertions(+), 7 deletions(-)
> 
> diff --git a/arch/arm64/kvm/hyp/vgic-v3-sr.c b/arch/arm64/kvm/hyp/vgic-v3-sr.c
> index 7b397fad26f2..a184def8f5ad 100644
> --- a/arch/arm64/kvm/hyp/vgic-v3-sr.c
> +++ b/arch/arm64/kvm/hyp/vgic-v3-sr.c
> @@ -268,8 +268,16 @@ void __vgic_v3_activate_traps(struct vgic_v3_cpu_if *cpu_if)
>  	 * starting to mess with the rest of the GIC, and VMCR_EL2 in
>  	 * particular.  This logic must be called before
>  	 * __vgic_v3_restore_state().
> +	 *
> +	 * However, if the vgic is disabled (ICH_HCR_EL2.EN==0), no GIC is
> +	 * provisionned at all. In order to prevent illegal accesses to the

typo: provisioned

> +	 * system registers to trap to EL1 (duh), force ICC_SRE_EL1.SRE to 1
> +	 * so that the trap bits can take effect. Yes, we *loves* the GIC.
>  	 */
> -	if (!cpu_if->vgic_sre) {
> +	if (!(cpu_if->vgic_hcr & ICH_HCR_EN)) {
> +		write_gicreg(ICC_SRE_EL1_SRE, ICC_SRE_EL1);
> +		isb();
> +	} else if (!cpu_if->vgic_sre) {
>  		write_gicreg(0, ICC_SRE_EL1);
>  		isb();
>  		write_gicreg(cpu_if->vgic_vmcr, ICH_VMCR_EL2);
> @@ -288,8 +296,9 @@ void __vgic_v3_activate_traps(struct vgic_v3_cpu_if *cpu_if)
>  	}
>  
>  	/*
> -	 * Prevent the guest from touching the GIC system registers if
> -	 * SRE isn't enabled for GICv3 emulation.
> +	 * Prevent the guest from touching the ICC_SRE_EL1 system
> +	 * register. Note that this may not have any effect, as
> +	 * ICC_SRE_EL2.Enable being RAO/WI is a valid implementation.

So this behavior is weird but still 'safe' as, ICC_SRE_EL1.SRE is also RAO/WI
and the HCR traps are still effective. Right?

>  	 */
>  	write_gicreg(read_gicreg(ICC_SRE_EL2) & ~ICC_SRE_EL2_ENABLE,
>  		     ICC_SRE_EL2);
> @@ -297,10 +306,11 @@ void __vgic_v3_activate_traps(struct vgic_v3_cpu_if *cpu_if)
>  	/*
>  	 * If we need to trap system registers, we must write
>  	 * ICH_HCR_EL2 anyway, even if no interrupts are being
> -	 * injected,
> +	 * injected. Note that this also applies if we don't expect
> +	 * any system register access (GICv2 or no vgic at all).

We don't expect the traps to come in the GICv2 case, though, right?

Looks alright to me otherwise, but blech!

-- 
Thanks,
Oliver


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

* Re: [PATCH 04/12] KVM: arm64: Force GICv3 traps activa when no irqchip is configured on VHE
  2024-08-20 10:03 ` [PATCH 04/12] KVM: arm64: Force GICv3 traps activa when no irqchip is configured on VHE Marc Zyngier
@ 2024-08-20 23:33   ` Oliver Upton
  2024-08-21 11:13     ` Marc Zyngier
  0 siblings, 1 reply; 26+ messages in thread
From: Oliver Upton @ 2024-08-20 23:33 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: kvmarm, linux-arm-kernel, kvm, James Morse, Suzuki K Poulose,
	Zenghui Yu, Alexander Potapenko

s/activa/active/

On Tue, Aug 20, 2024 at 11:03:41AM +0100, Marc Zyngier wrote:
> On a VHE system, no GICv3 traps get configured when no irqchip is
> present. This is not quite matching the "no GICv3" semantics that
> we want to present.
> 
> Force such traps to be configured in this case.
> 
> Signed-off-by: Marc Zyngier <maz@kernel.org>
> ---
>  arch/arm64/kvm/vgic/vgic.c | 14 ++++++++++----
>  1 file changed, 10 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
> index 974849ea7101..2caa64415ff3 100644
> --- a/arch/arm64/kvm/vgic/vgic.c
> +++ b/arch/arm64/kvm/vgic/vgic.c
> @@ -917,10 +917,13 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
>  
>  void kvm_vgic_load(struct kvm_vcpu *vcpu)
>  {
> -	if (unlikely(!vgic_initialized(vcpu->kvm)))
> +	if (unlikely(!irqchip_in_kernel(vcpu->kvm) || !vgic_initialized(vcpu->kvm))) {

Doesn't !vgic_initialized(vcpu->kvm) also cover the case of no irqchip
in kernel?

-- 
Thanks,
Oliver


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

* Re: [PATCH 06/12] KVM: arm64: Zero ID_AA64PFR0_EL1.GIC when no GICv3 is presented to the guest
  2024-08-20 10:03 ` [PATCH 06/12] KVM: arm64: Zero ID_AA64PFR0_EL1.GIC when no GICv3 is presented to the guest Marc Zyngier
@ 2024-08-20 23:50   ` Oliver Upton
  2024-08-21 11:16     ` Marc Zyngier
  0 siblings, 1 reply; 26+ messages in thread
From: Oliver Upton @ 2024-08-20 23:50 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: kvmarm, linux-arm-kernel, kvm, James Morse, Suzuki K Poulose,
	Zenghui Yu, Alexander Potapenko

On Tue, Aug 20, 2024 at 11:03:43AM +0100, Marc Zyngier wrote:
> In order to be consistent, we shouldn't advertise a GICv3 when none
> is actually usable by the guest.
> 
> Wipe the feature when these conditions apply, and allow the field
> to be written from userspace.
> 
> Signed-off-by: Marc Zyngier <maz@kernel.org>
> ---
>  arch/arm64/kvm/sys_regs.c | 6 +++++-
>  1 file changed, 5 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index bc2d54da3827..7d00d7e359e1 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -2365,7 +2365,6 @@ static const struct sys_reg_desc sys_reg_descs[] = {
>  		   ID_AA64PFR0_EL1_MPAM |
>  		   ID_AA64PFR0_EL1_SVE |
>  		   ID_AA64PFR0_EL1_RAS |
> -		   ID_AA64PFR0_EL1_GIC |
>  		   ID_AA64PFR0_EL1_AdvSIMD |
>  		   ID_AA64PFR0_EL1_FP), },
>  	ID_SANITISED(ID_AA64PFR1_EL1),
> @@ -4634,6 +4633,11 @@ int kvm_finalize_sys_regs(struct kvm_vcpu *vcpu)
>  
>  	guard(mutex)(&kvm->arch.config_lock);
>  
> +	if (!kvm_has_gicv3(kvm)) {
> +		kvm->arch.id_regs[IDREG_IDX(SYS_ID_AA64PFR0_EL1)] &= ~ID_AA64PFR0_EL1_GIC_MASK;
> +		kvm->arch.id_regs[IDREG_IDX(SYS_ID_PFR1_EL1)] &= ~ID_PFR1_EL1_GIC_MASK;
> +	}
> +

Hmm, should we use the ID register field as the source of truth for
kvm_has_gicv3() at this point?

I think what you have in patch #1 makes good sense for a stable
backport. Using the ID register from this point forward would make the
behavior consistent for a stupid userspace instantiated GICv3 for the VM
but clobbered it from the ID register.

AFAICT all other usage of kvm_has_gicv3() happens after
kvm_finalize_sys_regs(), so it should take this last-minute fixup into
account.

-- 
Thanks,
Oliver


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

* Re: [PATCH 12/12] KVM: arm64: Add selftest checking how the absence of GICv3 is handled
  2024-08-20 10:03 ` [PATCH 12/12] KVM: arm64: Add selftest checking how the absence of GICv3 is handled Marc Zyngier
@ 2024-08-21  0:10   ` Oliver Upton
  2024-08-21 11:17     ` Marc Zyngier
  0 siblings, 1 reply; 26+ messages in thread
From: Oliver Upton @ 2024-08-21  0:10 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: kvmarm, linux-arm-kernel, kvm, James Morse, Suzuki K Poulose,
	Zenghui Yu, Alexander Potapenko

On Tue, Aug 20, 2024 at 11:03:49AM +0100, Marc Zyngier wrote:
> Given how tortuous and fragile the whole lack-of-GICv3 story is,
> add a selftest checking that we don't regress it.
> 
> Signed-off-by: Marc Zyngier <maz@kernel.org>
> ---
>  tools/testing/selftests/kvm/Makefile          |   1 +
>  .../selftests/kvm/aarch64/no-vgic-v3.c        | 170 ++++++++++++++++++
>  2 files changed, 171 insertions(+)
>  create mode 100644 tools/testing/selftests/kvm/aarch64/no-vgic-v3.c
> 
> diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile
> index 48d32c5aa3eb..f66b37acc0b0 100644
> --- a/tools/testing/selftests/kvm/Makefile
> +++ b/tools/testing/selftests/kvm/Makefile
> @@ -163,6 +163,7 @@ TEST_GEN_PROGS_aarch64 += aarch64/vgic_init
>  TEST_GEN_PROGS_aarch64 += aarch64/vgic_irq
>  TEST_GEN_PROGS_aarch64 += aarch64/vgic_lpi_stress
>  TEST_GEN_PROGS_aarch64 += aarch64/vpmu_counter_access
> +TEST_GEN_PROGS_aarch64 += aarch64/no-vgic-v3
>  TEST_GEN_PROGS_aarch64 += access_tracking_perf_test
>  TEST_GEN_PROGS_aarch64 += arch_timer
>  TEST_GEN_PROGS_aarch64 += demand_paging_test
> diff --git a/tools/testing/selftests/kvm/aarch64/no-vgic-v3.c b/tools/testing/selftests/kvm/aarch64/no-vgic-v3.c
> new file mode 100644
> index 000000000000..27169afc94c6
> --- /dev/null
> +++ b/tools/testing/selftests/kvm/aarch64/no-vgic-v3.c
> @@ -0,0 +1,170 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +// Check that, on a GICv3 system, not configuring GICv3 correctly
> +// results in all of the sysregs generating an UNDEF exception.
> +
> +#include <test_util.h>
> +#include <kvm_util.h>
> +#include <processor.h>
> +
> +static volatile bool handled;
> +
> +#define __check_sr_read(r)					\
> +	do {							\
> +		uint64_t val;					\
> +								\
> +		handled = false;				\
> +		dsb(sy);					\
> +		val = read_sysreg_s(SYS_ ## r);			\
> +		(void)val;					\
> +	} while(0)
> +
> +#define __check_sr_write(r)					\
> +	do {							\
> +		handled = false;				\
> +		dsb(sy);					\
> +		write_sysreg_s(0, SYS_ ## r);			\
> +		isb();						\
> +	} while(0)
> +
> +/* Fatal checks */
> +#define check_sr_read(r)					\
> +	do {							\
> +		__check_sr_read(r);				\
> +		__GUEST_ASSERT(handled, #r " no read trap");	\
> +	} while(0)
> +
> +#define check_sr_write(r)					\
> +	do {							\
> +		__check_sr_write(r);				\
> +		__GUEST_ASSERT(handled, #r " no write trap");	\
> +	} while(0)
> +
> +#define check_sr_rw(r)				\
> +	do {					\
> +		check_sr_read(r);		\
> +		check_sr_write(r);		\
> +	} while(0)
> +
> +/* Non-fatal checks */
> +#define check_sr_read_maybe(r)						\
> +	do {								\
> +		__check_sr_read(r);					\
> +		if (!handled)						\
> +			GUEST_PRINTF(#r " read not trapping (OK)\n");	\
> +	} while(0)
> +
> +#define check_sr_write_maybe(r)						\
> +	do {								\
> +		__check_sr_write(r);					\
> +		if (!handled)						\
> +			GUEST_PRINTF(#r " write not trapping (OK)\n");	\
> +	} while(0)
> +
> +static void guest_code(void)
> +{
> +	/*
> +	 * Check that we advertise that ID_AA64PFR0_EL1.GIC == 0, having
> +	 * hidden the feature at runtime without any other userspace action.
> +	 */
> +	__GUEST_ASSERT(FIELD_GET(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_GIC),
> +				 read_sysreg(id_aa64pfr0_el1)) == 0,
> +		       "GICv3 wrongly advertised");
> +
> +	/*
> +	 * Access all GICv3 registers, and fail if we don't get an UNDEF.
> +	 * Note that we happily access all the APxRn registers without
> +	 * checking their existance, as all we want to see is a failure.
> +	 */
> +	check_sr_rw(ICC_PMR_EL1);
> +	check_sr_read(ICC_IAR0_EL1);
> +	check_sr_write(ICC_EOIR0_EL1);
> +	check_sr_rw(ICC_HPPIR0_EL1);
> +	check_sr_rw(ICC_BPR0_EL1);
> +	check_sr_rw(ICC_AP0R0_EL1);
> +	check_sr_rw(ICC_AP0R1_EL1);
> +	check_sr_rw(ICC_AP0R2_EL1);
> +	check_sr_rw(ICC_AP0R3_EL1);
> +	check_sr_rw(ICC_AP1R0_EL1);
> +	check_sr_rw(ICC_AP1R1_EL1);
> +	check_sr_rw(ICC_AP1R2_EL1);
> +	check_sr_rw(ICC_AP1R3_EL1);
> +	check_sr_write(ICC_DIR_EL1);
> +	check_sr_read(ICC_RPR_EL1);
> +	check_sr_write(ICC_SGI1R_EL1);
> +	check_sr_write(ICC_ASGI1R_EL1);
> +	check_sr_write(ICC_SGI0R_EL1);
> +	check_sr_read(ICC_IAR1_EL1);
> +	check_sr_write(ICC_EOIR1_EL1);
> +	check_sr_rw(ICC_HPPIR1_EL1);
> +	check_sr_rw(ICC_BPR1_EL1);
> +	check_sr_rw(ICC_CTLR_EL1);
> +	check_sr_rw(ICC_IGRPEN0_EL1);
> +	check_sr_rw(ICC_IGRPEN1_EL1);
> +
> +	/*
> +	 * ICC_SRE_EL1 may not be trappable, as ICC_SRE_EL2.Enable can
> +	 * be RAO/WI
> +	 */
> +	check_sr_read_maybe(ICC_SRE_EL1);
> +	check_sr_write_maybe(ICC_SRE_EL1);

In the case that a write does not UNDEF, should we check that
ICC_SRE_EL1.SRE is also RAO/WI?

-- 
Thanks,
Oliver


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

* Re: [PATCH 01/12] KVM: arm64: Make ICC_*SGI*_EL1 undef in the absence of a vGICv3
  2024-08-20 21:46   ` Oliver Upton
@ 2024-08-21 10:59     ` Marc Zyngier
  2024-08-21 16:53       ` Oliver Upton
  0 siblings, 1 reply; 26+ messages in thread
From: Marc Zyngier @ 2024-08-21 10:59 UTC (permalink / raw)
  To: Oliver Upton
  Cc: kvmarm, linux-arm-kernel, kvm, James Morse, Suzuki K Poulose,
	Zenghui Yu, Alexander Potapenko, stable

On Tue, 20 Aug 2024 22:46:30 +0100,
Oliver Upton <oliver.upton@linux.dev> wrote:
> 
> On Tue, Aug 20, 2024 at 11:03:38AM +0100, Marc Zyngier wrote:
> > On a system with a GICv3, if a guest hasn't been configured with
> > GICv3 and that the host is not capable of GICv2 emulation,
> > a write to any of the ICC_*SGI*_EL1 registers is trapped to EL2.
> > 
> > We therefore try to emulate the SGI access, only to hit a NULL
> > pointer as no private interrupt is allocated (no GIC, remember?).
> > 
> > The obvious fix is to give the guest what it deserves, in the
> > shape of a UNDEF exception.
> > 
> > Reported-by: Alexander Potapenko <glider@google.com>
> > Signed-off-by: Marc Zyngier <maz@kernel.org>
> > Cc: stable@vger.kernel.org
> 
> LGTM, and just as an FYI I do plan on grabbing this for 6.11

Great, thanks. Are you planning to route this via arm64, given that
Paolo is away for a bit?

	M.

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


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

* Re: [PATCH 03/12] KVM: arm64: Force SRE traps when SRE access is not enabled
  2024-08-20 23:19   ` Oliver Upton
@ 2024-08-21 11:05     ` Marc Zyngier
  0 siblings, 0 replies; 26+ messages in thread
From: Marc Zyngier @ 2024-08-21 11:05 UTC (permalink / raw)
  To: Oliver Upton
  Cc: kvmarm, linux-arm-kernel, kvm, James Morse, Suzuki K Poulose,
	Zenghui Yu, Alexander Potapenko

On Wed, 21 Aug 2024 00:19:32 +0100,
Oliver Upton <oliver.upton@linux.dev> wrote:
> 
> Hey,
> 
> On Tue, Aug 20, 2024 at 11:03:40AM +0100, Marc Zyngier wrote:
> > We so far only write the ICH_HCR_EL2 config in two situations:
> > 
> > - when we need to emulate the GICv3 CPU interface due to HW bugs
> > 
> > - when we do direct injection, as the virtual CPU interface needs
> >   to be enabled
> > 
> > This is all good. But it also means that we don't do anything special
> > when we emulate a GICv2, or that there is no GIC at all.
> > 
> > What happens in this case when the guest uses the GICv3 system
> > registers? The *guest* gets a trap for a sysreg access (EC=0x18)
> > while we'd really like it to get an UNDEF.
> > 
> > Fixing this is a bit involved:
> > 
> > - we need to set all the required trap bits (TC, TALL0, TALL1, TDIR)
> > 
> > - for these traps to take effect, we need to (counter-intuitively)
> >   set ICC_SRE_EL1.SRE to 1 so that the above traps take priority.
> > 
> > Note that doesn't fully work when GICv2 emulation is enabled, as
> > we cannot set ICC_SRE_EL1.SRE to 1 (it breaks Group0 delivery as
> > IRQ).
> 
> Just to make sure I'm following completely, GICv2-on-GICv3 guest sees
> the (barf) architected behavior of sysreg traps going to EL1.

Indeed. There isn't anything we can do about that, short of changing
the behaviour of GICv2 emulation. I'll add something to that effect in
the commit message.

> 
> > Signed-off-by: Marc Zyngier <maz@kernel.org>
> > ---
> >  arch/arm64/kvm/hyp/vgic-v3-sr.c | 22 ++++++++++++++++------
> >  arch/arm64/kvm/vgic/vgic-v3.c   |  5 ++++-
> >  2 files changed, 20 insertions(+), 7 deletions(-)
> > 
> > diff --git a/arch/arm64/kvm/hyp/vgic-v3-sr.c b/arch/arm64/kvm/hyp/vgic-v3-sr.c
> > index 7b397fad26f2..a184def8f5ad 100644
> > --- a/arch/arm64/kvm/hyp/vgic-v3-sr.c
> > +++ b/arch/arm64/kvm/hyp/vgic-v3-sr.c
> > @@ -268,8 +268,16 @@ void __vgic_v3_activate_traps(struct vgic_v3_cpu_if *cpu_if)
> >  	 * starting to mess with the rest of the GIC, and VMCR_EL2 in
> >  	 * particular.  This logic must be called before
> >  	 * __vgic_v3_restore_state().
> > +	 *
> > +	 * However, if the vgic is disabled (ICH_HCR_EL2.EN==0), no GIC is
> > +	 * provisionned at all. In order to prevent illegal accesses to the
> 
> typo: provisioned
> 
> > +	 * system registers to trap to EL1 (duh), force ICC_SRE_EL1.SRE to 1
> > +	 * so that the trap bits can take effect. Yes, we *loves* the GIC.
> >  	 */
> > -	if (!cpu_if->vgic_sre) {
> > +	if (!(cpu_if->vgic_hcr & ICH_HCR_EN)) {
> > +		write_gicreg(ICC_SRE_EL1_SRE, ICC_SRE_EL1);
> > +		isb();
> > +	} else if (!cpu_if->vgic_sre) {
> >  		write_gicreg(0, ICC_SRE_EL1);
> >  		isb();
> >  		write_gicreg(cpu_if->vgic_vmcr, ICH_VMCR_EL2);
> > @@ -288,8 +296,9 @@ void __vgic_v3_activate_traps(struct vgic_v3_cpu_if *cpu_if)
> >  	}
> >  
> >  	/*
> > -	 * Prevent the guest from touching the GIC system registers if
> > -	 * SRE isn't enabled for GICv3 emulation.
> > +	 * Prevent the guest from touching the ICC_SRE_EL1 system
> > +	 * register. Note that this may not have any effect, as
> > +	 * ICC_SRE_EL2.Enable being RAO/WI is a valid implementation.
> 
> So this behavior is weird but still 'safe' as, ICC_SRE_EL1.SRE is also RAO/WI
> and the HCR traps are still effective. Right?

Exactly. All the traps are working, *except* for ICC_SRE_EL1 itself. A
guest can then infer that it runs under a hypervisor, but not much more.

> 
> >  	 */
> >  	write_gicreg(read_gicreg(ICC_SRE_EL2) & ~ICC_SRE_EL2_ENABLE,
> >  		     ICC_SRE_EL2);
> > @@ -297,10 +306,11 @@ void __vgic_v3_activate_traps(struct vgic_v3_cpu_if *cpu_if)
> >  	/*
> >  	 * If we need to trap system registers, we must write
> >  	 * ICH_HCR_EL2 anyway, even if no interrupts are being
> > -	 * injected,
> > +	 * injected. Note that this also applies if we don't expect
> > +	 * any system register access (GICv2 or no vgic at all).
> 
> We don't expect the traps to come in the GICv2 case, though, right?

Yup. I'll fix the comment, as it is misleading.

> Looks alright to me otherwise, but blech!

Yeah. It's the sort of code that makes you feel dirty just looking at
it.

Thanks,

	M.

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


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

* Re: [PATCH 04/12] KVM: arm64: Force GICv3 traps activa when no irqchip is configured on VHE
  2024-08-20 23:33   ` Oliver Upton
@ 2024-08-21 11:13     ` Marc Zyngier
  2024-08-21 16:52       ` Oliver Upton
  0 siblings, 1 reply; 26+ messages in thread
From: Marc Zyngier @ 2024-08-21 11:13 UTC (permalink / raw)
  To: Oliver Upton
  Cc: kvmarm, linux-arm-kernel, kvm, James Morse, Suzuki K Poulose,
	Zenghui Yu, Alexander Potapenko

On Wed, 21 Aug 2024 00:33:40 +0100,
Oliver Upton <oliver.upton@linux.dev> wrote:
> 
> s/activa/active/
> 
> On Tue, Aug 20, 2024 at 11:03:41AM +0100, Marc Zyngier wrote:
> > On a VHE system, no GICv3 traps get configured when no irqchip is
> > present. This is not quite matching the "no GICv3" semantics that
> > we want to present.
> > 
> > Force such traps to be configured in this case.
> > 
> > Signed-off-by: Marc Zyngier <maz@kernel.org>
> > ---
> >  arch/arm64/kvm/vgic/vgic.c | 14 ++++++++++----
> >  1 file changed, 10 insertions(+), 4 deletions(-)
> > 
> > diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
> > index 974849ea7101..2caa64415ff3 100644
> > --- a/arch/arm64/kvm/vgic/vgic.c
> > +++ b/arch/arm64/kvm/vgic/vgic.c
> > @@ -917,10 +917,13 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
> >  
> >  void kvm_vgic_load(struct kvm_vcpu *vcpu)
> >  {
> > -	if (unlikely(!vgic_initialized(vcpu->kvm)))
> > +	if (unlikely(!irqchip_in_kernel(vcpu->kvm) || !vgic_initialized(vcpu->kvm))) {
> 
> Doesn't !vgic_initialized(vcpu->kvm) also cover the case of no irqchip
> in kernel?

It does, but that's purely accidental. I can drop that, but it is
really fragile.

Thanks,

	M.

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


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

* Re: [PATCH 06/12] KVM: arm64: Zero ID_AA64PFR0_EL1.GIC when no GICv3 is presented to the guest
  2024-08-20 23:50   ` Oliver Upton
@ 2024-08-21 11:16     ` Marc Zyngier
  0 siblings, 0 replies; 26+ messages in thread
From: Marc Zyngier @ 2024-08-21 11:16 UTC (permalink / raw)
  To: Oliver Upton
  Cc: kvmarm, linux-arm-kernel, kvm, James Morse, Suzuki K Poulose,
	Zenghui Yu, Alexander Potapenko

On Wed, 21 Aug 2024 00:50:18 +0100,
Oliver Upton <oliver.upton@linux.dev> wrote:
> 
> On Tue, Aug 20, 2024 at 11:03:43AM +0100, Marc Zyngier wrote:
> > In order to be consistent, we shouldn't advertise a GICv3 when none
> > is actually usable by the guest.
> > 
> > Wipe the feature when these conditions apply, and allow the field
> > to be written from userspace.
> > 
> > Signed-off-by: Marc Zyngier <maz@kernel.org>
> > ---
> >  arch/arm64/kvm/sys_regs.c | 6 +++++-
> >  1 file changed, 5 insertions(+), 1 deletion(-)
> > 
> > diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> > index bc2d54da3827..7d00d7e359e1 100644
> > --- a/arch/arm64/kvm/sys_regs.c
> > +++ b/arch/arm64/kvm/sys_regs.c
> > @@ -2365,7 +2365,6 @@ static const struct sys_reg_desc sys_reg_descs[] = {
> >  		   ID_AA64PFR0_EL1_MPAM |
> >  		   ID_AA64PFR0_EL1_SVE |
> >  		   ID_AA64PFR0_EL1_RAS |
> > -		   ID_AA64PFR0_EL1_GIC |
> >  		   ID_AA64PFR0_EL1_AdvSIMD |
> >  		   ID_AA64PFR0_EL1_FP), },
> >  	ID_SANITISED(ID_AA64PFR1_EL1),
> > @@ -4634,6 +4633,11 @@ int kvm_finalize_sys_regs(struct kvm_vcpu *vcpu)
> >  
> >  	guard(mutex)(&kvm->arch.config_lock);
> >  
> > +	if (!kvm_has_gicv3(kvm)) {
> > +		kvm->arch.id_regs[IDREG_IDX(SYS_ID_AA64PFR0_EL1)] &= ~ID_AA64PFR0_EL1_GIC_MASK;
> > +		kvm->arch.id_regs[IDREG_IDX(SYS_ID_PFR1_EL1)] &= ~ID_PFR1_EL1_GIC_MASK;
> > +	}
> > +
> 
> Hmm, should we use the ID register field as the source of truth for
> kvm_has_gicv3() at this point?
> 
> I think what you have in patch #1 makes good sense for a stable
> backport. Using the ID register from this point forward would make the
> behavior consistent for a stupid userspace instantiated GICv3 for the VM
> but clobbered it from the ID register.
> 
> AFAICT all other usage of kvm_has_gicv3() happens after
> kvm_finalize_sys_regs(), so it should take this last-minute fixup into
> account.

Right, so changing the definition of kvm_has_gicv3() in this patch,
and using the "old" definition here only. Yup, this seems like a
reasonable thing to do.

Thanks,

	M.

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


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

* Re: [PATCH 12/12] KVM: arm64: Add selftest checking how the absence of GICv3 is handled
  2024-08-21  0:10   ` Oliver Upton
@ 2024-08-21 11:17     ` Marc Zyngier
  0 siblings, 0 replies; 26+ messages in thread
From: Marc Zyngier @ 2024-08-21 11:17 UTC (permalink / raw)
  To: Oliver Upton
  Cc: kvmarm, linux-arm-kernel, kvm, James Morse, Suzuki K Poulose,
	Zenghui Yu, Alexander Potapenko

On Wed, 21 Aug 2024 01:10:23 +0100,
Oliver Upton <oliver.upton@linux.dev> wrote:
> 
> On Tue, Aug 20, 2024 at 11:03:49AM +0100, Marc Zyngier wrote:
> > Given how tortuous and fragile the whole lack-of-GICv3 story is,
> > add a selftest checking that we don't regress it.
> > 
> > Signed-off-by: Marc Zyngier <maz@kernel.org>
> > ---
> >  tools/testing/selftests/kvm/Makefile          |   1 +
> >  .../selftests/kvm/aarch64/no-vgic-v3.c        | 170 ++++++++++++++++++
> >  2 files changed, 171 insertions(+)
> >  create mode 100644 tools/testing/selftests/kvm/aarch64/no-vgic-v3.c
> > 
> > diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile
> > index 48d32c5aa3eb..f66b37acc0b0 100644
> > --- a/tools/testing/selftests/kvm/Makefile
> > +++ b/tools/testing/selftests/kvm/Makefile
> > @@ -163,6 +163,7 @@ TEST_GEN_PROGS_aarch64 += aarch64/vgic_init
> >  TEST_GEN_PROGS_aarch64 += aarch64/vgic_irq
> >  TEST_GEN_PROGS_aarch64 += aarch64/vgic_lpi_stress
> >  TEST_GEN_PROGS_aarch64 += aarch64/vpmu_counter_access
> > +TEST_GEN_PROGS_aarch64 += aarch64/no-vgic-v3
> >  TEST_GEN_PROGS_aarch64 += access_tracking_perf_test
> >  TEST_GEN_PROGS_aarch64 += arch_timer
> >  TEST_GEN_PROGS_aarch64 += demand_paging_test
> > diff --git a/tools/testing/selftests/kvm/aarch64/no-vgic-v3.c b/tools/testing/selftests/kvm/aarch64/no-vgic-v3.c
> > new file mode 100644
> > index 000000000000..27169afc94c6
> > --- /dev/null
> > +++ b/tools/testing/selftests/kvm/aarch64/no-vgic-v3.c
> > @@ -0,0 +1,170 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +
> > +// Check that, on a GICv3 system, not configuring GICv3 correctly
> > +// results in all of the sysregs generating an UNDEF exception.
> > +
> > +#include <test_util.h>
> > +#include <kvm_util.h>
> > +#include <processor.h>
> > +
> > +static volatile bool handled;
> > +
> > +#define __check_sr_read(r)					\
> > +	do {							\
> > +		uint64_t val;					\
> > +								\
> > +		handled = false;				\
> > +		dsb(sy);					\
> > +		val = read_sysreg_s(SYS_ ## r);			\
> > +		(void)val;					\
> > +	} while(0)
> > +
> > +#define __check_sr_write(r)					\
> > +	do {							\
> > +		handled = false;				\
> > +		dsb(sy);					\
> > +		write_sysreg_s(0, SYS_ ## r);			\
> > +		isb();						\
> > +	} while(0)
> > +
> > +/* Fatal checks */
> > +#define check_sr_read(r)					\
> > +	do {							\
> > +		__check_sr_read(r);				\
> > +		__GUEST_ASSERT(handled, #r " no read trap");	\
> > +	} while(0)
> > +
> > +#define check_sr_write(r)					\
> > +	do {							\
> > +		__check_sr_write(r);				\
> > +		__GUEST_ASSERT(handled, #r " no write trap");	\
> > +	} while(0)
> > +
> > +#define check_sr_rw(r)				\
> > +	do {					\
> > +		check_sr_read(r);		\
> > +		check_sr_write(r);		\
> > +	} while(0)
> > +
> > +/* Non-fatal checks */
> > +#define check_sr_read_maybe(r)						\
> > +	do {								\
> > +		__check_sr_read(r);					\
> > +		if (!handled)						\
> > +			GUEST_PRINTF(#r " read not trapping (OK)\n");	\
> > +	} while(0)
> > +
> > +#define check_sr_write_maybe(r)						\
> > +	do {								\
> > +		__check_sr_write(r);					\
> > +		if (!handled)						\
> > +			GUEST_PRINTF(#r " write not trapping (OK)\n");	\
> > +	} while(0)
> > +
> > +static void guest_code(void)
> > +{
> > +	/*
> > +	 * Check that we advertise that ID_AA64PFR0_EL1.GIC == 0, having
> > +	 * hidden the feature at runtime without any other userspace action.
> > +	 */
> > +	__GUEST_ASSERT(FIELD_GET(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_GIC),
> > +				 read_sysreg(id_aa64pfr0_el1)) == 0,
> > +		       "GICv3 wrongly advertised");
> > +
> > +	/*
> > +	 * Access all GICv3 registers, and fail if we don't get an UNDEF.
> > +	 * Note that we happily access all the APxRn registers without
> > +	 * checking their existance, as all we want to see is a failure.
> > +	 */
> > +	check_sr_rw(ICC_PMR_EL1);
> > +	check_sr_read(ICC_IAR0_EL1);
> > +	check_sr_write(ICC_EOIR0_EL1);
> > +	check_sr_rw(ICC_HPPIR0_EL1);
> > +	check_sr_rw(ICC_BPR0_EL1);
> > +	check_sr_rw(ICC_AP0R0_EL1);
> > +	check_sr_rw(ICC_AP0R1_EL1);
> > +	check_sr_rw(ICC_AP0R2_EL1);
> > +	check_sr_rw(ICC_AP0R3_EL1);
> > +	check_sr_rw(ICC_AP1R0_EL1);
> > +	check_sr_rw(ICC_AP1R1_EL1);
> > +	check_sr_rw(ICC_AP1R2_EL1);
> > +	check_sr_rw(ICC_AP1R3_EL1);
> > +	check_sr_write(ICC_DIR_EL1);
> > +	check_sr_read(ICC_RPR_EL1);
> > +	check_sr_write(ICC_SGI1R_EL1);
> > +	check_sr_write(ICC_ASGI1R_EL1);
> > +	check_sr_write(ICC_SGI0R_EL1);
> > +	check_sr_read(ICC_IAR1_EL1);
> > +	check_sr_write(ICC_EOIR1_EL1);
> > +	check_sr_rw(ICC_HPPIR1_EL1);
> > +	check_sr_rw(ICC_BPR1_EL1);
> > +	check_sr_rw(ICC_CTLR_EL1);
> > +	check_sr_rw(ICC_IGRPEN0_EL1);
> > +	check_sr_rw(ICC_IGRPEN1_EL1);
> > +
> > +	/*
> > +	 * ICC_SRE_EL1 may not be trappable, as ICC_SRE_EL2.Enable can
> > +	 * be RAO/WI
> > +	 */
> > +	check_sr_read_maybe(ICC_SRE_EL1);
> > +	check_sr_write_maybe(ICC_SRE_EL1);
> 
> In the case that a write does not UNDEF, should we check that
> ICC_SRE_EL1.SRE is also RAO/WI?

Ah, not a bad idea. I'll add that.

Thanks,

	M.

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


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

* Re: [PATCH 04/12] KVM: arm64: Force GICv3 traps activa when no irqchip is configured on VHE
  2024-08-21 11:13     ` Marc Zyngier
@ 2024-08-21 16:52       ` Oliver Upton
  0 siblings, 0 replies; 26+ messages in thread
From: Oliver Upton @ 2024-08-21 16:52 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: kvmarm, linux-arm-kernel, kvm, James Morse, Suzuki K Poulose,
	Zenghui Yu, Alexander Potapenko

On Wed, Aug 21, 2024 at 12:13:57PM +0100, Marc Zyngier wrote:
> On Wed, 21 Aug 2024 00:33:40 +0100,
> Oliver Upton <oliver.upton@linux.dev> wrote:
> > 
> > s/activa/active/
> > 
> > On Tue, Aug 20, 2024 at 11:03:41AM +0100, Marc Zyngier wrote:
> > > On a VHE system, no GICv3 traps get configured when no irqchip is
> > > present. This is not quite matching the "no GICv3" semantics that
> > > we want to present.
> > > 
> > > Force such traps to be configured in this case.
> > > 
> > > Signed-off-by: Marc Zyngier <maz@kernel.org>
> > > ---
> > >  arch/arm64/kvm/vgic/vgic.c | 14 ++++++++++----
> > >  1 file changed, 10 insertions(+), 4 deletions(-)
> > > 
> > > diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
> > > index 974849ea7101..2caa64415ff3 100644
> > > --- a/arch/arm64/kvm/vgic/vgic.c
> > > +++ b/arch/arm64/kvm/vgic/vgic.c
> > > @@ -917,10 +917,13 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
> > >  
> > >  void kvm_vgic_load(struct kvm_vcpu *vcpu)
> > >  {
> > > -	if (unlikely(!vgic_initialized(vcpu->kvm)))
> > > +	if (unlikely(!irqchip_in_kernel(vcpu->kvm) || !vgic_initialized(vcpu->kvm))) {
> > 
> > Doesn't !vgic_initialized(vcpu->kvm) also cover the case of no irqchip
> > in kernel?
> 
> It does, but that's purely accidental. I can drop that, but it is
> really fragile.

Oh, definitely not, I was just wondering if this was meant as a
functional change or a readability change to make the relation explicit.

-- 
Thanks,
Oliver


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

* Re: [PATCH 01/12] KVM: arm64: Make ICC_*SGI*_EL1 undef in the absence of a vGICv3
  2024-08-21 10:59     ` Marc Zyngier
@ 2024-08-21 16:53       ` Oliver Upton
  0 siblings, 0 replies; 26+ messages in thread
From: Oliver Upton @ 2024-08-21 16:53 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: kvmarm, linux-arm-kernel, kvm, James Morse, Suzuki K Poulose,
	Zenghui Yu, Alexander Potapenko, stable

On Wed, Aug 21, 2024 at 11:59:52AM +0100, Marc Zyngier wrote:
> On Tue, 20 Aug 2024 22:46:30 +0100,
> Oliver Upton <oliver.upton@linux.dev> wrote:
> > 
> > On Tue, Aug 20, 2024 at 11:03:38AM +0100, Marc Zyngier wrote:
> > > On a system with a GICv3, if a guest hasn't been configured with
> > > GICv3 and that the host is not capable of GICv2 emulation,
> > > a write to any of the ICC_*SGI*_EL1 registers is trapped to EL2.
> > > 
> > > We therefore try to emulate the SGI access, only to hit a NULL
> > > pointer as no private interrupt is allocated (no GIC, remember?).
> > > 
> > > The obvious fix is to give the guest what it deserves, in the
> > > shape of a UNDEF exception.
> > > 
> > > Reported-by: Alexander Potapenko <glider@google.com>
> > > Signed-off-by: Marc Zyngier <maz@kernel.org>
> > > Cc: stable@vger.kernel.org
> > 
> > LGTM, and just as an FYI I do plan on grabbing this for 6.11
> 
> Great, thanks. Are you planning to route this via arm64, given that
> Paolo is away for a bit?

Yup, exactly that. I'll send the PR in the next day or two when I have
some time to kick the tires on everything.

-- 
Thanks,
Oliver


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

* Re: (subset) [PATCH 01/12] KVM: arm64: Make ICC_*SGI*_EL1 undef in the absence of a vGICv3
  2024-08-20 10:03 ` [PATCH 01/12] KVM: arm64: Make ICC_*SGI*_EL1 undef in the absence of a vGICv3 Marc Zyngier
  2024-08-20 21:46   ` Oliver Upton
@ 2024-08-22  8:15   ` Oliver Upton
  1 sibling, 0 replies; 26+ messages in thread
From: Oliver Upton @ 2024-08-22  8:15 UTC (permalink / raw)
  To: kvmarm, kvm, Marc Zyngier, linux-arm-kernel
  Cc: Oliver Upton, Zenghui Yu, James Morse, stable,
	Alexander Potapenko, Suzuki K Poulose

On Tue, 20 Aug 2024 11:03:38 +0100, Marc Zyngier wrote:
> On a system with a GICv3, if a guest hasn't been configured with
> GICv3 and that the host is not capable of GICv2 emulation,
> a write to any of the ICC_*SGI*_EL1 registers is trapped to EL2.
> 
> We therefore try to emulate the SGI access, only to hit a NULL
> pointer as no private interrupt is allocated (no GIC, remember?).
> 
> [...]

Applied to kvmarm/fixes, thanks!

[01/12] KVM: arm64: Make ICC_*SGI*_EL1 undef in the absence of a vGICv3
        https://git.kernel.org/kvmarm/kvmarm/c/3e6245ebe7ef

--
Best,
Oliver


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

end of thread, other threads:[~2024-08-22  8:17 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-08-20 10:03 [PATCH 00/12] KVM: arm64: Handle the lack of GICv3 exposed to a guest Marc Zyngier
2024-08-20 10:03 ` [PATCH 01/12] KVM: arm64: Make ICC_*SGI*_EL1 undef in the absence of a vGICv3 Marc Zyngier
2024-08-20 21:46   ` Oliver Upton
2024-08-21 10:59     ` Marc Zyngier
2024-08-21 16:53       ` Oliver Upton
2024-08-22  8:15   ` (subset) " Oliver Upton
2024-08-20 10:03 ` [PATCH 02/12] KVM: arm64: Move GICv3 trap configuration to kvm_calculate_traps() Marc Zyngier
2024-08-20 10:03 ` [PATCH 03/12] KVM: arm64: Force SRE traps when SRE access is not enabled Marc Zyngier
2024-08-20 23:19   ` Oliver Upton
2024-08-21 11:05     ` Marc Zyngier
2024-08-20 10:03 ` [PATCH 04/12] KVM: arm64: Force GICv3 traps activa when no irqchip is configured on VHE Marc Zyngier
2024-08-20 23:33   ` Oliver Upton
2024-08-21 11:13     ` Marc Zyngier
2024-08-21 16:52       ` Oliver Upton
2024-08-20 10:03 ` [PATCH 05/12] KVM: arm64: Add helper for last ditch idreg adjustments Marc Zyngier
2024-08-20 10:03 ` [PATCH 06/12] KVM: arm64: Zero ID_AA64PFR0_EL1.GIC when no GICv3 is presented to the guest Marc Zyngier
2024-08-20 23:50   ` Oliver Upton
2024-08-21 11:16     ` Marc Zyngier
2024-08-20 10:03 ` [PATCH 07/12] KVM: arm64: Add ICH_HCR_EL2 to the vcpu state Marc Zyngier
2024-08-20 10:03 ` [PATCH 08/12] KVM: arm64: Add trap routing information for ICH_HCR_EL2 Marc Zyngier
2024-08-20 10:03 ` [PATCH 09/12] KVM: arm64: Honor guest requested traps in GICv3 emulation Marc Zyngier
2024-08-20 10:03 ` [PATCH 10/12] KVM: arm64: Make most GICv3 accesses UNDEF if they trap Marc Zyngier
2024-08-20 10:03 ` [PATCH 11/12] KVM: arm64: Unify UNDEF injection helpers Marc Zyngier
2024-08-20 10:03 ` [PATCH 12/12] KVM: arm64: Add selftest checking how the absence of GICv3 is handled Marc Zyngier
2024-08-21  0:10   ` Oliver Upton
2024-08-21 11:17     ` Marc Zyngier

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).