Skip to content

Commit

Permalink
x86/kvm: Disable all PV features on crash
Browse files Browse the repository at this point in the history
Crash shutdown handler only disables kvmclock and steal time, other PV
features remain active so we risk corrupting memory or getting some
side-effects in kdump kernel. Move crash handler to kvm.c and unify
with CPU offline.

Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
Message-Id: <20210414123544.1060604-5-vkuznets@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
  • Loading branch information
Vitaly Kuznetsov authored and Paolo Bonzini committed May 7, 2021
1 parent c02027b commit 3d6b841
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 39 deletions.
6 changes: 0 additions & 6 deletions arch/x86/include/asm/kvm_para.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,6 @@ unsigned int kvm_arch_para_hints(void);
void kvm_async_pf_task_wait_schedule(u32 token);
void kvm_async_pf_task_wake(u32 token);
u32 kvm_read_and_reset_apf_flags(void);
void kvm_disable_steal_time(void);
bool __kvm_handle_async_pf(struct pt_regs *regs, u32 token);

DECLARE_STATIC_KEY_FALSE(kvm_async_pf_enabled);
Expand Down Expand Up @@ -137,11 +136,6 @@ static inline u32 kvm_read_and_reset_apf_flags(void)
return 0;
}

static inline void kvm_disable_steal_time(void)
{
return;
}

static __always_inline bool kvm_handle_async_pf(struct pt_regs *regs, u32 token)
{
return false;
Expand Down
44 changes: 32 additions & 12 deletions arch/x86/kernel/kvm.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include <asm/tlb.h>
#include <asm/cpuidle_haltpoll.h>
#include <asm/ptrace.h>
#include <asm/reboot.h>
#include <asm/svm.h>

DEFINE_STATIC_KEY_FALSE(kvm_async_pf_enabled);
Expand Down Expand Up @@ -375,6 +376,14 @@ static void kvm_pv_disable_apf(void)
pr_info("disable async PF for cpu %d\n", smp_processor_id());
}

static void kvm_disable_steal_time(void)
{
if (!has_steal_clock)
return;

wrmsr(MSR_KVM_STEAL_TIME, 0, 0);
}

static void kvm_pv_guest_cpu_reboot(void *unused)
{
/*
Expand Down Expand Up @@ -417,14 +426,6 @@ static u64 kvm_steal_clock(int cpu)
return steal;
}

void kvm_disable_steal_time(void)
{
if (!has_steal_clock)
return;

wrmsr(MSR_KVM_STEAL_TIME, 0, 0);
}

static inline void __set_percpu_decrypted(void *ptr, unsigned long size)
{
early_set_memory_decrypted((unsigned long) ptr, size);
Expand Down Expand Up @@ -452,13 +453,14 @@ static void __init sev_map_percpu_data(void)
}
}

static void kvm_guest_cpu_offline(void)
static void kvm_guest_cpu_offline(bool shutdown)
{
kvm_disable_steal_time();
if (kvm_para_has_feature(KVM_FEATURE_PV_EOI))
wrmsrl(MSR_KVM_PV_EOI_EN, 0);
kvm_pv_disable_apf();
apf_task_wake_all();
if (!shutdown)
apf_task_wake_all();
kvmclock_disable();
}

Expand Down Expand Up @@ -661,7 +663,7 @@ static int kvm_cpu_down_prepare(unsigned int cpu)
unsigned long flags;

local_irq_save(flags);
kvm_guest_cpu_offline();
kvm_guest_cpu_offline(false);
local_irq_restore(flags);
return 0;
}
Expand All @@ -670,7 +672,7 @@ static int kvm_cpu_down_prepare(unsigned int cpu)

static int kvm_suspend(void)
{
kvm_guest_cpu_offline();
kvm_guest_cpu_offline(false);

return 0;
}
Expand All @@ -685,6 +687,20 @@ static struct syscore_ops kvm_syscore_ops = {
.resume = kvm_resume,
};

/*
* After a PV feature is registered, the host will keep writing to the
* registered memory location. If the guest happens to shutdown, this memory
* won't be valid. In cases like kexec, in which you install a new kernel, this
* means a random memory location will be kept being written.
*/
#ifdef CONFIG_KEXEC_CORE
static void kvm_crash_shutdown(struct pt_regs *regs)
{
kvm_guest_cpu_offline(true);
native_machine_crash_shutdown(regs);
}
#endif

static void __init kvm_guest_init(void)
{
int i;
Expand Down Expand Up @@ -727,6 +743,10 @@ static void __init kvm_guest_init(void)
kvm_guest_cpu_init();
#endif

#ifdef CONFIG_KEXEC_CORE
machine_ops.crash_shutdown = kvm_crash_shutdown;
#endif

register_syscore_ops(&kvm_syscore_ops);

/*
Expand Down
21 changes: 0 additions & 21 deletions arch/x86/kernel/kvmclock.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
#include <asm/hypervisor.h>
#include <asm/mem_encrypt.h>
#include <asm/x86_init.h>
#include <asm/reboot.h>
#include <asm/kvmclock.h>

static int kvmclock __initdata = 1;
Expand Down Expand Up @@ -203,23 +202,6 @@ static void kvm_setup_secondary_clock(void)
}
#endif

/*
* After the clock is registered, the host will keep writing to the
* registered memory location. If the guest happens to shutdown, this memory
* won't be valid. In cases like kexec, in which you install a new kernel, this
* means a random memory location will be kept being written. So before any
* kind of shutdown from our side, we unregister the clock by writing anything
* that does not have the 'enable' bit set in the msr
*/
#ifdef CONFIG_KEXEC_CORE
static void kvm_crash_shutdown(struct pt_regs *regs)
{
native_write_msr(msr_kvm_system_time, 0, 0);
kvm_disable_steal_time();
native_machine_crash_shutdown(regs);
}
#endif

void kvmclock_disable(void)
{
native_write_msr(msr_kvm_system_time, 0, 0);
Expand Down Expand Up @@ -349,9 +331,6 @@ void __init kvmclock_init(void)
#endif
x86_platform.save_sched_clock_state = kvm_save_sched_clock_state;
x86_platform.restore_sched_clock_state = kvm_restore_sched_clock_state;
#ifdef CONFIG_KEXEC_CORE
machine_ops.crash_shutdown = kvm_crash_shutdown;
#endif
kvm_get_preset_lpj();

/*
Expand Down

0 comments on commit 3d6b841

Please sign in to comment.