All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/7] KVM: arm64: pKVM host hypercall and GICv5 CPU interface fixes
@ 2026-09-15 12:38 Fuad Tabba
  2026-09-15 12:38 ` [PATCH 1/7] KVM: arm64: Reject the GICv5 CPU interface hypercalls under pKVM Fuad Tabba
                   ` (6 more replies)
  0 siblings, 7 replies; 13+ messages in thread
From: Fuad Tabba @ 2026-09-15 12:38 UTC (permalink / raw)
  To: maz, oupton, kvmarm, linux-arm-kernel, linux-kernel
  Cc: catalin.marinas, will, joey.gouly, seiden, suzuki.poulose,
	yuzenghui, mark.rutland, vdonnefort, qperret, Sascha.Bischoff,
	steven.price, tabba

Hi folks,

This series consolidates three postings, which it supersedes:
  - The stage-2 MMU pointer hypercall rejection [1]: patch 2, reworked
    to move the hypercalls out of the always-available band instead of
    guarding each handler, and covering __kvm_flush_vm_context() too
    (Marc). __kvm_flush_cpu_context() stays in the set, which the
    sketch on the thread left out.
  - The GICv5 CPU interface series [2]: its hypercall patch reworked
    the same way, as patch 1, and its other three as patches 3, 6 and
    7, with 3's comment and 7's message trimmed and 6 unchanged.
    Sascha's Reviewed-by on the reworked patch isn't carried, the code
    having changed.
  - The __kvm_adjust_pc() host pointer fixes [3]: patches 4 and 5,
    with Vincent's and Joey's nits taken and their Reviewed-by
    collected. (thanks!)

Under pKVM, EL2 still trusts the host at the hypercall boundary in a
few places: hypercalls the host has no use for in protected mode stay
callable, the __kvm_adjust_pc() hypercall it does use takes a host
vCPU nothing pins or validates, and the vgic model EL2 copies out of
the host's struct kvm goes unchecked.

Patches 1 and 2 move the GICv5 CPU interface save/restore and the
stage-2 flushes into the band the dispatcher rejects once pKVM has
finalised. Patch 3 validates the vgic model EL2 copies from the host.
Patches 4 and 5 fix two host pointers dereferenced unvalidated on the
__kvm_adjust_pc() path, the vCPU's VM and the vCPU itself: either
panics the hypervisor if unmapped, and the VM read leaks a bit of hyp
memory through PSR_TCO on MTE hardware. Both carry Cc: stable. The
pKVM core series [4] carries the same two fixes as its patches 2 and
3, in the form posted before Vincent's nits, so that it applies as
is. Patches 6 and 7 are the rest of [2]: the EL1 side of the GICv5
access on nVHE, and a comment fix.

Patch 2 carries no Fixes: tag, no in-tree host path reaching those
hypercalls under pKVM; patch 1 keeps the one it was posted with.

The GICv5 residency and VDPEND hypercalls queued for 7.4 carry the
per-handler check the superseded GICv5 patch used, and can move the
same way.

Superseded postings:
  - 20260914174521.832575-1-fuad.tabba@linux.dev
  - 20260817103228.1203140-1-fuad.tabba@linux.dev (and its v1,
    20260806100256.371164-1-fuad.tabba@linux.dev)
  - 20260915070418.3209779-1-fuad.tabba@linux.dev (and its v1,
    20260914065136.3418404-1-fuad.tabba@linux.dev)

Based on v7.3-rc3 (fd73f4a665989). On kvmarm/next, patches 1 and 2
conflict with the new GICv5 hypercall IDs and patch 5 with the typed
hypercall handlers.

Cheers,
/fuad

[1] https://lore.kernel.org/all/20260914174521.832575-1-fuad.tabba@linux.dev/
[2] https://lore.kernel.org/all/20260817103228.1203140-1-fuad.tabba@linux.dev/
[3] https://lore.kernel.org/all/20260915070418.3209779-1-fuad.tabba@linux.dev/
[4] https://lore.kernel.org/all/20260914113338.159227-1-fuad.tabba@linux.dev/

Fuad Tabba (7):
  KVM: arm64: Reject the GICv5 CPU interface hypercalls under pKVM
  KVM: arm64: Reject the stage-2 flush hypercalls under pKVM
  KVM: arm64: Validate the host-provided vgic model in pKVM
  KVM: arm64: Validate the host vCPU's VM before reading it under pKVM
  KVM: arm64: Pin the host vCPU before adjusting its PC under pKVM
  KVM: arm64: vgic: Do not access the GICv5 CPU interface from EL1
  KVM: arm64: Fix stale VGICv3 comments in the nVHE world switch

 arch/arm64/include/asm/kvm_asm.h           | 16 ++++----
 arch/arm64/kvm/hyp/exception.c             |  5 ++-
 arch/arm64/kvm/hyp/include/hyp/adjust_pc.h | 28 +++++++++++++
 arch/arm64/kvm/hyp/include/nvhe/pkvm.h     |  2 +
 arch/arm64/kvm/hyp/nvhe/hyp-main.c         | 36 +++++++++++++----
 arch/arm64/kvm/hyp/nvhe/pkvm.c             | 47 +++++++++++++++++++++-
 arch/arm64/kvm/hyp/nvhe/switch.c           |  4 +-
 arch/arm64/kvm/vgic/vgic.c                 | 12 ++++--
 8 files changed, 125 insertions(+), 25 deletions(-)


base-commit: fd73f4a6659897191fa0d40695fe370925dd3780
-- 
2.39.5



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

* [PATCH 1/7] KVM: arm64: Reject the GICv5 CPU interface hypercalls under pKVM
  2026-09-15 12:38 [PATCH 0/7] KVM: arm64: pKVM host hypercall and GICv5 CPU interface fixes Fuad Tabba
