Skip to content

Commit 87727ba

Browse files
committed
KVM: arm64: Ensure CPU PMU probes before pKVM host de-privilege
Although pKVM supports CPU PMU emulation for non-protected guests since 722625c ("KVM: arm64: Reenable pmu in Protected Mode"), this relies on the PMU driver probing before the host has de-privileged so that the 'kvm_arm_pmu_available' static key can still be enabled by patching the hypervisor text. As it happens, both of these events hang off device_initcall() but the PMU consistently won the race until 7755cec ("arm64: perf: Move PMUv3 driver to drivers/perf"). Since then, the host will fail to boot when pKVM is enabled: | hw perfevents: enabled with armv8_pmuv3_0 PMU driver, 7 counters available | kvm [1]: nVHE hyp BUG at: [<ffff8000090366e0>] __kvm_nvhe_handle_host_mem_abort+0x270/0x284! | kvm [1]: Cannot dump pKVM nVHE stacktrace: !CONFIG_PROTECTED_NVHE_STACKTRACE | kvm [1]: Hyp Offset: 0xfffea41fbdf70000 | Kernel panic - not syncing: HYP panic: | PS:a00003c9 PC:0000dbe04b0c66e0 ESR:00000000f2000800 | FAR:fffffbfffddfcf00 HPFAR:00000000010b0bf0 PAR:0000000000000000 | VCPU:0000000000000000 | CPU: 2 PID: 1 Comm: swapper/0 Not tainted 6.3.0-rc7-00083-g0bce6746d154 #1 | Hardware name: QEMU QEMU Virtual Machine, BIOS 0.0.0 02/06/2015 | Call trace: | dump_backtrace+0xec/0x108 | show_stack+0x18/0x2c | dump_stack_lvl+0x50/0x68 | dump_stack+0x18/0x24 | panic+0x13c/0x33c | nvhe_hyp_panic_handler+0x10c/0x190 | aarch64_insn_patch_text_nosync+0x64/0xc8 | arch_jump_label_transform+0x4c/0x5c | __jump_label_update+0x84/0xfc | jump_label_update+0x100/0x134 | static_key_enable_cpuslocked+0x68/0xac | static_key_enable+0x20/0x34 | kvm_host_pmu_init+0x88/0xa4 | armpmu_register+0xf0/0xf4 | arm_pmu_acpi_probe+0x2ec/0x368 | armv8_pmu_driver_init+0x38/0x44 | do_one_initcall+0xcc/0x240 Fix the race properly by deferring the de-privilege step to device_initcall_sync(). This will also be needed in future when probing IOMMU devices and allows us to separate the pKVM de-privilege logic from the core hypervisor initialisation path. Cc: Oliver Upton <[email protected]> Cc: Fuad Tabba <[email protected]> Cc: Marc Zyngier <[email protected]> Fixes: 7755cec ("arm64: perf: Move PMUv3 driver to drivers/perf") Tested-by: Fuad Tabba <[email protected]> Acked-by: Marc Zyngier <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Will Deacon <[email protected]>
1 parent 257aedb commit 87727ba

File tree

2 files changed

+47
-45
lines changed

2 files changed

+47
-45
lines changed

arch/arm64/kvm/arm.c

Lines changed: 0 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
#include <linux/fs.h>
1717
#include <linux/mman.h>
1818
#include <linux/sched.h>
19-
#include <linux/kmemleak.h>
2019
#include <linux/kvm.h>
2120
#include <linux/kvm_irqfd.h>
2221
#include <linux/irqbypass.h>
@@ -46,7 +45,6 @@
4645
#include <kvm/arm_psci.h>
4746

4847
static enum kvm_mode kvm_mode = KVM_MODE_DEFAULT;
49-
DEFINE_STATIC_KEY_FALSE(kvm_protected_mode_initialized);
5048

5149
DECLARE_KVM_HYP_PER_CPU(unsigned long, kvm_hyp_vector);
5250

@@ -2105,41 +2103,6 @@ static int __init init_hyp_mode(void)
21052103
return err;
21062104
}
21072105

