[PATCH v2 2/4] KVM: arm64: pkvm: Fix missing reset of GICv3 LRs
Vincent Donnefort
vdonnefort at google.com
Thu Oct 22 07:00:46 PDT 2026
The vGIC LRs are architecturally UNKNOWN when the CPU boots or resumes.
However, in protected mode, only the used ones are reset, because the
HVC __vgic_v3_init_lrs() is never called:
* During boot, vgic_present is only set in init_subsystems(), after
cpu_hyp_init() was called.
* During CPU hotplug, kvm_arch_enable_virtualization_cpu() never calls
it either because kvm_hyp_initialized is always set.
* During CPU resume, no notifier is registered for pKVM.
First, return the error of __hyp_reset_vectors(). On an error, we know
the hypervisor doesn't allow a reset. Only re-init what the host has
access to, no matter the KVM configuration, which is the vGIC LRs.
Then, cpu_hyp_init() is only called from init_subsystems and
kvm_arch_enable_virtualization_cpu(). Remove the kvm_hyp_initialized
gate: when pKVM is enabled, the cpu_hyp_reset() will just return an
error while for other modes, we already know kvm_hyp_initialized is
false at this point.
Finally, enable the PM notifiers for pKVM, it is now safe to do so. It
will ensure the host properly configures the vGIC LRs regardless of the
KVM configuration.
Fixes: fa8c3d65538a ("KVM: arm64: Keep nVHE EL2 vector installed")
Signed-off-by: Vincent Donnefort <vdonnefort at google.com>
---
arch/arm64/include/asm/virt.h | 2 +-
arch/arm64/kvm/arm.c | 51 +++++++++++++++++++----------------
2 files changed, 29 insertions(+), 24 deletions(-)
diff --git a/arch/arm64/include/asm/virt.h b/arch/arm64/include/asm/virt.h
index b546703c3ab9..a5bde8cc5df5 100644
--- a/arch/arm64/include/asm/virt.h
+++ b/arch/arm64/include/asm/virt.h
@@ -83,7 +83,7 @@ extern u32 __boot_cpu_mode[2];
#define ARM64_VECTOR_TABLE_LEN SZ_2K
void __hyp_set_vectors(phys_addr_t phys_vector_base);
-void __hyp_reset_vectors(void);
+int __hyp_reset_vectors(void);
bool is_kvm_arm_initialised(void);
DECLARE_STATIC_KEY_FALSE(kvm_protected_mode_initialized);
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 0576c2022ef5..4c4e2fb7b660 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -2246,10 +2246,12 @@ static void cpu_init_hyp_mode(void)
}
}
-static void cpu_hyp_reset(void)
+static int cpu_hyp_reset(void)
{
if (!is_kernel_in_hyp_mode())
- __hyp_reset_vectors();
+ return __hyp_reset_vectors() ? -EPERM : 0;
+
+ return 0;
}
/*
@@ -2300,32 +2302,39 @@ static void cpu_hyp_init_features(void)
kvm_timer_init_vhe();
kvm_debug_init_vhe();
}
-
- if (vgic_present)
- kvm_vgic_init_cpu_hardware();
}
static void cpu_hyp_reinit(void)
{
- cpu_hyp_reset();
- cpu_hyp_init_context();
- cpu_hyp_init_features();
+ if (!cpu_hyp_reset()) {
+ cpu_hyp_init_context();
+ cpu_hyp_init_features();
+ } else {
+ if (WARN_ON(!__this_cpu_read(kvm_hyp_initialized)))
+ return;
+ }
+
+ /*
+ * Even if the hypervisor didn't allow resetting the vectors we can
+ * reset what we have access to.
+ */
+ if (vgic_present)
+ kvm_vgic_init_cpu_hardware();
}
static void cpu_hyp_init(void *discard)
{
- if (!__this_cpu_read(kvm_hyp_initialized)) {
- cpu_hyp_reinit();
- __this_cpu_write(kvm_hyp_initialized, 1);
- }
+ cpu_hyp_reinit();
+ __this_cpu_write(kvm_hyp_initialized, 1);
}
static void cpu_hyp_uninit(void *discard)
{
- if (!is_protected_kvm_enabled() && __this_cpu_read(kvm_hyp_initialized)) {
- cpu_hyp_reset();
+ if (!__this_cpu_read(kvm_hyp_initialized))
+ return;
+
+ if (!cpu_hyp_reset())
__this_cpu_write(kvm_hyp_initialized, 0);
- }
}
int kvm_arch_enable_virtualization_cpu(void)
@@ -2353,8 +2362,7 @@ void kvm_arch_disable_virtualization_cpu(void)
kvm_timer_cpu_down();
kvm_vgic_cpu_down();
- if (!is_protected_kvm_enabled())
- cpu_hyp_uninit(NULL);
+ cpu_hyp_uninit(NULL);
}
#ifdef CONFIG_CPU_PM
@@ -2397,13 +2405,11 @@ static struct notifier_block hyp_init_cpu_pm_nb = {
static void __init hyp_cpu_pm_init(void)
{
- if (!is_protected_kvm_enabled())
- cpu_pm_register_notifier(&hyp_init_cpu_pm_nb);
+ cpu_pm_register_notifier(&hyp_init_cpu_pm_nb);
}
static void __init hyp_cpu_pm_exit(void)
{
- if (!is_protected_kvm_enabled())
- cpu_pm_unregister_notifier(&hyp_init_cpu_pm_nb);
+ cpu_pm_unregister_notifier(&hyp_init_cpu_pm_nb);
}
#else
static inline void __init hyp_cpu_pm_init(void)
@@ -2526,8 +2532,7 @@ static int __init init_subsystems(void)
if (err)
hyp_cpu_pm_exit();
- if (err || !is_protected_kvm_enabled())
- on_each_cpu(cpu_hyp_uninit, NULL, 1);
+ on_each_cpu(cpu_hyp_uninit, NULL, 1);
return err;
}
--
2.56.0.257.gf7497c7d27-goog
More information about the linux-arm-kernel
mailing list