@ 2026-09-15 12:38 ` Fuad Tabba
  2026-09-15 14:02   ` Marc Zyngier
  2026-09-15 12:38 ` [PATCH 2/7] KVM: arm64: Reject the stage-2 flush " Fuad Tabba
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 13+ messages in thread
From: Fuad Tabba @ 2026-09-15 12:38 UTC (permalink / raw)
  To: maz, oupton, kvmarm, linux-arm-kernel, linux-kernel
  Cc: catalin.marinas, will, joey.gouly, seiden, suzuki.poulose,
	yuzenghui, mark.rutland, vdonnefort, qperret, Sascha.Bischoff,
	steven.price, tabba

__vgic_v5_save_apr() and __vgic_v5_restore_vmcr_apr() remain callable
once pKVM has finalised. pKVM never registers a GICv5 vgic, so neither
has a valid caller in protected mode, and on a GICv3 machine both reach
a register that is UNDEFINED at EL2 and panic the hypervisor.

Move both into the band the dispatcher rejects once pKVM has finalised.

Fixes: af325e87af5da ("KVM: arm64: gic-v5: Add vgic-v5 save/restore hyp interface")
Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
---
 arch/arm64/include/asm/kvm_asm.h   | 4 ++--
 arch/arm64/kvm/hyp/nvhe/hyp-main.c | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
index e5b92ac09e69e..ea319c496bb26 100644
--- a/arch/arm64/include/asm/kvm_asm.h
+++ b/arch/arm64/include/asm/kvm_asm.h
@@ -62,6 +62,8 @@ enum __kvm_host_smccc_func {
 	__KVM_HOST_SMCCC_FUNC___kvm_enable_ssbs,
 	__KVM_HOST_SMCCC_FUNC___vgic_v3_init_lrs,
 	__KVM_HOST_SMCCC_FUNC___vgic_v3_get_gic_config,
+	__KVM_HOST_SMCCC_FUNC___vgic_v5_save_apr,
+	__KVM_HOST_SMCCC_FUNC___vgic_v5_restore_vmcr_apr,
 
 	MARKER(__KVM_HOST_SMCCC_FUNC_MIN_PKVM),
 
@@ -87,8 +89,6 @@ enum __kvm_host_smccc_func {
 	__KVM_HOST_SMCCC_FUNC___tracing_write_event,
 	__KVM_HOST_SMCCC_FUNC___vgic_v3_save_aprs,
 	__KVM_HOST_SMCCC_FUNC___vgic_v3_restore_vmcr_aprs,
-	__KVM_HOST_SMCCC_FUNC___vgic_v5_save_apr,
-	__KVM_HOST_SMCCC_FUNC___vgic_v5_restore_vmcr_apr,
 
 	MARKER(__KVM_HOST_SMCCC_FUNC_PKVM_ONLY),
 
diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
index 9a3b92e626adb..7c939baf9c1ba 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
@@ -911,6 +911,8 @@ static const hcall_t host_hcall[] = {
 	HANDLE_FUNC(__kvm_enable_ssbs),
 	HANDLE_FUNC(__vgic_v3_init_lrs),
 	HANDLE_FUNC(__vgic_v3_get_gic_config),
+	HANDLE_FUNC(__vgic_v5_save_apr),
+	HANDLE_FUNC(__vgic_v5_restore_vmcr_apr),
 	HANDLE_FUNC(__pkvm_prot_finalize),
 
 	HANDLE_FUNC(__kvm_adjust_pc),
@@ -932,8 +934,6 @@ static const hcall_t host_hcall[] = {
 	HANDLE_FUNC(__tracing_write_event),
 	HANDLE_FUNC(__vgic_v3_save_aprs),
 	HANDLE_FUNC(__vgic_v3_restore_vmcr_aprs),
-	HANDLE_FUNC(__vgic_v5_save_apr),
-	HANDLE_FUNC(__vgic_v5_restore_vmcr_apr),
 
 	HANDLE_FUNC(__pkvm_host_share_hyp),
 	HANDLE_FUNC(__pkvm_host_unshare_hyp),
-- 
2.39.5



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

* [PATCH 2/7] KVM: arm64: Reject the stage-2 flush hypercalls under pKVM
  2026-09-15 12:38 [PATCH 0/7] KVM: arm64: pKVM host hypercall and GICv5 CPU interface fixes Fuad Tabba
  2026-09-15 12:38 ` [PATCH 1/7] KVM: arm64: Reject the GICv5 CPU interface hypercalls under pKVM Fuad Tabba
@ 2026-09-15 12:38 ` Fuad Tabba
  2026-09-15 12:38 ` [PATCH 3/7] KVM: arm64: Validate the host-provided vgic model in pKVM Fuad Tabba
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 13+ messages in thread
From: Fuad Tabba @ 2026-09-15 12:38 UTC (permalink / raw)
  To: maz, oupton, kvmarm, linux-arm-kernel, linux-kernel
  Cc: catalin.marinas, will, joey.gouly, seiden, suzuki.poulose,
	yuzenghui, mark.rutland, vdonnefort, qperret, Sascha.Bischoff,
	steven.price, tabba

The stage-2 TLB and context flush hypercalls remain callable once pKVM
has finalised, and five of the six dereference a host-supplied
struct kvm_s2_mmu pointer. Under pKVM none has a valid caller: the host
walks no guest stage-2, its TLB flushes go through the handle-based
__pkvm_tlb_flush_vmid, and kvm_arch_vcpu_load() skips both the VMID
update and the CPU context flush.

Move them into the band the dispatcher rejects once pKVM has finalised.

Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://lore.kernel.org/all/20260914130152.F0D5F1F000FF@smtp.kernel.org/
Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
---
 arch/arm64/include/asm/kvm_asm.h   | 12 ++++++------
 arch/arm64/kvm/hyp/nvhe/hyp-main.c | 11 ++++++-----
 2 files changed, 12 insertions(+), 11 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