2108-
static void __init _kvm_host_prot_finalize(void *arg)
2109-
{
2110-
int *err = arg;
2111-
2112-
if (WARN_ON(kvm_call_hyp_nvhe(__pkvm_prot_finalize)))
2113-
WRITE_ONCE(*err, -EINVAL);
2114-
}
2115-
2116-
static int __init pkvm_drop_host_privileges(void)
2117-
{
2118-
int ret = 0;
2119-
2120-
/*
2121-
* Flip the static key upfront as that may no longer be possible
2122-
* once the host stage 2 is installed.
2123-
*/
2124-
static_branch_enable(&kvm_protected_mode_initialized);
2125-
on_each_cpu(_kvm_host_prot_finalize, &ret, 1);
2126-
return ret;
2127-
}
2128-
2129-
static int __init finalize_hyp_mode(void)
2130-
{
2131-
if (!is_protected_kvm_enabled())
2132-
return 0;
2133-
2134-
/*
2135-
* Exclude HYP sections from kmemleak so that they don't get peeked
2136-
* at, which would end badly once inaccessible.
2137-
*/
2138-
kmemleak_free_part(__hyp_bss_start, __hyp_bss_end - __hyp_bss_start);
2139-
kmemleak_free_part_phys(hyp_mem_base, hyp_mem_size);
2140-
return pkvm_drop_host_privileges();
2141-
}
2142-
21432106
struct kvm_vcpu *kvm_mpidr_to_vcpu(struct kvm *kvm, unsigned long mpidr)
21442107
{
21452108
struct kvm_vcpu *vcpu;
@@ -2257,14 +2220,6 @@ static __init int kvm_arm_init(void)
22572220
if (err)
22582221
goto out_hyp;
22592222

2260-
if (!in_hyp_mode) {
2261-
err = finalize_hyp_mode();
2262-
if (err) {
2263-
kvm_err("Failed to finalize Hyp protection\n");
2264-
goto out_subs;
2265-
}
2266-
}
2267-
22682223
if (is_protected_kvm_enabled()) {
22692224
kvm_info("Protected nVHE mode initialized successfully\n");
22702225
} else if (in_hyp_mode) {

arch/arm64/kvm/pkvm.c

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
* Author: Quentin Perret <[email protected]>
55
*/
66

7+
#include <linux/init.h>
8+
#include <linux/kmemleak.h>
79
#include <linux/kvm_host.h>
810
#include <linux/memblock.h>
911
#include <linux/mutex.h>
@@ -13,6 +15,8 @@
1315

1416
#include "hyp_constants.h"
1517

18+
DEFINE_STATIC_KEY_FALSE(kvm_protected_mode_initialized);
19+
1620
static struct memblock_region *hyp_memory = kvm_nvhe_sym(hyp_memory);
1721
static unsigned int *hyp_memblock_nr_ptr = &kvm_nvhe_sym(hyp_memblock_nr);
1822

@@ -213,3 +217,46 @@ int pkvm_init_host_vm(struct kvm *host_kvm)
213217
mutex_init(&host_kvm->lock);
214218
return 0;
215219
}
220+
221+
static void __init _kvm_host_prot_finalize(void *arg)
222+
{
223+
int *err = arg;
224+
225+
if (WARN_ON(kvm_call_hyp_nvhe(__pkvm_prot_finalize)))
226+
WRITE_ONCE(*err, -EINVAL);
227+
}
228+
229+
static int __init pkvm_drop_host_privileges(void)
230+
{
231+
int ret = 0;
232+
233+
/*
234+
* Flip the static key upfront as that may no longer be possible
235+
* once the host stage 2 is installed.
236+
*/
237+
static_branch_enable(&kvm_protected_mode_initialized);
238+
on_each_cpu(_kvm_host_prot_finalize, &ret, 1);
239+
return ret;
240+
}
241+
242+
static int __init finalize_pkvm(void)
243+
{
244+
int ret;
245+
246+
if (!is_protected_kvm_enabled())
247+
return 0;
248+
249+
/*
250+
* Exclude HYP sections from kmemleak so that they don't get peeked
251+
* at, which would end badly once inaccessible.
252+
*/
253+
kmemleak_free_part(__hyp_bss_start, __hyp_bss_end - __hyp_bss_start);
254+
kmemleak_free_part_phys(hyp_mem_base, hyp_mem_size);
255+
256+
ret = pkvm_drop_host_privileges();
257+
if (ret)
258+
pr_err("Failed to finalize Hyp protection: %d\n", ret);
259+
260+
return ret;
261+
}
262+
device_initcall_sync(finalize_pkvm);

0 commit comments

Comments
 (0)