* [PATCH v2 0/5] KVM: arm64: pKVM host hypercall and GICv5 CPU interface fixes
@ 2026-10-11 14:36 Fuad Tabba
2026-10-11 14:36 ` [PATCH v2 1/5] KVM: arm64: Reject the GICv5 CPU interface hypercalls under pKVM Fuad Tabba
` (4 more replies)
0 siblings, 5 replies; 11+ messages in thread
From: Fuad Tabba @ 2026-10-11 14:36 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,
Changes since v1 [1]:
- Dropped the two __kvm_adjust_pc() fixes (v1's patches 4 and 5),
which went into kvmarm/next with the pKVM core series [2].
- Minor wording fixes to a comment and the commit messages. (Joey)
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, since the host has no use for them in protected mode.
Patch 3 validates the vgic model EL2 copies from the host. Patch 4
stops nVHE from accessing the GICv5 CPU interface from EL1, and patch
5 fixes two stale comments.
The GICv5 residency and VDPEND hypercalls in kvmarm/next still check
for pKVM in each handler. I'll move them into the same band once this
lands.
Based on Linux 7.3-rc3 (fd73f4a665989). On kvmarm/next, patches 1 and
2 have a minor conflict: new hypercall IDs sit next to the ones they
move.
Cheers,
/fuad
[1] https://lore.kernel.org/all/20260915123846.2317931-1-fuad.tabba@linux.dev/
[2] https://lore.kernel.org/all/20261001135711.1640520-1-fuad.tabba@linux.dev/
Fuad Tabba (5):
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: 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/nvhe/hyp-main.c | 15 ++++++++-------
arch/arm64/kvm/hyp/nvhe/pkvm.c | 10 ++++++++--
arch/arm64/kvm/hyp/nvhe/switch.c | 4 ++--
arch/arm64/kvm/vgic/vgic.c | 12 ++++++++----
5 files changed, 34 insertions(+), 23 deletions(-)
base-commit: fd73f4a6659897191fa0d40695fe370925dd3780
--
2.39.5
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v2 1/5] KVM: arm64: Reject the GICv5 CPU interface hypercalls under pKVM
2026-10-11 14:36 [PATCH v2 0/5] KVM: arm64: pKVM host hypercall and GICv5 CPU interface fixes Fuad Tabba
@ 2026-10-11 14:36 ` Fuad Tabba
2026-10-12 10:43 ` Suzuki K Poulose
2026-10-11 14:36 ` [PATCH v2 2/5] KVM: arm64: Reject the stage-2 flush " Fuad Tabba
` (3 subsequent siblings)
4 siblings, 1 reply; 11+ messages in thread
From: Fuad Tabba @ 2026-10-11 14:36 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 [flat|nested] 11+ messages in thread
* [PATCH v2 2/5] KVM: arm64: Reject the stage-2 flush hypercalls under pKVM
2026-10-11 14:36 [PATCH v2 0/5] KVM: arm64: pKVM host hypercall and GICv5 CPU interface fixes Fuad Tabba
2026-10-11 14:36 ` [PATCH v2 1/5] KVM: arm64: Reject the GICv5 CPU interface hypercalls under pKVM Fuad Tabba
@ 2026-10-11 14:36 ` Fuad Tabba
2026-10-12 12:03 ` Suzuki K Poulose
2026-10-11 14:36 ` [PATCH v2 3/5] KVM: arm64: Validate the host-provided vgic model in pKVM Fuad Tabba
` (2 subsequent siblings)
4 siblings, 1 reply; 11+ messages in thread
From: Fuad Tabba @ 2026-10-11 14:36 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 [flat|nested] 11+ messages in thread
* [PATCH v2 3/5] KVM: arm64: Validate the host-provided vgic model in pKVM
2026-10-11 14:36 [PATCH v2 0/5] KVM: arm64: pKVM host hypercall and GICv5 CPU interface fixes Fuad Tabba
2026-10-11 14:36 ` [PATCH v2 1/5] KVM: arm64: Reject the GICv5 CPU interface hypercalls under pKVM Fuad Tabba
2026-10-11 14:36 ` [PATCH v2 2/5] KVM: arm64: Reject the stage-2 flush " Fuad Tabba
@ 2026-10-11 14:36 ` Fuad Tabba
2026-10-12 12:15 ` Suzuki K Poulose
2026-10-11 14:36 ` [PATCH v2 4/5] KVM: arm64: vgic: Do not access the GICv5 CPU interface from EL1 Fuad Tabba
2026-10-11 14:36 ` [PATCH v2 5/5] KVM: arm64: Fix stale VGICv3 comments in the nVHE world switch Fuad Tabba
4 siblings, 1 reply; 11+ messages in thread
From: Fuad Tabba @ 2026-10-11 14:36 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, and force anything else
to 0, as for a VM with no in-kernel irqchip. EL2 reads the model only to
pick the GICv5 world switch and to emulate GICv3 CPU interface accesses,
and the host's own copy is left alone.
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..a9d0e94709199 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;
+ /*
+ * pKVM runs only GICv3. Anything else becomes 0, the model of a VM
+ * with no in-kernel irqchip, which keeps EL2 off the GICv5 registers.
+ */
+ 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 [flat|nested] 11+ messages in thread
* [PATCH v2 4/5] KVM: arm64: vgic: Do not access the GICv5 CPU interface from EL1
2026-10-11 14:36 [PATCH v2 0/5] KVM: arm64: pKVM host hypercall and GICv5 CPU interface fixes Fuad Tabba
` (2 preceding siblings ...)
2026-10-11 14:36 ` [PATCH v2 3/5] KVM: arm64: Validate the host-provided vgic model in pKVM Fuad Tabba
@ 2026-10-11 14:36 ` Fuad Tabba
2026-10-11 15:10 ` Marc Zyngier
2026-10-11 14:36 ` [PATCH v2 5/5] KVM: arm64: Fix stale VGICv3 comments in the nVHE world switch Fuad Tabba
4 siblings, 1 reply; 11+ messages in thread
From: Fuad Tabba @ 2026-10-11 14:36 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, so running a vCPU oopses the host. 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 [flat|nested] 11+ messages in thread
* [PATCH v2 5/5] KVM: arm64: Fix stale VGICv3 comments in the nVHE world switch
2026-10-11 14:36 [PATCH v2 0/5] KVM: arm64: pKVM host hypercall and GICv5 CPU interface fixes Fuad Tabba
` (3 preceding siblings ...)
2026-10-11 14:36 ` [PATCH v2 4/5] KVM: arm64: vgic: Do not access the GICv5 CPU interface from EL1 Fuad Tabba
@ 2026-10-11 14:36 ` Fuad Tabba
4 siblings, 0 replies; 11+ messages in thread
From: Fuad Tabba @ 2026-10-11 14:36 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 [flat|nested] 11+ messages in thread
* Re: [PATCH v2 4/5] KVM: arm64: vgic: Do not access the GICv5 CPU interface from EL1
2026-10-11 14:36 ` [PATCH v2 4/5] KVM: arm64: vgic: Do not access the GICv5 CPU interface from EL1 Fuad Tabba
@ 2026-10-11 15:10 ` Marc Zyngier
2026-10-11 15:26 ` Fuad Tabba
0 siblings, 1 reply; 11+ messages in thread
From: Marc Zyngier @ 2026-10-11 15:10 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 Sun, 11 Oct 2026 15:36:47 +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, so running a vCPU oopses the host. 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;
This really is perpetuating the wrong model. The rule is simple:
anything that requires system instructions or system registers cannot
be accessed from EL1, and therefore GICv2 is the only one that can be
accessed from EL1. So the whole thing should read:
return has_vhe() || kvm_vgic_global_state.type == VGIC_V2;
Ultimately, we should static keys for all of the vgic types.
M.
--
Jazz isn't dead. It just smells funny.
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v2 4/5] KVM: arm64: vgic: Do not access the GICv5 CPU interface from EL1
2026-10-11 15:10 ` Marc Zyngier
@ 2026-10-11 15:26 ` Fuad Tabba
0 siblings, 0 replies; 11+ messages in thread
From: Fuad Tabba @ 2026-10-11 15:26 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
Hi Marc,
On Sun, 11 Oct 2026 16:10:19 +0100, Marc Zyngier <maz@kernel.org> wrote:
[...]
> This really is perpetuating the wrong model. The rule is simple:
> anything that requires system instructions or system registers cannot
> be accessed from EL1, and therefore GICv2 is the only one that can be
> accessed from EL1. So the whole thing should read:
>
> return has_vhe() || kvm_vgic_global_state.type == VGIC_V2;
Ack, I'll respin it that way.
> Ultimately, we should static keys for all of the vgic types.
I'll do that as a follow-up once the merge window is over.
Cheers,
/fuad
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v2 1/5] KVM: arm64: Reject the GICv5 CPU interface hypercalls under pKVM
2026-10-11 14:36 ` [PATCH v2 1/5] KVM: arm64: Reject the GICv5 CPU interface hypercalls under pKVM Fuad Tabba
@ 2026-10-12 10:43 ` Suzuki K Poulose
0 siblings, 0 replies; 11+ messages in thread
From: Suzuki K Poulose @ 2026-10-12 10:43 UTC (permalink / raw)
To: Fuad Tabba, maz, oupton, kvmarm, linux-arm-kernel, linux-kernel
Cc: catalin.marinas, will, joey.gouly, seiden, yuzenghui,
mark.rutland, vdonnefort, qperret, Sascha.Bischoff, steven.price,
tabba
On 11/10/2026 15:36, Fuad Tabba wrote:
> __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),
>
Any calls above are rejected after pKVM is initialized, so the calls are
indeed rejected.
Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v2 2/5] KVM: arm64: Reject the stage-2 flush hypercalls under pKVM
2026-10-11 14:36 ` [PATCH v2 2/5] KVM: arm64: Reject the stage-2 flush " Fuad Tabba
@ 2026-10-12 12:03 ` Suzuki K Poulose
0 siblings, 0 replies; 11+ messages in thread
From: Suzuki K Poulose @ 2026-10-12 12:03 UTC (permalink / raw)
To: Fuad Tabba, maz, oupton, kvmarm, linux-arm-kernel, linux-kernel
Cc: catalin.marinas, will, joey.gouly, seiden, yuzenghui,
mark.rutland, vdonnefort, qperret, Sascha.Bischoff, steven.price,
tabba
On 11/10/2026 15:36, Fuad Tabba wrote:
> 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,
For a moment (pardon my inexperience with pKVM code base) I thought we
could get this called via
pkvm_stage2_relax_perms() ->... kvm_stage2_relax_perms() for the host,
but we are in EL2 already and it is a direct call.
So, yes makes sense to me.
FWIW:
Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
> + __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
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v2 3/5] KVM: arm64: Validate the host-provided vgic model in pKVM
2026-10-11 14:36 ` [PATCH v2 3/5] KVM: arm64: Validate the host-provided vgic model in pKVM Fuad Tabba
@ 2026-10-12 12:15 ` Suzuki K Poulose
0 siblings, 0 replies; 11+ messages in thread
From: Suzuki K Poulose @ 2026-10-12 12:15 UTC (permalink / raw)
To: Fuad Tabba, maz, oupton, kvmarm, linux-arm-kernel, linux-kernel
Cc: catalin.marinas, will, joey.gouly, seiden, yuzenghui,
mark.rutland, vdonnefort, qperret, Sascha.Bischoff, steven.price,
tabba
On 11/10/2026 15:36, 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, and force anything else
> to 0, as for a VM with no in-kernel irqchip. EL2 reads the model only to
> pick the GICv5 world switch and to emulate GICv3 CPU interface accesses,
> and the host's own copy is left alone.
>
> 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..a9d0e94709199 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;
> + /*
> + * pKVM runs only GICv3. Anything else becomes 0, the model of a VM
> + * with no in-kernel irqchip, which keeps EL2 off the GICv5 registers.
> + */
> + if (vgic_model != KVM_DEV_TYPE_ARM_VGIC_V3)
> + vgic_model = 0;
> + hyp_vm->kvm.arch.vgic.vgic_model = vgic_model;
0 is not a valid KVM_DEV_TYPE_*, so this looks good to me.
Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2026-10-12 12:15 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-11 14:36 [PATCH v2 0/5] KVM: arm64: pKVM host hypercall and GICv5 CPU interface fixes Fuad Tabba
2026-10-11 14:36 ` [PATCH v2 1/5] KVM: arm64: Reject the GICv5 CPU interface hypercalls under pKVM Fuad Tabba
2026-10-12 10:43 ` Suzuki K Poulose
2026-10-11 14:36 ` [PATCH v2 2/5] KVM: arm64: Reject the stage-2 flush " Fuad Tabba
2026-10-12 12:03 ` Suzuki K Poulose
2026-10-11 14:36 ` [PATCH v2 3/5] KVM: arm64: Validate the host-provided vgic model in pKVM Fuad Tabba
2026-10-12 12:15 ` Suzuki K Poulose
2026-10-11 14:36 ` [PATCH v2 4/5] KVM: arm64: vgic: Do not access the GICv5 CPU interface from EL1 Fuad Tabba
2026-10-11 15:10 ` Marc Zyngier
2026-10-11 15:26 ` Fuad Tabba
2026-10-11 14:36 ` [PATCH v2 5/5] KVM: arm64: Fix stale VGICv3 comments in the nVHE world switch Fuad Tabba
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®