index ea319c496bb26..b182c908c1a98 100644
--- a/arch/arm64/include/asm/kvm_asm.h
+++ b/arch/arm64/include/asm/kvm_asm.h
@@ -64,6 +64,12 @@ enum __kvm_host_smccc_func {
 	__KVM_HOST_SMCCC_FUNC___vgic_v3_get_gic_config,
 	__KVM_HOST_SMCCC_FUNC___vgic_v5_save_apr,
 	__KVM_HOST_SMCCC_FUNC___vgic_v5_restore_vmcr_apr,
+	__KVM_HOST_SMCCC_FUNC___kvm_flush_vm_context,
+	__KVM_HOST_SMCCC_FUNC___kvm_tlb_flush_vmid_ipa,
+	__KVM_HOST_SMCCC_FUNC___kvm_tlb_flush_vmid_ipa_nsh,
+	__KVM_HOST_SMCCC_FUNC___kvm_tlb_flush_vmid,
+	__KVM_HOST_SMCCC_FUNC___kvm_tlb_flush_vmid_range,
+	__KVM_HOST_SMCCC_FUNC___kvm_flush_cpu_context,
 
 	MARKER(__KVM_HOST_SMCCC_FUNC_MIN_PKVM),
 
@@ -72,12 +78,6 @@ enum __kvm_host_smccc_func {
 	/* Hypercalls that are always available and common to [nh]VHE/pKVM. */
 	__KVM_HOST_SMCCC_FUNC___kvm_adjust_pc,
 	__KVM_HOST_SMCCC_FUNC___kvm_vcpu_run,
-	__KVM_HOST_SMCCC_FUNC___kvm_flush_vm_context,
-	__KVM_HOST_SMCCC_FUNC___kvm_tlb_flush_vmid_ipa,
-	__KVM_HOST_SMCCC_FUNC___kvm_tlb_flush_vmid_ipa_nsh,
-	__KVM_HOST_SMCCC_FUNC___kvm_tlb_flush_vmid,
-	__KVM_HOST_SMCCC_FUNC___kvm_tlb_flush_vmid_range,
-	__KVM_HOST_SMCCC_FUNC___kvm_flush_cpu_context,
 	__KVM_HOST_SMCCC_FUNC___kvm_timer_set_cntvoff,
 	__KVM_HOST_SMCCC_FUNC___tracing_load,
 	__KVM_HOST_SMCCC_FUNC___tracing_unload,
diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
index 7c939baf9c1ba..b2657a3c65b40 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
@@ -913,16 +913,16 @@ static const hcall_t host_hcall[] = {
 	HANDLE_FUNC(__vgic_v3_get_gic_config),
 	HANDLE_FUNC(__vgic_v5_save_apr),
 	HANDLE_FUNC(__vgic_v5_restore_vmcr_apr),
-	HANDLE_FUNC(__pkvm_prot_finalize),
-
-	HANDLE_FUNC(__kvm_adjust_pc),
-	HANDLE_FUNC(__kvm_vcpu_run),
 	HANDLE_FUNC(__kvm_flush_vm_context),
 	HANDLE_FUNC(__kvm_tlb_flush_vmid_ipa),
 	HANDLE_FUNC(__kvm_tlb_flush_vmid_ipa_nsh),
 	HANDLE_FUNC(__kvm_tlb_flush_vmid),
 	HANDLE_FUNC(__kvm_tlb_flush_vmid_range),
 	HANDLE_FUNC(__kvm_flush_cpu_context),
+	HANDLE_FUNC(__pkvm_prot_finalize),
+
+	HANDLE_FUNC(__kvm_adjust_pc),
+	HANDLE_FUNC(__kvm_vcpu_run),
 	HANDLE_FUNC(__kvm_timer_set_cntvoff),
 	HANDLE_FUNC(__tracing_load),
 	HANDLE_FUNC(__tracing_unload),
@@ -969,7 +969,8 @@ static void handle_host_hcall(struct kvm_cpu_context *host_ctxt)
 
 	/*
 	 * If pKVM has been initialised then reject any calls to the
-	 * early "privileged" hypercalls. Note that we cannot reject
+	 * early "privileged" hypercalls, and to the ones the host has no
+	 * use for in protected mode. Note that we cannot reject
 	 * calls to __pkvm_prot_finalize for two reasons: (1) The static
 	 * key used to determine initialisation must be toggled prior to
 	 * finalisation and (2) finalisation is performed on a per-CPU
-- 
2.39.5



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

* [PATCH 3/7] KVM: arm64: Validate the host-provided vgic model in pKVM
  2026-09-15 12:38 [PATCH 0/7] KVM: arm64: pKVM host hypercall and GICv5 CPU interface fixes Fuad Tabba
  2026-09-15 12:38 ` [PATCH 1/7] KVM: arm64: Reject the GICv5 CPU interface hypercalls under pKVM Fuad Tabba
  2026-09-15 12:38 ` [PATCH 2/7] KVM: arm64: Reject the stage-2 flush " Fuad Tabba
@ 2026-09-15 12:38 ` Fuad Tabba
  2026-09-16 11:00   ` Joey Gouly
  2026-09-15 12:38 ` [PATCH 4/7] KVM: arm64: Validate the host vCPU's VM before reading it under pKVM Fuad Tabba
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 13+ messages in thread
From: Fuad Tabba @ 2026-09-15 12:38 UTC (permalink / raw)
  To: maz, oupton, kvmarm, linux-arm-kernel, linux-kernel
  Cc: catalin.marinas, will, joey.gouly, seiden, suzuki.poulose,
	yuzenghui, mark.rutland, vdonnefort, qperret, Sascha.Bischoff,
	steven.price, tabba

EL2 copies vgic_model from the host's struct kvm unchecked, and the nVHE
world switch dispatches on it with no cpucap guard. A host writing
KVM_DEV_TYPE_ARM_VGIC_V5 makes EL2 access GICv5 CPU interface registers
that are UNDEFINED without FEAT_GCIE, and panics the hypervisor on any
GICv3 machine.

Accept only GICv3, the one model pKVM supports, forcing anything else
to 0.

Fixes: 9b8e3d4ca0e73 ("KVM: arm64: gic-v5: Implement GICv5 load/put and save/restore")
Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
---
 arch/arm64/kvm/hyp/nvhe/pkvm.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c
index 459bd9eb7e4bc..4c33c863e90e1 100644
--- a/arch/arm64/kvm/hyp/nvhe/pkvm.c
+++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c
@@ -340,13 +340,19 @@ static void pkvm_init_features_from_host(struct pkvm_hyp_vm *hyp_vm, const struc
 {
 	struct kvm *kvm = &hyp_vm->kvm;
 	unsigned long host_arch_flags = READ_ONCE(host_kvm->arch.flags);
+	u32 vgic_model = READ_ONCE(host_kvm->arch.vgic.vgic_model);
 	DECLARE_BITMAP(allowed_features, KVM_VCPU_MAX_FEATURES);
 
 	/* CTR_EL0 is always under host control, even for protected VMs. */
 	hyp_vm->kvm.arch.ctr_el0 = host_kvm->arch.ctr_el0;
 
-	/* Preserve the vgic model so that GICv3 emulation works */
-	hyp_vm->kvm.arch.vgic.vgic_model = host_kvm->arch.vgic.vgic_model;
+	/*
+	 * GICv3 is the only model pKVM runs, and the GICv5 world switch
+	 * touches registers UNDEFINED at EL2 without FEAT_GCIE.
+	 */
+	if (vgic_model != KVM_DEV_TYPE_ARM_VGIC_V3)
+		vgic_model = 0;
+	hyp_vm->kvm.arch.vgic.vgic_model = vgic_model;
 
 	/* No restrictions for non-protected VMs. */
 	if (!kvm_vm_is_protected(kvm)) {
-- 
2.39.5



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

* [PATCH 4/7] KVM: arm64: Validate the host vCPU's VM before reading it under pKVM
  2026-09-15 12:38 [PATCH 0/7] KVM: arm64: pKVM host hypercall and GICv5 CPU interface fixes Fuad Tabba
                   ` (2 preceding siblings ...)
  2026-09-15 12:38 ` [PATCH 3/7] KVM: arm64: Validate the host-provided vgic model in pKVM Fuad Tabba
@ 2026-09-15 12:38 ` Fuad Tabba
  2026-09-15 12:38 ` [PATCH 5/7] KVM: arm64: Pin the host vCPU before adjusting its PC " Fuad Tabba
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 13+ messages in thread
From: Fuad Tabba @ 2026-09-15 12:38 UTC (permalink / raw)
  To: maz, oupton, kvmarm, linux-arm-kernel, linux-kernel
  Cc: catalin.marinas, will, joey.gouly, seiden, suzuki.poulose,
	yuzenghui, mark.rutland, vdonnefort, qperret, Sascha.Bischoff,
	steven.price, tabba

On an MTE-capable host under pKVM, enter_exception64() reads the VM's
MTE flag through vcpu->kvm, which for a host vCPU is a host-writable
pointer nothing validates. The host can point it at any address in the
hyp linear map and read back bit 1 of that word through PSR_TCO in the
vCPU's CPSR, or panic the hypervisor with an unmapped one.

Get the VM through a get/put pair around the read: a loaded vCPU's is
the hyp VM, an unloaded host vCPU's is read once and pinned, and a
pointer the host never shared leaves TCO clear.

Fixes: ea7fc1bb1cd1b ("KVM: arm64: Introduce MTE VM feature")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://lore.kernel.org/all/20260914070536.877D91F000FF@smtp.kernel.org/
Reviewed-by: Vincent Donnefort <vdonnefort@google.com>
Reviewed-by: Joey Gouly <joey.gouly@arm.com>
Cc: stable@vger.kernel.org
Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
---
 arch/arm64/kvm/hyp/exception.c             |  5 ++-
 arch/arm64/kvm/hyp/include/hyp/adjust_pc.h | 28 ++++++++++++++++
 arch/arm64/kvm/hyp/include/nvhe/pkvm.h     |  2 ++
 arch/arm64/kvm/hyp/nvhe/pkvm.c             | 37 ++++++++++++++++++++++
 4 files changed, 71 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kvm/hyp/exception.c b/arch/arm64/kvm/hyp/exception.c
index 754e2dc1df54a..6e60d890afa4a 100644
--- a/arch/arm64/kvm/hyp/exception.c
+++ b/arch/arm64/kvm/hyp/exception.c
@@ -70,6 +70,7 @@ static void enter_exception64(struct kvm_vcpu *vcpu, unsigned long target_mode,
 			      enum exception_type type)
 {
 	unsigned long sctlr, vbar, old, new, mode;
+	struct kvm *kvm;
 	u64 exc_offset;
 
 	mode = *vcpu_cpsr(vcpu) & (PSR_MODE_MASK | PSR_MODE32_BIT);
@@ -109,8 +110,10 @@ static void enter_exception64(struct kvm_vcpu *vcpu, unsigned long target_mode,
 	new |= (old & PSR_C_BIT);
 	new |= (old & PSR_V_BIT);
 
-	if (kvm_has_mte(kern_hyp_va(vcpu->kvm)))
+	kvm = vcpu_get_kvm(vcpu);
+	if (kvm && kvm_has_mte(kvm))
 		new |= PSR_TCO_BIT;
+	vcpu_put_kvm(vcpu, kvm);
 
 	new |= (old & PSR_DIT_BIT);
 
diff --git a/arch/arm64/kvm/hyp/include/hyp/adjust_pc.h b/arch/arm64/kvm/hyp/include/hyp/adjust_pc.h
index 4fdfeabefeb43..f55950ee2a7e4 100644
--- a/arch/arm64/kvm/hyp/include/hyp/adjust_pc.h
+++ b/arch/arm64/kvm/hyp/include/hyp/adjust_pc.h
@@ -13,6 +13,34 @@
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_host.h>
 
+#ifdef __KVM_NVHE_HYPERVISOR__
+#include <nvhe/pkvm.h>
+
+/* Under pKVM a host vCPU's ->kvm is host-writable. */
+static inline struct kvm *vcpu_get_kvm(struct kvm_vcpu *vcpu)
+{
+	if (is_protected_kvm_enabled())
+		return pkvm_vcpu_get_kvm(vcpu);
+
+	return kern_hyp_va(vcpu->kvm);
+}
+
+static inline void vcpu_put_kvm(struct kvm_vcpu *vcpu, struct kvm *kvm)
+{
+	if (is_protected_kvm_enabled())
+		pkvm_vcpu_put_kvm(vcpu, kvm);
+}
+#else
+static inline struct kvm *vcpu_get_kvm(struct kvm_vcpu *vcpu)
+{
+	return vcpu->kvm;
+}
+
+static inline void vcpu_put_kvm(struct kvm_vcpu *vcpu, struct kvm *kvm)
+{
+}
+#endif
+
 static inline void kvm_skip_instr(struct kvm_vcpu *vcpu)
 {
 	if (vcpu_mode_is_32bit(vcpu)) {
diff --git a/arch/arm64/kvm/hyp/include/nvhe/pkvm.h b/arch/arm64/kvm/hyp/include/nvhe/pkvm.h
index c904647d2f760..5ddb407149667 100644
--- a/arch/arm64/kvm/hyp/include/nvhe/pkvm.h
+++ b/arch/arm64/kvm/hyp/include/nvhe/pkvm.h
@@ -83,6 +83,8 @@ struct pkvm_hyp_vcpu *pkvm_load_hyp_vcpu(pkvm_handle_t handle,
 					 unsigned int vcpu_idx);
 void pkvm_put_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu);
 struct pkvm_hyp_vcpu *pkvm_get_loaded_hyp_vcpu(void);
+struct kvm *pkvm_vcpu_get_kvm(struct kvm_vcpu *vcpu);
+void pkvm_vcpu_put_kvm(struct kvm_vcpu *vcpu, struct kvm *kvm);
 
 struct pkvm_hyp_vm *get_pkvm_hyp_vm(pkvm_handle_t handle);
 struct pkvm_hyp_vm *get_np_pkvm_hyp_vm(pkvm_handle_t handle);
diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c
index 4c33c863e90e1..737f3a5c4f640 100644
--- a/arch/arm64/kvm/hyp/nvhe/pkvm.c
+++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c
@@ -304,6 +304,43 @@ struct pkvm_hyp_vcpu *pkvm_get_loaded_hyp_vcpu(void)
 
 }
 
+static struct pkvm_hyp_vm *pkvm_get_loaded_hyp_vm(struct kvm_vcpu *vcpu)
+{
+	struct pkvm_hyp_vcpu *hyp_vcpu = pkvm_get_loaded_hyp_vcpu();
+
+	if (hyp_vcpu &&
+	    (vcpu == &hyp_vcpu->vcpu || vcpu == hyp_vcpu->host_vcpu))
+		return pkvm_hyp_vcpu_to_hyp_vm(hyp_vcpu);
+
+	return NULL;
+}
+
+/*
+ * A loaded vCPU's VM is the hyp VM. An unloaded host vCPU's is mapped at
+ * EL2 only while pinned, so it's read once and pinned; the pin fails for
+ * memory the host isn't sharing.
+ */
+struct kvm *pkvm_vcpu_get_kvm(struct kvm_vcpu *vcpu)
+{
+	struct pkvm_hyp_vm *hyp_vm = pkvm_get_loaded_hyp_vm(vcpu);
+	struct kvm *kvm;
+
+	if (hyp_vm)
+		return &hyp_vm->kvm;
+
+	kvm = kern_hyp_va(READ_ONCE(vcpu->kvm));
+	if (hyp_pin_shared_mem(kvm, kvm + 1))
+		return NULL;
+
+	return kvm;
+}
+
+void pkvm_vcpu_put_kvm(struct kvm_vcpu *vcpu, struct kvm *kvm)
+{
+	if (kvm && !pkvm_get_loaded_hyp_vm(vcpu))
+		hyp_unpin_shared_mem(kvm, kvm + 1);
+}
+
 struct pkvm_hyp_vm *get_pkvm_hyp_vm(pkvm_handle_t handle)
 {
 	struct pkvm_hyp_vm *hyp_vm;
-- 
2.39.5



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

* [PATCH 5/7] KVM: arm64: Pin the host vCPU before adjusting its PC under pKVM
  2026-09-15 12:38 [PATCH 0/7] KVM: arm64: pKVM host hypercall and GICv5 CPU interface fixes Fuad Tabba
                   ` (3 preceding siblings ...)
  2026-09-15 12:38 ` [PATCH 4/7] KVM: arm64: Validate the host vCPU's VM before reading it under pKVM Fuad Tabba
@ 2026-09-15 12:38 ` Fuad Tabba
  2026-09-15 12:38 ` [PATCH 6/7] KVM: arm64: vgic: Do not access the GICv5 CPU interface from EL1 Fuad Tabba
  2026-09-15 12:38 ` [PATCH 7/7] KVM: arm64: Fix stale VGICv3 comments in the nVHE world switch Fuad Tabba
  6 siblings, 0 replies; 13+ messages in thread
From: Fuad Tabba @ 2026-09-15 12:38 UTC (permalink / raw)
  To: maz, oupton, kvmarm, linux-arm-kernel, linux-kernel
  Cc: catalin.marinas, will, joey.gouly, seiden, suzuki.poulose,
	yuzenghui, mark.rutland, vdonnefort, qperret, Sascha.Bischoff,
	steven.price, tabba

Under pKVM, a page the host shares with EL2 is mapped at EL2 only while
it's pinned, and the host vCPU is pinned at its first KVM_RUN.
KVM_SET_VCPU_EVENTS with ext_dabt_pending reaches __kvm_adjust_pc() at
EL2 before that, and dereferencing the unmapped host vCPU panics the
hypervisor. Any process holding /dev/kvm on a pKVM host can trigger it.

Pin the host vCPU around the adjustment when no hyp vCPU is loaded for
it. A loaded hyp vCPU implies it's pinned. A pin fails only for memory
the host isn't sharing, and the request is then dropped like any other
bad host pointer.

Fixes: efa1368ba9f4b ("KVM: arm64: Commit exceptions from KVM_SET_VCPU_EVENTS immediately")
Reviewed-by: Vincent Donnefort <vdonnefort@google.com>
Reviewed-by: Joey Gouly <joey.gouly@arm.com>
Cc: stable@vger.kernel.org
Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
---
 arch/arm64/kvm/hyp/nvhe/hyp-main.c | 21 ++++++++++++++++++++-
 1 file changed, 20 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
index b2657a3c65b40..a138b42e7cea3 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
@@ -542,8 +542,27 @@ static void handle___pkvm_host_mkyoung_guest(struct kvm_cpu_context *host_ctxt)
 static void handle___kvm_adjust_pc(struct kvm_cpu_context *host_ctxt)
 {
 	DECLARE_REG(struct kvm_vcpu *, vcpu, host_ctxt, 1);
+	struct pkvm_hyp_vcpu *hyp_vcpu;
+	struct kvm_vcpu *host_vcpu;
 
-	__kvm_adjust_pc(kern_hyp_va(vcpu));
+	host_vcpu = __get_host_hyp_vcpus(vcpu, &hyp_vcpu);
+	if (host_vcpu) {
+		__kvm_adjust_pc(host_vcpu);
+		return;
+	}
+
+	/*
+	 * With no hyp vCPU loaded for it, the host vCPU may be unpinned,
+	 * and so unmapped at EL2: its first run pins it. A pin fails only
+	 * for memory the host isn't sharing, a bad pointer, so the request
+	 * is dropped.
+	 */
+	host_vcpu = kern_hyp_va(vcpu);
+	if (hyp_pin_shared_mem(host_vcpu, host_vcpu + 1))
+		return;
+
+	__kvm_adjust_pc(host_vcpu);
+	hyp_unpin_shared_mem(host_vcpu, host_vcpu + 1);
 }
 
 static void handle___kvm_flush_vm_context(struct kvm_cpu_context *host_ctxt)
-- 
2.39.5



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

* [PATCH 6/7] KVM: arm64: vgic: Do not access the GICv5 CPU interface from EL1
  2026-09-15 12:38 [PATCH 0/7] KVM: arm64: pKVM host hypercall and GICv5 CPU interface fixes Fuad Tabba
                   ` (4 preceding siblings ...)
  2026-09-15 12:38 ` [PATCH 5/7] KVM: arm64: Pin the host vCPU before adjusting its PC " Fuad Tabba
@ 2026-09-15 12:38 ` Fuad Tabba
  2026-09-22  7:38   ` Fuad Tabba
  2026-09-15 12:38 ` [PATCH 7/7] KVM: arm64: Fix stale VGICv3 comments in the nVHE world switch Fuad Tabba
  6 siblings, 1 reply; 13+ messages in thread
From: Fuad Tabba @ 2026-09-15 12:38 UTC (permalink / raw)
  To: maz, oupton, kvmarm, linux-arm-kernel, linux-kernel
  Cc: catalin.marinas, will, joey.gouly, seiden, suzuki.poulose,
	yuzenghui, mark.rutland, vdonnefort, qperret, Sascha.Bischoff,
	steven.price, tabba

can_access_vgic_from_kernel() excludes only the GICv3 system register
interface, so on a native GICv5 system without FEAT_GCIE_LEGACY it
returns true under nVHE. The kernel then saves and restores the CPU
interface from EL1, where ICH_VMCR_EL2 and the ICH_PPI_* registers are
UNDEFINED, and the nVHE world switch already does that work at EL2.

Require VHE for GICv5 as for GICv3.

Fixes: 9b8e3d4ca0e73 ("KVM: arm64: gic-v5: Implement GICv5 load/put and save/restore")
Reviewed-by: Sascha Bischoff <sascha.bischoff@arm.com>
Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
---
 arch/arm64/kvm/vgic/vgic.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
index b25303d9919fd..da72779d3b3ee 100644
--- a/arch/arm64/kvm/vgic/vgic.c
+++ b/arch/arm64/kvm/vgic/vgic.c
@@ -1045,11 +1045,15 @@ static void vgic_flush_lr_state(struct kvm_vcpu *vcpu)
 static inline bool can_access_vgic_from_kernel(void)
 {
 	/*
-	 * GICv2 can always be accessed from the kernel because it is
-	 * memory-mapped, and VHE systems can access GICv3 EL2 system
-	 * registers.
+	 * GICv3 and GICv5 drive the CPU interface through EL2 system
+	 * registers, so only VHE reaches them from the kernel. GICv2 is
+	 * memory-mapped and always reachable.
 	 */
-	return !static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif) || has_vhe();
+	if (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif) ||
+	    kvm_vgic_global_state.type == VGIC_V5)
+		return has_vhe();
+
+	return true;
 }
 
 static inline void vgic_save_state(struct kvm_vcpu *vcpu)
-- 
2.39.5



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

* [PATCH 7/7] KVM: arm64: Fix stale VGICv3 comments in the nVHE world switch
  2026-09-15 12:38 [PATCH 0/7] KVM: arm64: pKVM host hypercall and GICv5 CPU interface fixes Fuad Tabba
                   ` (5 preceding siblings ...)
  2026-09-15 12:38 ` [PATCH 6/7] KVM: arm64: vgic: Do not access the GICv5 CPU interface from EL1 Fuad Tabba
@ 2026-09-15 12:38 ` Fuad Tabba
  6 siblings, 0 replies; 13+ messages in thread
From: Fuad Tabba @ 2026-09-15 12:38 UTC (permalink / raw)
  To: maz, oupton, kvmarm, linux-arm-kernel, linux-kernel
  Cc: catalin.marinas, will, joey.gouly, seiden, suzuki.poulose,
	yuzenghui, mark.rutland, vdonnefort, qperret, Sascha.Bischoff,
	steven.price, tabba

__hyp_vgic_save_state() and __hyp_vgic_restore_state() handle GICv5 as
well as GICv3, but their comments name VGICv3 only.

Reviewed-by: Sascha Bischoff <sascha.bischoff@arm.com>
Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
---
 arch/arm64/kvm/hyp/nvhe/switch.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/hyp/nvhe/switch.c b/arch/arm64/kvm/hyp/nvhe/switch.c
index 7318e3e6a5f36..6b9e20f6b31b3 100644
--- a/arch/arm64/kvm/hyp/nvhe/switch.c
+++ b/arch/arm64/kvm/hyp/nvhe/switch.c
@@ -110,7 +110,7 @@ static void __deactivate_traps(struct kvm_vcpu *vcpu)
 	write_sysreg(__kvm_hyp_host_vector, vbar_el2);
 }
 
-/* Save VGICv3 state on non-VHE systems */
+/* Save vgic state on non-VHE systems */
 static void __hyp_vgic_save_state(struct kvm_vcpu *vcpu)
 {
 	if (vgic_is_v5(kern_hyp_va(vcpu->kvm))) {
@@ -125,7 +125,7 @@ static void __hyp_vgic_save_state(struct kvm_vcpu *vcpu)
 	}
 }
 
-/* Restore VGICv3 state on non-VHE systems */
+/* Restore vgic state on non-VHE systems */
 static void __hyp_vgic_restore_state(struct kvm_vcpu *vcpu)
 {
 	if (vgic_is_v5(kern_hyp_va(vcpu->kvm))) {
-- 
2.39.5



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

* Re: [PATCH 1/7] KVM: arm64: Reject the GICv5 CPU interface hypercalls under pKVM
  2026-09-15 12:38 ` [PATCH 1/7] KVM: arm64: Reject the GICv5 CPU interface hypercalls under pKVM Fuad Tabba
@ 2026-09-15 14:02   ` Marc Zyngier
  2026-09-15 14:12     ` Fuad Tabba
  0 siblings, 1 reply; 13+ messages in thread
From: Marc Zyngier @ 2026-09-15 14:02 UTC (permalink / raw)
  To: Fuad Tabba
  Cc: oupton, kvmarm, linux-arm-kernel, linux-kernel, catalin.marinas,
	will, joey.gouly, seiden, suzuki.poulose, yuzenghui, mark.rutland,
	vdonnefort, qperret, Sascha.Bischoff, steven.price, tabba

On Tue, 15 Sep 2026 13:38:40 +0100,
Fuad Tabba <fuad.tabba@linux.dev> wrote:
>

[...]

> diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> index 9a3b92e626adb..7c939baf9c1ba 100644
> --- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> +++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> @@ -911,6 +911,8 @@ static const hcall_t host_hcall[] = {
>  	HANDLE_FUNC(__kvm_enable_ssbs),
>  	HANDLE_FUNC(__vgic_v3_init_lrs),
>  	HANDLE_FUNC(__vgic_v3_get_gic_config),
> +	HANDLE_FUNC(__vgic_v5_save_apr),
> +	HANDLE_FUNC(__vgic_v5_restore_vmcr_apr),
>  	HANDLE_FUNC(__pkvm_prot_finalize),
>  
>  	HANDLE_FUNC(__kvm_adjust_pc),
> @@ -932,8 +934,6 @@ static const hcall_t host_hcall[] = {
>  	HANDLE_FUNC(__tracing_write_event),
>  	HANDLE_FUNC(__vgic_v3_save_aprs),
>  	HANDLE_FUNC(__vgic_v3_restore_vmcr_aprs),
> -	HANDLE_FUNC(__vgic_v5_save_apr),
> -	HANDLE_FUNC(__vgic_v5_restore_vmcr_apr),
>  
>  	HANDLE_FUNC(__pkvm_host_share_hyp),
>  	HANDLE_FUNC(__pkvm_host_unshare_hyp),

Why moving things in the array? The whole point of HANDLE_FUNC() is to
abstract the position.

	M.

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


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

* Re: [PATCH 1/7] KVM: arm64: Reject the GICv5 CPU interface hypercalls under pKVM
  2026-09-15 14:02   ` Marc Zyngier
@ 2026-09-15 14:12     ` Fuad Tabba
  0 siblings, 0 replies; 13+ messages in thread
From: Fuad Tabba @ 2026-09-15 14:12 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: oupton, kvmarm, linux-arm-kernel, linux-kernel, catalin.marinas,
	will, joey.gouly, seiden, suzuki.poulose, yuzenghui, mark.rutland,
	vdonnefort, qperret, Sascha.Bischoff, steven.price

On Tue, 15 Sept 2026 at 15:02, Marc Zyngier <maz@kernel.org> wrote:
>
> On Tue, 15 Sep 2026 13:38:40 +0100,
> Fuad Tabba <fuad.tabba@linux.dev> wrote:
> >
>
> [...]
>
> > diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> > index 9a3b92e626adb..7c939baf9c1ba 100644
> > --- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> > +++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> > @@ -911,6 +911,8 @@ static const hcall_t host_hcall[] = {
> >       HANDLE_FUNC(__kvm_enable_ssbs),
> >       HANDLE_FUNC(__vgic_v3_init_lrs),
> >       HANDLE_FUNC(__vgic_v3_get_gic_config),
> > +     HANDLE_FUNC(__vgic_v5_save_apr),
> > +     HANDLE_FUNC(__vgic_v5_restore_vmcr_apr),
> >       HANDLE_FUNC(__pkvm_prot_finalize),
> >
> >       HANDLE_FUNC(__kvm_adjust_pc),
> > @@ -932,8 +934,6 @@ static const hcall_t host_hcall[] = {
> >       HANDLE_FUNC(__tracing_write_event),
> >       HANDLE_FUNC(__vgic_v3_save_aprs),
> >       HANDLE_FUNC(__vgic_v3_restore_vmcr_aprs),
> > -     HANDLE_FUNC(__vgic_v5_save_apr),
> > -     HANDLE_FUNC(__vgic_v5_restore_vmcr_apr),
> >
> >       HANDLE_FUNC(__pkvm_host_share_hyp),
> >       HANDLE_FUNC(__pkvm_host_unshare_hyp),
>
> Why moving things in the array? The whole point of HANDLE_FUNC() is to
> abstract the position.

It's only cosmetic. The array is in the same order as the enum today,
entry for entry.

Cheers,
/fuad

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


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

* Re: [PATCH 3/7] KVM: arm64: Validate the host-provided vgic model in pKVM
  2026-09-15 12:38 ` [PATCH 3/7] KVM: arm64: Validate the host-provided vgic model in pKVM Fuad Tabba
@ 2026-09-16 11:00   ` Joey Gouly
  2026-09-16 11:30     ` Fuad Tabba
  0 siblings, 1 reply; 13+ messages in thread
From: Joey Gouly @ 2026-09-16 11:00 UTC (permalink / raw)
  To: Fuad Tabba
  Cc: maz, oupton, kvmarm, linux-arm-kernel, linux-kernel,
	catalin.marinas, will, seiden, suzuki.poulose, yuzenghui,
	mark.rutland, vdonnefort, qperret, Sascha.Bischoff, steven.price,
	tabba

Question(s)
   |
   |
   v

On Tue, Sep 15, 2026 at 01:38:42PM +0100, Fuad Tabba wrote:
> EL2 copies vgic_model from the host's struct kvm unchecked, and the nVHE
> world switch dispatches on it with no cpucap guard. A host writing
> KVM_DEV_TYPE_ARM_VGIC_V5 makes EL2 access GICv5 CPU interface registers
> that are UNDEFINED without FEAT_GCIE, and panics the hypervisor on any
> GICv3 machine.
> 
> Accept only GICv3, the one model pKVM supports, forcing anything else
> to 0.
> 
> Fixes: 9b8e3d4ca0e73 ("KVM: arm64: gic-v5: Implement GICv5 load/put and save/restore")
> Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
> ---
>  arch/arm64/kvm/hyp/nvhe/pkvm.c | 10 ++++++++--
>  1 file changed, 8 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c
> index 459bd9eb7e4bc..4c33c863e90e1 100644
> --- a/arch/arm64/kvm/hyp/nvhe/pkvm.c
> +++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c
> @@ -340,13 +340,19 @@ static void pkvm_init_features_from_host(struct pkvm_hyp_vm *hyp_vm, const struc
>  {
>  	struct kvm *kvm = &hyp_vm->kvm;
>  	unsigned long host_arch_flags = READ_ONCE(host_kvm->arch.flags);
> +	u32 vgic_model = READ_ONCE(host_kvm->arch.vgic.vgic_model);
>  	DECLARE_BITMAP(allowed_features, KVM_VCPU_MAX_FEATURES);
>  
>  	/* CTR_EL0 is always under host control, even for protected VMs. */
>  	hyp_vm->kvm.arch.ctr_el0 = host_kvm->arch.ctr_el0;
>  
> -	/* Preserve the vgic model so that GICv3 emulation works */
> -	hyp_vm->kvm.arch.vgic.vgic_model = host_kvm->arch.vgic.vgic_model;
> +	/*
> +	 * GICv3 is the only model pKVM runs, and the GICv5 world switch
> +	 * touches registers UNDEFINED at EL2 without FEAT_GCIE.
> +	 */
> +	if (vgic_model != KVM_DEV_TYPE_ARM_VGIC_V3)
> +		vgic_model = 0;
> +	hyp_vm->kvm.arch.vgic.vgic_model = vgic_model;

A bit confused by what is expected by writing 0 here? I would have maybe
expected to refuse running this VM? What happens if the host writes some
garbage here, so vgic_model=0, but then tries to access gic-v3
registers?

Thanks,
Joey

>  
>  	/* No restrictions for non-protected VMs. */
>  	if (!kvm_vm_is_protected(kvm)) {
> -- 
> 2.39.5
> 


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

* Re: [PATCH 3/7] KVM: arm64: Validate the host-provided vgic model in pKVM
  2026-09-16 11:00   ` Joey Gouly
@ 2026-09-16 11:30     ` Fuad Tabba
  0 siblings, 0 replies; 13+ messages in thread
From: Fuad Tabba @ 2026-09-16 11:30 UTC (permalink / raw)
  To: Joey Gouly
  Cc: maz, oupton, kvmarm, linux-arm-kernel, linux-kernel,
	catalin.marinas, will, seiden, suzuki.poulose, yuzenghui,
	mark.rutland, vdonnefort, qperret, Sascha.Bischoff, steven.price

Hi Joey,

On Wed, 16 Sept 2026 at 12:00, Joey Gouly <joey.gouly@arm.com> wrote:
[...]
> > +       if (vgic_model != KVM_DEV_TYPE_ARM_VGIC_V3)
> > +               vgic_model = 0;
> > +       hyp_vm->kvm.arch.vgic.vgic_model = vgic_model;
>
> A bit confused by what is expected by writing 0 here? I would have maybe
> expected to refuse running this VM? What happens if the host writes some
> garbage here, so vgic_model=0, but then tries to access gic-v3
> registers?

0 is vgic_model for a VM with no in-kernel irqchip, which pKVM runs.
An unsupported model is treated the same, as a protected VM's features
are masked rather than rejected.

At EL2 the model only selects the GICv5 world-switch path (GICv3 is
saved and restored under the gicv3_cpuif static key) and gates
__vgic_v3_perform_cpuif_access(), which returns 0 for anything but V3
and leaves a trapped ICC_* access to the host. A host that writes a
model it doesn't have gets a guest without a working GIC, which it can
do anyway, but can't make EL2 run the GICv5 path on a GICv3 machine.

I'll say so in the comment if I respin.

Cheers,
/fuad


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

* Re: [PATCH 6/7] KVM: arm64: vgic: Do not access the GICv5 CPU interface from EL1
  2026-09-15 12:38 ` [PATCH 6/7] KVM: arm64: vgic: Do not access the GICv5 CPU interface from EL1 Fuad Tabba
@ 2026-09-22  7:38   ` Fuad Tabba
  0 siblings, 0 replies; 13+ messages in thread
From: Fuad Tabba @ 2026-09-22  7:38 UTC (permalink / raw)
  To: maz, oupton, kvmarm, linux-arm-kernel
  Cc: catalin.marinas, will, joey.gouly, seiden, suzuki.poulose,
	yuzenghui, mark.rutland, vdonnefort, qperret, Sascha.Bischoff,
	steven.price

Hi,

On Tue, 15 Sep 2026 13:38:45 +0100, Fuad Tabba <fuad.tabba@linux.dev> wrote:
> can_access_vgic_from_kernel() excludes only the GICv3 system register
> interface, so on a native GICv5 system without FEAT_GCIE_LEGACY it
> returns true under nVHE. The kernel then saves and restores the CPU
> interface from EL1, where ICH_VMCR_EL2 and the ICH_PPI_* registers are
> UNDEFINED, and the nVHE world switch already does that work at EL2.

FWIW, I've since run this on the FVP GICv5 model (support_virtualization=1, kvm-arm.mode=nvhe). On kvmarm/next at 23ddf997ab16b the vgic_v5 selftest oopses the host at the first KVM_RUN:

  Internal error: Oops - Undefined instruction: 0000000002000000 [#1]  SMP
  pc : __vgic_v5_restore_ppi_state+0x10/0x9c
  lr : vgic_v5_restore_state+0x28/0x3c
  Code: d503245f a941240a d0012448 91160108 (d51cca0a)

d51cca0a is the ICH_PPI_DVIR0_EL2 write, from EL1. With this patch applied the same run passes.

Cheers,
/fuad


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

end of thread, other threads:[~2026-09-22  7:38 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-15 12:38 [PATCH 0/7] KVM: arm64: pKVM host hypercall and GICv5 CPU interface fixes Fuad Tabba
2026-09-15 12:38 ` [PATCH 1/7] KVM: arm64: Reject the GICv5 CPU interface hypercalls under pKVM Fuad Tabba
2026-09-15 14:02   ` Marc Zyngier
2026-09-15 14:12     ` Fuad Tabba
2026-09-15 12:38 ` [PATCH 2/7] KVM: arm64: Reject the stage-2 flush " Fuad Tabba
2026-09-15 12:38 ` [PATCH 3/7] KVM: arm64: Validate the host-provided vgic model in pKVM Fuad Tabba
2026-09-16 11:00   ` Joey Gouly
2026-09-16 11:30     ` Fuad Tabba
2026-09-15 12:38 ` [PATCH 4/7] KVM: arm64: Validate the host vCPU's VM before reading it under pKVM Fuad Tabba
2026-09-15 12:38 ` [PATCH 5/7] KVM: arm64: Pin the host vCPU before adjusting its PC " Fuad Tabba
2026-09-15 12:38 ` [PATCH 6/7] KVM: arm64: vgic: Do not access the GICv5 CPU interface from EL1 Fuad Tabba
2026-09-22  7:38   ` Fuad Tabba
2026-09-15 12:38 ` [PATCH 7/7] KVM: arm64: Fix stale VGICv3 comments in the nVHE world switch Fuad Tabba

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.