* [PATCH 01/16] x86/reboot: VMCLEAR active VMCSes before emergency reboot
2022-12-01 23:26 [PATCH 00/16] x86/reboot: KVM: Clean up "emergency" virt code Sean Christopherson
@ 2022-12-01 23:26 ` Sean Christopherson
2022-12-01 23:26 ` [PATCH 02/16] x86/reboot: Expose VMCS crash hooks if and only if KVM_INTEL is enabled Sean Christopherson
` (14 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Sean Christopherson @ 2022-12-01 23:26 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
Sean Christopherson, Paolo Bonzini
Cc: H. Peter Anvin, linux-kernel, kvm, Andrew Cooper
VMCLEAR active VMCSes before any emergency reboot, not just if the kernel
may kexec into a new kernel after a crash. Per Intel's SDM, the VMX
architecture doesn't require the CPU to flush the VMCS cache on INIT. If
an emergency reboot doesn't RESET CPUs, cached VMCSes could theoretically
be kept and only be written back to memory after the new kernel is booted,
i.e. could effectively corrupt memory after reboot.
Opportunistically remove the setting of the global pointer to NULL to make
checkpatch happy.
Cc: Andrew Cooper <Andrew.Cooper3@citrix.com>
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
arch/x86/include/asm/kexec.h | 2 --
arch/x86/include/asm/reboot.h | 2 ++
arch/x86/kernel/crash.c | 31 -------------------------------
arch/x86/kernel/reboot.c | 22 ++++++++++++++++++++++
arch/x86/kvm/vmx/vmx.c | 10 +++-------
5 files changed, 27 insertions(+), 40 deletions(-)
diff --git a/arch/x86/include/asm/kexec.h b/arch/x86/include/asm/kexec.h
index a3760ca796aa..256eee99afc8 100644
--- a/arch/x86/include/asm/kexec.h
+++ b/arch/x86/include/asm/kexec.h
@@ -208,8 +208,6 @@ int arch_kimage_file_post_load_cleanup(struct kimage *image);
#endif
#endif
-typedef void crash_vmclear_fn(void);
-extern crash_vmclear_fn __rcu *crash_vmclear_loaded_vmcss;
extern void kdump_nmi_shootdown_cpus(void);
#endif /* __ASSEMBLY__ */
diff --git a/arch/x86/include/asm/reboot.h b/arch/x86/include/asm/reboot.h
index bc5b4d788c08..2551baec927d 100644
--- a/arch/x86/include/asm/reboot.h
+++ b/arch/x86/include/asm/reboot.h
@@ -25,6 +25,8 @@ void __noreturn machine_real_restart(unsigned int type);
#define MRR_BIOS 0
#define MRR_APM 1
+typedef void crash_vmclear_fn(void);
+extern crash_vmclear_fn __rcu *crash_vmclear_loaded_vmcss;
void cpu_emergency_disable_virtualization(void);
typedef void (*nmi_shootdown_cb)(int, struct pt_regs*);
diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c
index 6b8a6aae02e3..7611dd5f90a4 100644
--- a/arch/x86/kernel/crash.c
+++ b/arch/x86/kernel/crash.c
@@ -48,38 +48,12 @@ struct crash_memmap_data {
unsigned int type;
};
-/*
- * This is used to VMCLEAR all VMCSs loaded on the
- * processor. And when loading kvm_intel module, the
- * callback function pointer will be assigned.
- *
- * protected by rcu.
- */
-crash_vmclear_fn __rcu *crash_vmclear_loaded_vmcss = NULL;
-EXPORT_SYMBOL_GPL(crash_vmclear_loaded_vmcss);
-
-static inline void cpu_crash_vmclear_loaded_vmcss(void)
-{
- crash_vmclear_fn *do_vmclear_operation = NULL;
-
- rcu_read_lock();
- do_vmclear_operation = rcu_dereference(crash_vmclear_loaded_vmcss);
- if (do_vmclear_operation)
- do_vmclear_operation();
- rcu_read_unlock();
-}
-
#if defined(CONFIG_SMP) && defined(CONFIG_X86_LOCAL_APIC)
static void kdump_nmi_callback(int cpu, struct pt_regs *regs)
{
crash_save_cpu(regs, cpu);
- /*
- * VMCLEAR VMCSs loaded on all cpus if needed.
- */
- cpu_crash_vmclear_loaded_vmcss();
-
/*
* Disable Intel PT to stop its logging
*/
@@ -133,11 +107,6 @@ void native_machine_crash_shutdown(struct pt_regs *regs)
crash_smp_send_stop();
- /*
- * VMCLEAR VMCSs loaded on this cpu if needed.
- */
- cpu_crash_vmclear_loaded_vmcss();
-
cpu_emergency_disable_virtualization();
/*
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
index d03c551defcc..299b970e5f82 100644
--- a/arch/x86/kernel/reboot.c
+++ b/arch/x86/kernel/reboot.c
@@ -787,6 +787,26 @@ void machine_crash_shutdown(struct pt_regs *regs)
}
#endif
+/*
+ * This is used to VMCLEAR all VMCSs loaded on the
+ * processor. And when loading kvm_intel module, the
+ * callback function pointer will be assigned.
+ *
+ * protected by rcu.
+ */
+crash_vmclear_fn __rcu *crash_vmclear_loaded_vmcss;
+EXPORT_SYMBOL_GPL(crash_vmclear_loaded_vmcss);
+
+static inline void cpu_crash_vmclear_loaded_vmcss(void)
+{
+ crash_vmclear_fn *do_vmclear_operation = NULL;
+
+ rcu_read_lock();
+ do_vmclear_operation = rcu_dereference(crash_vmclear_loaded_vmcss);
+ if (do_vmclear_operation)
+ do_vmclear_operation();
+ rcu_read_unlock();
+}
/* This is the CPU performing the emergency shutdown work. */
int crashing_cpu = -1;
@@ -798,6 +818,8 @@ int crashing_cpu = -1;
*/
void cpu_emergency_disable_virtualization(void)
{
+ cpu_crash_vmclear_loaded_vmcss();
+
cpu_emergency_vmxoff();
cpu_emergency_svm_disable();
}
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index 39dd3082fcd8..7ea020456dd0 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -41,7 +41,7 @@
#include <asm/idtentry.h>
#include <asm/io.h>
#include <asm/irq_remapping.h>
-#include <asm/kexec.h>
+#include <asm/reboot.h>
#include <asm/perf_event.h>
#include <asm/mmu_context.h>
#include <asm/mshyperv.h>
@@ -743,7 +743,6 @@ static int vmx_set_guest_uret_msr(struct vcpu_vmx *vmx,
return ret;
}
-#ifdef CONFIG_KEXEC_CORE
static void crash_vmclear_local_loaded_vmcss(void)
{
int cpu = raw_smp_processor_id();
@@ -753,7 +752,6 @@ static void crash_vmclear_local_loaded_vmcss(void)
loaded_vmcss_on_cpu_link)
vmcs_clear(v->vmcs);
}
-#endif /* CONFIG_KEXEC_CORE */
static void __loaded_vmcs_clear(void *arg)
{
@@ -8528,10 +8526,9 @@ static void __vmx_exit(void)
{
allow_smaller_maxphyaddr = false;
-#ifdef CONFIG_KEXEC_CORE
RCU_INIT_POINTER(crash_vmclear_loaded_vmcss, NULL);
synchronize_rcu();
-#endif
+
vmx_cleanup_l1d_flush();
}
@@ -8580,10 +8577,9 @@ static int __init vmx_init(void)
pi_init_cpu(cpu);
}
-#ifdef CONFIG_KEXEC_CORE
rcu_assign_pointer(crash_vmclear_loaded_vmcss,
crash_vmclear_local_loaded_vmcss);
-#endif
+
vmx_check_vmcs12_offsets();
/*
--
2.39.0.rc0.267.gcb52ba06e7-goog
^ permalink raw reply [flat|nested] 17+ messages in thread* [PATCH 02/16] x86/reboot: Expose VMCS crash hooks if and only if KVM_INTEL is enabled
2022-12-01 23:26 [PATCH 00/16] x86/reboot: KVM: Clean up "emergency" virt code Sean Christopherson
2022-12-01 23:26 ` [PATCH 01/16] x86/reboot: VMCLEAR active VMCSes before emergency reboot Sean Christopherson
@ 2022-12-01 23:26 ` Sean Christopherson
2022-12-01 23:26 ` [PATCH 03/16] x86/reboot: Harden virtualization hooks for emergency reboot Sean Christopherson
` (13 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Sean Christopherson @ 2022-12-01 23:26 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
Sean Christopherson, Paolo Bonzini
Cc: H. Peter Anvin, linux-kernel, kvm, Andrew Cooper
Expose the crash/reboot hooks used by KVM to do VMCLEAR+VMXOFF if and
only if there's a potential in-tree user, KVM_INTEL.
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
arch/x86/include/asm/reboot.h | 2 ++
arch/x86/kernel/reboot.c | 4 ++++
2 files changed, 6 insertions(+)
diff --git a/arch/x86/include/asm/reboot.h b/arch/x86/include/asm/reboot.h
index 2551baec927d..33c8e911e0de 100644
--- a/arch/x86/include/asm/reboot.h
+++ b/arch/x86/include/asm/reboot.h
@@ -25,8 +25,10 @@ void __noreturn machine_real_restart(unsigned int type);
#define MRR_BIOS 0
#define MRR_APM 1
+#if IS_ENABLED(CONFIG_KVM_INTEL)
typedef void crash_vmclear_fn(void);
extern crash_vmclear_fn __rcu *crash_vmclear_loaded_vmcss;
+#endif
void cpu_emergency_disable_virtualization(void);
typedef void (*nmi_shootdown_cb)(int, struct pt_regs*);
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
index 299b970e5f82..6c0b1634b884 100644
--- a/arch/x86/kernel/reboot.c
+++ b/arch/x86/kernel/reboot.c
@@ -787,6 +787,7 @@ void machine_crash_shutdown(struct pt_regs *regs)
}
#endif
+#if IS_ENABLED(CONFIG_KVM_INTEL)
/*
* This is used to VMCLEAR all VMCSs loaded on the
* processor. And when loading kvm_intel module, the
@@ -807,6 +808,7 @@ static inline void cpu_crash_vmclear_loaded_vmcss(void)
do_vmclear_operation();
rcu_read_unlock();
}
+#endif
/* This is the CPU performing the emergency shutdown work. */
int crashing_cpu = -1;
@@ -818,7 +820,9 @@ int crashing_cpu = -1;
*/
void cpu_emergency_disable_virtualization(void)
{
+#if IS_ENABLED(CONFIG_KVM_INTEL)
cpu_crash_vmclear_loaded_vmcss();
+#endif
cpu_emergency_vmxoff();
cpu_emergency_svm_disable();
--
2.39.0.rc0.267.gcb52ba06e7-goog
^ permalink raw reply [flat|nested] 17+ messages in thread* [PATCH 03/16] x86/reboot: Harden virtualization hooks for emergency reboot
2022-12-01 23:26 [PATCH 00/16] x86/reboot: KVM: Clean up "emergency" virt code Sean Christopherson
2022-12-01 23:26 ` [PATCH 01/16] x86/reboot: VMCLEAR active VMCSes before emergency reboot Sean Christopherson
2022-12-01 23:26 ` [PATCH 02/16] x86/reboot: Expose VMCS crash hooks if and only if KVM_INTEL is enabled Sean Christopherson
@ 2022-12-01 23:26 ` Sean Christopherson
2022-12-01 23:26 ` [PATCH 04/16] x86/reboot: Assert that IRQs are disabled when turning off virtualization Sean Christopherson
` (12 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Sean Christopherson @ 2022-12-01 23:26 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
Sean Christopherson, Paolo Bonzini
Cc: H. Peter Anvin, linux-kernel, kvm, Andrew Cooper
Provide dedicated helpers to (un)register virt hooks used during an
emergency crash/reboot, and WARN if there is an attempt to overwrite
the registered callback, or an attempt to do an unpaired unregister.
Opportunsitically use rcu_assign_pointer() instead of RCU_INIT_POINTER(),
mainly so that the set/unset paths are more symmetrical, but also because
any performance gains from using RCU_INIT_POINTER() are meaningless for
this code.
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
arch/x86/include/asm/reboot.h | 5 +++--
arch/x86/kernel/reboot.c | 30 ++++++++++++++++++++++++------
arch/x86/kvm/vmx/vmx.c | 6 ++----
3 files changed, 29 insertions(+), 12 deletions(-)
diff --git a/arch/x86/include/asm/reboot.h b/arch/x86/include/asm/reboot.h
index 33c8e911e0de..1d098a7d329a 100644
--- a/arch/x86/include/asm/reboot.h
+++ b/arch/x86/include/asm/reboot.h
@@ -26,8 +26,9 @@ void __noreturn machine_real_restart(unsigned int type);
#define MRR_APM 1
#if IS_ENABLED(CONFIG_KVM_INTEL)
-typedef void crash_vmclear_fn(void);
-extern crash_vmclear_fn __rcu *crash_vmclear_loaded_vmcss;
+typedef void (cpu_emergency_virt_cb)(void);
+void cpu_emergency_register_virt_callback(cpu_emergency_virt_cb *callback);
+void cpu_emergency_unregister_virt_callback(cpu_emergency_virt_cb *callback);
#endif
void cpu_emergency_disable_virtualization(void);
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
index 6c0b1634b884..78182b2969db 100644
--- a/arch/x86/kernel/reboot.c
+++ b/arch/x86/kernel/reboot.c
@@ -795,17 +795,35 @@ void machine_crash_shutdown(struct pt_regs *regs)
*
* protected by rcu.
*/
-crash_vmclear_fn __rcu *crash_vmclear_loaded_vmcss;
-EXPORT_SYMBOL_GPL(crash_vmclear_loaded_vmcss);
+static cpu_emergency_virt_cb __rcu *cpu_emergency_virt_callback;
+
+void cpu_emergency_register_virt_callback(cpu_emergency_virt_cb *callback)
+{
+ if (WARN_ON_ONCE(rcu_access_pointer(cpu_emergency_virt_callback)))
+ return;
+
+ rcu_assign_pointer(cpu_emergency_virt_callback, callback);
+}
+EXPORT_SYMBOL_GPL(cpu_emergency_register_virt_callback);
+
+void cpu_emergency_unregister_virt_callback(cpu_emergency_virt_cb *callback)
+{
+ if (WARN_ON_ONCE(rcu_access_pointer(cpu_emergency_virt_callback) != callback))
+ return;
+
+ rcu_assign_pointer(cpu_emergency_virt_callback, NULL);
+ synchronize_rcu();
+}
+EXPORT_SYMBOL_GPL(cpu_emergency_unregister_virt_callback);
static inline void cpu_crash_vmclear_loaded_vmcss(void)
{
- crash_vmclear_fn *do_vmclear_operation = NULL;
+ cpu_emergency_virt_cb *callback;
rcu_read_lock();
- do_vmclear_operation = rcu_dereference(crash_vmclear_loaded_vmcss);
- if (do_vmclear_operation)
- do_vmclear_operation();
+ callback = rcu_dereference(cpu_emergency_virt_callback);
+ if (callback)
+ callback();
rcu_read_unlock();
}
#endif
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index 7ea020456dd0..6e0cc4d03884 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -8526,8 +8526,7 @@ static void __vmx_exit(void)
{
allow_smaller_maxphyaddr = false;
- RCU_INIT_POINTER(crash_vmclear_loaded_vmcss, NULL);
- synchronize_rcu();
+ cpu_emergency_unregister_virt_callback(crash_vmclear_local_loaded_vmcss);
vmx_cleanup_l1d_flush();
}
@@ -8577,8 +8576,7 @@ static int __init vmx_init(void)
pi_init_cpu(cpu);
}
- rcu_assign_pointer(crash_vmclear_loaded_vmcss,
- crash_vmclear_local_loaded_vmcss);
+ cpu_emergency_register_virt_callback(crash_vmclear_local_loaded_vmcss);
vmx_check_vmcs12_offsets();
--
2.39.0.rc0.267.gcb52ba06e7-goog
^ permalink raw reply [flat|nested] 17+ messages in thread* [PATCH 04/16] x86/reboot: Assert that IRQs are disabled when turning off virtualization
2022-12-01 23:26 [PATCH 00/16] x86/reboot: KVM: Clean up "emergency" virt code Sean Christopherson
` (2 preceding siblings ...)
2022-12-01 23:26 ` [PATCH 03/16] x86/reboot: Harden virtualization hooks for emergency reboot Sean Christopherson
@ 2022-12-01 23:26 ` Sean Christopherson
2022-12-01 23:26 ` [PATCH 05/16] x86/reboot: KVM: Handle VMXOFF in KVM's reboot callback Sean Christopherson
` (11 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Sean Christopherson @ 2022-12-01 23:26 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
Sean Christopherson, Paolo Bonzini
Cc: H. Peter Anvin, linux-kernel, kvm, Andrew Cooper
Assert that IRQs are disabled when turning off virtualization in an
emergency. KVM enables hardware via on_each_cpu(), i.e. could re-enable
hardware if a pending IPI were delivered after disabling virtualization.
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
arch/x86/kernel/reboot.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
index 78182b2969db..40ea16ecb3b8 100644
--- a/arch/x86/kernel/reboot.c
+++ b/arch/x86/kernel/reboot.c
@@ -838,6 +838,8 @@ int crashing_cpu = -1;
*/
void cpu_emergency_disable_virtualization(void)
{
+ lockdep_assert_irqs_disabled();
+
#if IS_ENABLED(CONFIG_KVM_INTEL)
cpu_crash_vmclear_loaded_vmcss();
#endif
--
2.39.0.rc0.267.gcb52ba06e7-goog
^ permalink raw reply [flat|nested] 17+ messages in thread* [PATCH 05/16] x86/reboot: KVM: Handle VMXOFF in KVM's reboot callback
2022-12-01 23:26 [PATCH 00/16] x86/reboot: KVM: Clean up "emergency" virt code Sean Christopherson
` (3 preceding siblings ...)
2022-12-01 23:26 ` [PATCH 04/16] x86/reboot: Assert that IRQs are disabled when turning off virtualization Sean Christopherson
@ 2022-12-01 23:26 ` Sean Christopherson
2022-12-01 23:26 ` [PATCH 06/16] x86/reboot: KVM: Disable SVM during reboot via virt/KVM " Sean Christopherson
` (10 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Sean Christopherson @ 2022-12-01 23:26 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
Sean Christopherson, Paolo Bonzini
Cc: H. Peter Anvin, linux-kernel, kvm, Andrew Cooper
Use KVM VMX's reboot/crash callback to do VMXOFF in an emergency instead
of manually and blindly doing VMXOFF. There's no need to attempt VMXOFF
if KVM (or some other out-of-tree hypervisor) isn't loaded/active, i.e.
if the CPU can't possibly be post-VMXON.
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
arch/x86/include/asm/virtext.h | 10 ----------
arch/x86/kernel/reboot.c | 30 +++++++++---------------------
arch/x86/kvm/vmx/vmx.c | 8 +++++---
3 files changed, 14 insertions(+), 34 deletions(-)
diff --git a/arch/x86/include/asm/virtext.h b/arch/x86/include/asm/virtext.h
index 0acb14806a74..4f61283b1f52 100644
--- a/arch/x86/include/asm/virtext.h
+++ b/arch/x86/include/asm/virtext.h
@@ -70,16 +70,6 @@ static inline void __cpu_emergency_vmxoff(void)
cpu_vmxoff();
}
-/** Disable VMX if it is supported and enabled on the current CPU
- */
-static inline void cpu_emergency_vmxoff(void)
-{
- if (cpu_has_vmx())
- __cpu_emergency_vmxoff();
-}
-
-
-
/*
* SVM functions:
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
index 40ea16ecb3b8..85ea1fdebf4c 100644
--- a/arch/x86/kernel/reboot.c
+++ b/arch/x86/kernel/reboot.c
@@ -788,13 +788,7 @@ void machine_crash_shutdown(struct pt_regs *regs)
#endif
#if IS_ENABLED(CONFIG_KVM_INTEL)
-/*
- * This is used to VMCLEAR all VMCSs loaded on the
- * processor. And when loading kvm_intel module, the
- * callback function pointer will be assigned.
- *
- * protected by rcu.
- */
+/* RCU-protected callback to disable virtualization prior to reboot. */
static cpu_emergency_virt_cb __rcu *cpu_emergency_virt_callback;
void cpu_emergency_register_virt_callback(cpu_emergency_virt_cb *callback)
@@ -815,17 +809,6 @@ void cpu_emergency_unregister_virt_callback(cpu_emergency_virt_cb *callback)
synchronize_rcu();
}
EXPORT_SYMBOL_GPL(cpu_emergency_unregister_virt_callback);
-
-static inline void cpu_crash_vmclear_loaded_vmcss(void)
-{
- cpu_emergency_virt_cb *callback;
-
- rcu_read_lock();
- callback = rcu_dereference(cpu_emergency_virt_callback);
- if (callback)
- callback();
- rcu_read_unlock();
-}
#endif
/* This is the CPU performing the emergency shutdown work. */
@@ -841,10 +824,15 @@ void cpu_emergency_disable_virtualization(void)
lockdep_assert_irqs_disabled();
#if IS_ENABLED(CONFIG_KVM_INTEL)
- cpu_crash_vmclear_loaded_vmcss();
-#endif
+ cpu_emergency_virt_cb *callback;
- cpu_emergency_vmxoff();
+ rcu_read_lock();
+ callback = rcu_dereference(cpu_emergency_virt_callback);
+ if (callback)
+ callback();
+ rcu_read_unlock();
+#endif
+ /* KVM_AMD doesn't yet utilize the common callback. */
cpu_emergency_svm_disable();
}
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index 6e0cc4d03884..6f3ade75a670 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -743,7 +743,7 @@ static int vmx_set_guest_uret_msr(struct vcpu_vmx *vmx,
return ret;
}
-static void crash_vmclear_local_loaded_vmcss(void)
+static void vmx_emergency_disable(void)
{
int cpu = raw_smp_processor_id();
struct loaded_vmcs *v;
@@ -751,6 +751,8 @@ static void crash_vmclear_local_loaded_vmcss(void)
list_for_each_entry(v, &per_cpu(loaded_vmcss_on_cpu, cpu),
loaded_vmcss_on_cpu_link)
vmcs_clear(v->vmcs);
+
+ __cpu_emergency_vmxoff();
}
static void __loaded_vmcs_clear(void *arg)
@@ -8526,7 +8528,7 @@ static void __vmx_exit(void)
{
allow_smaller_maxphyaddr = false;
- cpu_emergency_unregister_virt_callback(crash_vmclear_local_loaded_vmcss);
+ cpu_emergency_unregister_virt_callback(vmx_emergency_disable);
vmx_cleanup_l1d_flush();
}
@@ -8576,7 +8578,7 @@ static int __init vmx_init(void)
pi_init_cpu(cpu);
}
- cpu_emergency_register_virt_callback(crash_vmclear_local_loaded_vmcss);
+ cpu_emergency_register_virt_callback(vmx_emergency_disable);
vmx_check_vmcs12_offsets();
--
2.39.0.rc0.267.gcb52ba06e7-goog
^ permalink raw reply [flat|nested] 17+ messages in thread* [PATCH 06/16] x86/reboot: KVM: Disable SVM during reboot via virt/KVM reboot callback
2022-12-01 23:26 [PATCH 00/16] x86/reboot: KVM: Clean up "emergency" virt code Sean Christopherson
` (4 preceding siblings ...)
2022-12-01 23:26 ` [PATCH 05/16] x86/reboot: KVM: Handle VMXOFF in KVM's reboot callback Sean Christopherson
@ 2022-12-01 23:26 ` Sean Christopherson
2022-12-01 23:26 ` [PATCH 07/16] x86/reboot: Hoist "disable virt" helpers above "emergency reboot" path Sean Christopherson
` (9 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Sean Christopherson @ 2022-12-01 23:26 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
Sean Christopherson, Paolo Bonzini
Cc: H. Peter Anvin, linux-kernel, kvm, Andrew Cooper
Use the virt callback to disable SVM (and set GIF=1) during an emergency
instead of blindly attempting to disable SVM. Like the VMX case, if KVM
(or an out-of-tree hypervisor) isn't loaded/active, SVM can't be in use.
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
arch/x86/include/asm/reboot.h | 2 +-
arch/x86/include/asm/virtext.h | 8 --------
arch/x86/kernel/reboot.c | 6 ++----
arch/x86/kvm/svm/svm.c | 19 +++++++++++++++++--
4 files changed, 20 insertions(+), 15 deletions(-)
diff --git a/arch/x86/include/asm/reboot.h b/arch/x86/include/asm/reboot.h
index 1d098a7d329a..dc2b77e6704b 100644
--- a/arch/x86/include/asm/reboot.h
+++ b/arch/x86/include/asm/reboot.h
@@ -25,7 +25,7 @@ void __noreturn machine_real_restart(unsigned int type);
#define MRR_BIOS 0
#define MRR_APM 1
-#if IS_ENABLED(CONFIG_KVM_INTEL)
+#if IS_ENABLED(CONFIG_KVM_INTEL) || IS_ENABLED(CONFIG_KVM_AMD)
typedef void (cpu_emergency_virt_cb)(void);
void cpu_emergency_register_virt_callback(cpu_emergency_virt_cb *callback);
void cpu_emergency_unregister_virt_callback(cpu_emergency_virt_cb *callback);
diff --git a/arch/x86/include/asm/virtext.h b/arch/x86/include/asm/virtext.h
index 4f61283b1f52..97349410c937 100644
--- a/arch/x86/include/asm/virtext.h
+++ b/arch/x86/include/asm/virtext.h
@@ -130,12 +130,4 @@ static inline void cpu_svm_disable(void)
}
}
-/** Makes sure SVM is disabled, if it is supported on the CPU
- */
-static inline void cpu_emergency_svm_disable(void)
-{
- if (cpu_has_svm(NULL))
- cpu_svm_disable();
-}
-
#endif /* _ASM_X86_VIRTEX_H */
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
index 85ea1fdebf4c..3eec3cdbc054 100644
--- a/arch/x86/kernel/reboot.c
+++ b/arch/x86/kernel/reboot.c
@@ -787,7 +787,7 @@ void machine_crash_shutdown(struct pt_regs *regs)
}
#endif
-#if IS_ENABLED(CONFIG_KVM_INTEL)
+#if IS_ENABLED(CONFIG_KVM_INTEL) || IS_ENABLED(CONFIG_KVM_AMD)
/* RCU-protected callback to disable virtualization prior to reboot. */
static cpu_emergency_virt_cb __rcu *cpu_emergency_virt_callback;
@@ -823,7 +823,7 @@ void cpu_emergency_disable_virtualization(void)
{
lockdep_assert_irqs_disabled();
-#if IS_ENABLED(CONFIG_KVM_INTEL)
+#if IS_ENABLED(CONFIG_KVM_INTEL) || IS_ENABLED(CONFIG_KVM_AMD)
cpu_emergency_virt_cb *callback;
rcu_read_lock();
@@ -832,8 +832,6 @@ void cpu_emergency_disable_virtualization(void)
callback();
rcu_read_unlock();
#endif
- /* KVM_AMD doesn't yet utilize the common callback. */
- cpu_emergency_svm_disable();
}
#if defined(CONFIG_SMP)
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index 46b658d0f46e..d56d5fe42262 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -38,6 +38,7 @@
#include <asm/spec-ctrl.h>
#include <asm/cpu_device_id.h>
#include <asm/traps.h>
+#include <asm/reboot.h>
#include <asm/fpu/api.h>
#include <asm/virtext.h>
@@ -565,6 +566,11 @@ void __svm_write_tsc_multiplier(u64 multiplier)
preempt_enable();
}
+static void svm_emergency_disable(void)
+{
+ cpu_svm_disable();
+}
+
static void svm_hardware_disable(void)
{
/* Make sure we clean up behind us */
@@ -5084,6 +5090,13 @@ static struct kvm_x86_init_ops svm_init_ops __initdata = {
.pmu_ops = &amd_pmu_ops,
};
+static void __svm_exit(void)
+{
+ kvm_x86_vendor_exit();
+
+ cpu_emergency_unregister_virt_callback(svm_emergency_disable);
+}
+
static int __init svm_init(void)
{
int r;
@@ -5097,6 +5110,8 @@ static int __init svm_init(void)
if (r)
return r;
+ cpu_emergency_register_virt_callback(svm_emergency_disable);
+
/*
* Common KVM initialization _must_ come last, after this, /dev/kvm is
* exposed to userspace!
@@ -5109,14 +5124,14 @@ static int __init svm_init(void)
return 0;
err_kvm_init:
- kvm_x86_vendor_exit();
+ __svm_exit();
return r;
}
static void __exit svm_exit(void)
{
kvm_exit();
- kvm_x86_vendor_exit();
+ __svm_exit();
}
module_init(svm_init)
--
2.39.0.rc0.267.gcb52ba06e7-goog
^ permalink raw reply [flat|nested] 17+ messages in thread* [PATCH 07/16] x86/reboot: Hoist "disable virt" helpers above "emergency reboot" path
2022-12-01 23:26 [PATCH 00/16] x86/reboot: KVM: Clean up "emergency" virt code Sean Christopherson
` (5 preceding siblings ...)
2022-12-01 23:26 ` [PATCH 06/16] x86/reboot: KVM: Disable SVM during reboot via virt/KVM " Sean Christopherson
@ 2022-12-01 23:26 ` Sean Christopherson
2022-12-01 23:26 ` [PATCH 08/16] x86/reboot: Disable virtualization during reboot iff callback is registered Sean Christopherson
` (8 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Sean Christopherson @ 2022-12-01 23:26 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
Sean Christopherson, Paolo Bonzini
Cc: H. Peter Anvin, linux-kernel, kvm, Andrew Cooper
Move the various "disable virtualization" helpers above the emergency
reboot path so that emergency_reboot_disable_virtualization() can be
stubbed out in a future patch if neither KVM_INTEL nor KVM_AMD is enabled,
i.e. if there is no in-tree user of CPU virtualization.
No functional change intended.
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
arch/x86/include/asm/reboot.h | 4 +-
arch/x86/kernel/reboot.c | 86 +++++++++++++++++------------------
2 files changed, 45 insertions(+), 45 deletions(-)
diff --git a/arch/x86/include/asm/reboot.h b/arch/x86/include/asm/reboot.h
index dc2b77e6704b..2be5b89c9a05 100644
--- a/arch/x86/include/asm/reboot.h
+++ b/arch/x86/include/asm/reboot.h
@@ -29,8 +29,10 @@ void __noreturn machine_real_restart(unsigned int type);
typedef void (cpu_emergency_virt_cb)(void);
void cpu_emergency_register_virt_callback(cpu_emergency_virt_cb *callback);
void cpu_emergency_unregister_virt_callback(cpu_emergency_virt_cb *callback);
-#endif
void cpu_emergency_disable_virtualization(void);
+#else
+static inline void cpu_emergency_disable_virtualization(void) {}
+#endif
typedef void (*nmi_shootdown_cb)(int, struct pt_regs*);
void nmi_panic_self_stop(struct pt_regs *regs);
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
index 3eec3cdbc054..a006ddaa1405 100644
--- a/arch/x86/kernel/reboot.c
+++ b/arch/x86/kernel/reboot.c
@@ -530,6 +530,48 @@ static inline void kb_wait(void)
static inline void nmi_shootdown_cpus_on_restart(void);
+#if IS_ENABLED(CONFIG_KVM_INTEL) || IS_ENABLED(CONFIG_KVM_AMD)
+/* RCU-protected callback to disable virtualization prior to reboot. */
+static cpu_emergency_virt_cb __rcu *cpu_emergency_virt_callback;
+
+void cpu_emergency_register_virt_callback(cpu_emergency_virt_cb *callback)
+{
+ if (WARN_ON_ONCE(rcu_access_pointer(cpu_emergency_virt_callback)))
+ return;
+
+ rcu_assign_pointer(cpu_emergency_virt_callback, callback);
+}
+EXPORT_SYMBOL_GPL(cpu_emergency_register_virt_callback);
+
+void cpu_emergency_unregister_virt_callback(cpu_emergency_virt_cb *callback)
+{
+ if (WARN_ON_ONCE(rcu_access_pointer(cpu_emergency_virt_callback) != callback))
+ return;
+
+ rcu_assign_pointer(cpu_emergency_virt_callback, NULL);
+ synchronize_rcu();
+}
+EXPORT_SYMBOL_GPL(cpu_emergency_unregister_virt_callback);
+
+/*
+ * Disable virtualization, i.e. VMX or SVM, to ensure INIT is recognized during
+ * reboot. VMX blocks INIT if the CPU is post-VMXON, and SVM blocks INIT if
+ * GIF=0, i.e. if the crash occurred between CLGI and STGI.
+ */
+void cpu_emergency_disable_virtualization(void)
+{
+ cpu_emergency_virt_cb *callback;
+
+ lockdep_assert_irqs_disabled();
+
+ rcu_read_lock();
+ callback = rcu_dereference(cpu_emergency_virt_callback);
+ if (callback)
+ callback();
+ rcu_read_unlock();
+}
+#endif /* CONFIG_KVM_INTEL || CONFIG_KVM_AMD */
+
static void emergency_reboot_disable_virtualization(void)
{
/* Just make sure we won't change CPUs while doing this */
@@ -787,53 +829,9 @@ void machine_crash_shutdown(struct pt_regs *regs)
}
#endif
-#if IS_ENABLED(CONFIG_KVM_INTEL) || IS_ENABLED(CONFIG_KVM_AMD)
-/* RCU-protected callback to disable virtualization prior to reboot. */
-static cpu_emergency_virt_cb __rcu *cpu_emergency_virt_callback;
-
-void cpu_emergency_register_virt_callback(cpu_emergency_virt_cb *callback)
-{
- if (WARN_ON_ONCE(rcu_access_pointer(cpu_emergency_virt_callback)))
- return;
-
- rcu_assign_pointer(cpu_emergency_virt_callback, callback);
-}
-EXPORT_SYMBOL_GPL(cpu_emergency_register_virt_callback);
-
-void cpu_emergency_unregister_virt_callback(cpu_emergency_virt_cb *callback)
-{
- if (WARN_ON_ONCE(rcu_access_pointer(cpu_emergency_virt_callback) != callback))
- return;
-
- rcu_assign_pointer(cpu_emergency_virt_callback, NULL);
- synchronize_rcu();
-}
-EXPORT_SYMBOL_GPL(cpu_emergency_unregister_virt_callback);
-#endif
-
/* This is the CPU performing the emergency shutdown work. */
int crashing_cpu = -1;
-/*
- * Disable virtualization, i.e. VMX or SVM, to ensure INIT is recognized during
- * reboot. VMX blocks INIT if the CPU is post-VMXON, and SVM blocks INIT if
- * GIF=0, i.e. if the crash occurred between CLGI and STGI.
- */
-void cpu_emergency_disable_virtualization(void)
-{
- lockdep_assert_irqs_disabled();
-
-#if IS_ENABLED(CONFIG_KVM_INTEL) || IS_ENABLED(CONFIG_KVM_AMD)
- cpu_emergency_virt_cb *callback;
-
- rcu_read_lock();
- callback = rcu_dereference(cpu_emergency_virt_callback);
- if (callback)
- callback();
- rcu_read_unlock();
-#endif
-}
-
#if defined(CONFIG_SMP)
static nmi_shootdown_cb shootdown_callback;
--
2.39.0.rc0.267.gcb52ba06e7-goog
^ permalink raw reply [flat|nested] 17+ messages in thread* [PATCH 08/16] x86/reboot: Disable virtualization during reboot iff callback is registered
2022-12-01 23:26 [PATCH 00/16] x86/reboot: KVM: Clean up "emergency" virt code Sean Christopherson
` (6 preceding siblings ...)
2022-12-01 23:26 ` [PATCH 07/16] x86/reboot: Hoist "disable virt" helpers above "emergency reboot" path Sean Christopherson
@ 2022-12-01 23:26 ` Sean Christopherson
2022-12-01 23:26 ` [PATCH 09/16] x86/virt: KVM: Open code cpu_has_vmx() in KVM VMX Sean Christopherson
` (7 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Sean Christopherson @ 2022-12-01 23:26 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
Sean Christopherson, Paolo Bonzini
Cc: H. Peter Anvin, linux-kernel, kvm, Andrew Cooper
Attempt to disable virtualization during an emergency reboot if and only
if there is a registered virt callback, i.e. iff a hypervisor (KVM) is
active. If there's no active hypervisor, then the CPU can't be operating
with VMX or SVM enabled (barring an egregious bug).
Note, IRQs are disabled, which prevents KVM from coming along and enabling
virtualization after the fact.
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
arch/x86/kernel/reboot.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
index a006ddaa1405..e0dd1b00ba01 100644
--- a/arch/x86/kernel/reboot.c
+++ b/arch/x86/kernel/reboot.c
@@ -22,7 +22,6 @@
#include <asm/reboot_fixups.h>
#include <asm/reboot.h>
#include <asm/pci_x86.h>
-#include <asm/virtext.h>
#include <asm/cpu.h>
#include <asm/nmi.h>
#include <asm/smp.h>
@@ -570,7 +569,6 @@ void cpu_emergency_disable_virtualization(void)
callback();
rcu_read_unlock();
}
-#endif /* CONFIG_KVM_INTEL || CONFIG_KVM_AMD */
static void emergency_reboot_disable_virtualization(void)
{
@@ -587,7 +585,7 @@ static void emergency_reboot_disable_virtualization(void)
* Do the NMI shootdown even if virtualization is off on _this_ CPU, as
* other CPUs may have virtualization enabled.
*/
- if (cpu_has_vmx() || cpu_has_svm(NULL)) {
+ if (rcu_access_pointer(cpu_emergency_virt_callback)) {
/* Safely force _this_ CPU out of VMX/SVM operation. */
cpu_emergency_disable_virtualization();
@@ -595,6 +593,9 @@ static void emergency_reboot_disable_virtualization(void)
nmi_shootdown_cpus_on_restart();
}
}
+#else
+static void emergency_reboot_disable_virtualization(void) { }
+#endif /* CONFIG_KVM_INTEL || CONFIG_KVM_AMD */
void __attribute__((weak)) mach_reboot_fixups(void)
--
2.39.0.rc0.267.gcb52ba06e7-goog
^ permalink raw reply [flat|nested] 17+ messages in thread* [PATCH 09/16] x86/virt: KVM: Open code cpu_has_vmx() in KVM VMX
2022-12-01 23:26 [PATCH 00/16] x86/reboot: KVM: Clean up "emergency" virt code Sean Christopherson
` (7 preceding siblings ...)
2022-12-01 23:26 ` [PATCH 08/16] x86/reboot: Disable virtualization during reboot iff callback is registered Sean Christopherson
@ 2022-12-01 23:26 ` Sean Christopherson
2022-12-01 23:26 ` [PATCH 10/16] x86/virt: KVM: Move VMXOFF helpers into " Sean Christopherson
` (6 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Sean Christopherson @ 2022-12-01 23:26 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
Sean Christopherson, Paolo Bonzini
Cc: H. Peter Anvin, linux-kernel, kvm, Andrew Cooper
Fold the raw CPUID check for VMX into kvm_is_vmx_supported(), its sole
user. Keep the check even though KVM also checks X86_FEATURE_VMX, as the
intent is to provide a unique error message if VMX is unsupported by
hardware, whereas X86_FEATURE_VMX may be clear due to firmware and/or
kernel actions.
No functional change intended.
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
arch/x86/include/asm/virtext.h | 10 ----------
arch/x86/kvm/vmx/vmx.c | 2 +-
2 files changed, 1 insertion(+), 11 deletions(-)
diff --git a/arch/x86/include/asm/virtext.h b/arch/x86/include/asm/virtext.h
index 97349410c937..c5df63c606be 100644
--- a/arch/x86/include/asm/virtext.h
+++ b/arch/x86/include/asm/virtext.h
@@ -22,14 +22,6 @@
/*
* VMX functions:
*/
-
-static inline int cpu_has_vmx(void)
-{
- unsigned long ecx = cpuid_ecx(1);
- return test_bit(5, &ecx); /* CPUID.1:ECX.VMX[bit 5] -> VT */
-}
-
-
/**
* cpu_vmxoff() - Disable VMX on the current CPU
*
@@ -61,8 +53,6 @@ static inline int cpu_vmx_enabled(void)
}
/** Disable VMX if it is enabled on the current CPU
- *
- * You shouldn't call this if cpu_has_vmx() returns 0.
*/
static inline void __cpu_emergency_vmxoff(void)
{
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index 6f3ade75a670..5bdcae435897 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -2713,7 +2713,7 @@ static bool kvm_is_vmx_supported(void)
{
int cpu = raw_smp_processor_id();
- if (!cpu_has_vmx()) {
+ if (!(cpuid_ecx(1) & feature_bit(VMX))) {
pr_err("VMX not supported by CPU %d\n", cpu);
return false;
}
--
2.39.0.rc0.267.gcb52ba06e7-goog
^ permalink raw reply [flat|nested] 17+ messages in thread* [PATCH 10/16] x86/virt: KVM: Move VMXOFF helpers into KVM VMX
2022-12-01 23:26 [PATCH 00/16] x86/reboot: KVM: Clean up "emergency" virt code Sean Christopherson
` (8 preceding siblings ...)
2022-12-01 23:26 ` [PATCH 09/16] x86/virt: KVM: Open code cpu_has_vmx() in KVM VMX Sean Christopherson
@ 2022-12-01 23:26 ` Sean Christopherson
2022-12-01 23:26 ` [PATCH 11/16] KVM: SVM: Make KVM_AMD depend on CPU_SUP_AMD or CPU_SUP_HYGON Sean Christopherson
` (5 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Sean Christopherson @ 2022-12-01 23:26 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
Sean Christopherson, Paolo Bonzini
Cc: H. Peter Anvin, linux-kernel, kvm, Andrew Cooper
Now that VMX is disabled in emergencies via the virt callbacks, move the
VMXOFF helpers into KVM, the only remaining user.
No functional change intended.
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
arch/x86/include/asm/virtext.h | 42 ----------------------------------
arch/x86/kvm/vmx/vmx.c | 29 ++++++++++++++++++++---
2 files changed, 26 insertions(+), 45 deletions(-)
diff --git a/arch/x86/include/asm/virtext.h b/arch/x86/include/asm/virtext.h
index c5df63c606be..0b373543514f 100644
--- a/arch/x86/include/asm/virtext.h
+++ b/arch/x86/include/asm/virtext.h
@@ -19,48 +19,6 @@
#include <asm/svm.h>
#include <asm/tlbflush.h>
-/*
- * VMX functions:
- */
-/**
- * cpu_vmxoff() - Disable VMX on the current CPU
- *
- * Disable VMX and clear CR4.VMXE (even if VMXOFF faults)
- *
- * Note, VMXOFF causes a #UD if the CPU is !post-VMXON, but it's impossible to
- * atomically track post-VMXON state, e.g. this may be called in NMI context.
- * Eat all faults as all other faults on VMXOFF faults are mode related, i.e.
- * faults are guaranteed to be due to the !post-VMXON check unless the CPU is
- * magically in RM, VM86, compat mode, or at CPL>0.
- */
-static inline int cpu_vmxoff(void)
-{
- asm_volatile_goto("1: vmxoff\n\t"
- _ASM_EXTABLE(1b, %l[fault])
- ::: "cc", "memory" : fault);
-
- cr4_clear_bits(X86_CR4_VMXE);
- return 0;
-
-fault:
- cr4_clear_bits(X86_CR4_VMXE);
- return -EIO;
-}
-
-static inline int cpu_vmx_enabled(void)
-{
- return __read_cr4() & X86_CR4_VMXE;
-}
-
-/** Disable VMX if it is enabled on the current CPU
- */
-static inline void __cpu_emergency_vmxoff(void)
-{
- if (cpu_vmx_enabled())
- cpu_vmxoff();
-}
-
-
/*
* SVM functions:
*/
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index 5bdcae435897..8be99651dcc9 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -47,7 +47,6 @@
#include <asm/mshyperv.h>
#include <asm/mwait.h>
#include <asm/spec-ctrl.h>
-#include <asm/virtext.h>
#include <asm/vmx.h>
#include "capabilities.h"
@@ -743,6 +742,29 @@ static int vmx_set_guest_uret_msr(struct vcpu_vmx *vmx,
return ret;
}
+/*
+ * Disable VMX and clear CR4.VMXE (even if VMXOFF faults)
+ *
+ * Note, VMXOFF causes a #UD if the CPU is !post-VMXON, but it's impossible to
+ * atomically track post-VMXON state, e.g. this may be called in NMI context.
+ * Eat all faults as all other faults on VMXOFF faults are mode related, i.e.
+ * faults are guaranteed to be due to the !post-VMXON check unless the CPU is
+ * magically in RM, VM86, compat mode, or at CPL>0.
+ */
+static int kvm_cpu_vmxoff(void)
+{
+ asm_volatile_goto("1: vmxoff\n\t"
+ _ASM_EXTABLE(1b, %l[fault])
+ ::: "cc", "memory" : fault);
+
+ cr4_clear_bits(X86_CR4_VMXE);
+ return 0;
+
+fault:
+ cr4_clear_bits(X86_CR4_VMXE);
+ return -EIO;
+}
+
static void vmx_emergency_disable(void)
{
int cpu = raw_smp_processor_id();
@@ -752,7 +774,8 @@ static void vmx_emergency_disable(void)
loaded_vmcss_on_cpu_link)
vmcs_clear(v->vmcs);
- __cpu_emergency_vmxoff();
+ if (__read_cr4() & X86_CR4_VMXE)
+ kvm_cpu_vmxoff();
}
static void __loaded_vmcs_clear(void *arg)
@@ -2814,7 +2837,7 @@ static void vmx_hardware_disable(void)
{
vmclear_local_loaded_vmcss();
- if (cpu_vmxoff())
+ if (kvm_cpu_vmxoff())
kvm_spurious_fault();
hv_reset_evmcs();
--
2.39.0.rc0.267.gcb52ba06e7-goog
^ permalink raw reply [flat|nested] 17+ messages in thread* [PATCH 11/16] KVM: SVM: Make KVM_AMD depend on CPU_SUP_AMD or CPU_SUP_HYGON
2022-12-01 23:26 [PATCH 00/16] x86/reboot: KVM: Clean up "emergency" virt code Sean Christopherson
` (9 preceding siblings ...)
2022-12-01 23:26 ` [PATCH 10/16] x86/virt: KVM: Move VMXOFF helpers into " Sean Christopherson
@ 2022-12-01 23:26 ` Sean Christopherson
2022-12-01 23:26 ` [PATCH 12/16] x86/virt: Drop unnecessary check on extended CPUID level in cpu_has_svm() Sean Christopherson
` (4 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Sean Christopherson @ 2022-12-01 23:26 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
Sean Christopherson, Paolo Bonzini
Cc: H. Peter Anvin, linux-kernel, kvm, Andrew Cooper
Make building KVM SVM support depend on support for AMD or Hygon. KVM
already effectively restricts SVM support to AMD and Hygon by virtue of
the vendor string checks in cpu_has_svm(), and KVM VMX supports depends
on one of its three known vendors (Intel, Centaur, or Zhaoxin).
Add the CPU_SUP_HYGON clause even though CPU_SUP_HYGON selects CPU_SUP_AMD
to document that KVM SVM support isn't just for AMD CPUs, and to prevent
breakage should Hygon support ever become a standalone thing.
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
arch/x86/kvm/Kconfig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig
index 8e578311ca9d..0d403e9b6a47 100644
--- a/arch/x86/kvm/Kconfig
+++ b/arch/x86/kvm/Kconfig
@@ -102,7 +102,7 @@ config X86_SGX_KVM
config KVM_AMD
tristate "KVM for AMD processors support"
- depends on KVM
+ depends on KVM && (CPU_SUP_AMD || CPU_SUP_HYGON)
help
Provides support for KVM on AMD processors equipped with the AMD-V
(SVM) extensions.
--
2.39.0.rc0.267.gcb52ba06e7-goog
^ permalink raw reply [flat|nested] 17+ messages in thread* [PATCH 12/16] x86/virt: Drop unnecessary check on extended CPUID level in cpu_has_svm()
2022-12-01 23:26 [PATCH 00/16] x86/reboot: KVM: Clean up "emergency" virt code Sean Christopherson
` (10 preceding siblings ...)
2022-12-01 23:26 ` [PATCH 11/16] KVM: SVM: Make KVM_AMD depend on CPU_SUP_AMD or CPU_SUP_HYGON Sean Christopherson
@ 2022-12-01 23:26 ` Sean Christopherson
2022-12-01 23:26 ` [PATCH 13/16] x86/virt: KVM: Open code cpu_has_svm() into kvm_is_svm_supported() Sean Christopherson
` (3 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Sean Christopherson @ 2022-12-01 23:26 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
Sean Christopherson, Paolo Bonzini
Cc: H. Peter Anvin, linux-kernel, kvm, Andrew Cooper
Drop the explicit check on the extended CPUID level in cpu_has_svm(), the
kernel's cached CPUID info will leave the entire SVM leaf unset if said
leaf is not supported by hardware. Prior to using cached information,
the check was needed to avoid false positives due to Intel's rather crazy
CPUID behavior of returning the values of the maximum supported leaf if
the specified leaf is unsupported.
Fixes: 682a8108872f ("x86/kvm/svm: Simplify cpu_has_svm()")
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
arch/x86/include/asm/virtext.h | 6 ------
1 file changed, 6 deletions(-)
diff --git a/arch/x86/include/asm/virtext.h b/arch/x86/include/asm/virtext.h
index 0b373543514f..eddc0eeb836f 100644
--- a/arch/x86/include/asm/virtext.h
+++ b/arch/x86/include/asm/virtext.h
@@ -39,12 +39,6 @@ static inline int cpu_has_svm(const char **msg)
return 0;
}
- if (boot_cpu_data.extended_cpuid_level < SVM_CPUID_FUNC) {
- if (msg)
- *msg = "can't execute cpuid_8000000a";
- return 0;
- }
-
if (!boot_cpu_has(X86_FEATURE_SVM)) {
if (msg)
*msg = "svm not available";
--
2.39.0.rc0.267.gcb52ba06e7-goog
^ permalink raw reply [flat|nested] 17+ messages in thread* [PATCH 13/16] x86/virt: KVM: Open code cpu_has_svm() into kvm_is_svm_supported()
2022-12-01 23:26 [PATCH 00/16] x86/reboot: KVM: Clean up "emergency" virt code Sean Christopherson
` (11 preceding siblings ...)
2022-12-01 23:26 ` [PATCH 12/16] x86/virt: Drop unnecessary check on extended CPUID level in cpu_has_svm() Sean Christopherson
@ 2022-12-01 23:26 ` Sean Christopherson
2022-12-01 23:26 ` [PATCH 14/16] x86/virt: KVM: Move "disable SVM" helper into KVM SVM Sean Christopherson
` (2 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Sean Christopherson @ 2022-12-01 23:26 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
Sean Christopherson, Paolo Bonzini
Cc: H. Peter Anvin, linux-kernel, kvm, Andrew Cooper
Fold the guts of cpu_has_svm() into kvm_is_svm_supported(), its sole
remaining user.
No functional change intended.
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
arch/x86/include/asm/virtext.h | 28 ----------------------------
arch/x86/kvm/svm/svm.c | 11 ++++++++---
2 files changed, 8 insertions(+), 31 deletions(-)
diff --git a/arch/x86/include/asm/virtext.h b/arch/x86/include/asm/virtext.h
index eddc0eeb836f..683d20411335 100644
--- a/arch/x86/include/asm/virtext.h
+++ b/arch/x86/include/asm/virtext.h
@@ -22,35 +22,7 @@
/*
* SVM functions:
*/
-
-/** Check if the CPU has SVM support
- *
- * You can use the 'msg' arg to get a message describing the problem,
- * if the function returns zero. Simply pass NULL if you are not interested
- * on the messages; gcc should take care of not generating code for
- * the messages on this case.
- */
-static inline int cpu_has_svm(const char **msg)
-{
- if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD &&
- boot_cpu_data.x86_vendor != X86_VENDOR_HYGON) {
- if (msg)
- *msg = "not amd or hygon";
- return 0;
- }
-
- if (!boot_cpu_has(X86_FEATURE_SVM)) {
- if (msg)
- *msg = "svm not available";
- return 0;
- }
- return 1;
-}
-
-
/** Disable SVM on the current CPU
- *
- * You should call this only if cpu_has_svm() returned true.
*/
static inline void cpu_svm_disable(void)
{
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index d56d5fe42262..ba281651dee4 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -523,11 +523,16 @@ static void svm_init_osvw(struct kvm_vcpu *vcpu)
static bool kvm_is_svm_supported(void)
{
int cpu = raw_smp_processor_id();
- const char *msg;
u64 vm_cr;
- if (!cpu_has_svm(&msg)) {
- pr_err("SVM not supported by CPU %d, %s\n", cpu, msg);
+ if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD &&
+ boot_cpu_data.x86_vendor != X86_VENDOR_HYGON) {
+ pr_err("CPU %d isn't AMD or Hygon\n", cpu);
+ return false;
+ }
+
+ if (!boot_cpu_has(X86_FEATURE_SVM)) {
+ pr_err("SVM not supported by CPU %d\n", cpu);
return false;
}
--
2.39.0.rc0.267.gcb52ba06e7-goog
^ permalink raw reply [flat|nested] 17+ messages in thread* [PATCH 14/16] x86/virt: KVM: Move "disable SVM" helper into KVM SVM
2022-12-01 23:26 [PATCH 00/16] x86/reboot: KVM: Clean up "emergency" virt code Sean Christopherson
` (12 preceding siblings ...)
2022-12-01 23:26 ` [PATCH 13/16] x86/virt: KVM: Open code cpu_has_svm() into kvm_is_svm_supported() Sean Christopherson
@ 2022-12-01 23:26 ` Sean Christopherson
2022-12-01 23:26 ` [PATCH 15/16] KVM: x86: Force kvm_rebooting=true during emergency reboot/crash Sean Christopherson
2022-12-01 23:26 ` [PATCH 16/16] KVM: SVM: Use "standard" stgi() helper when disabling SVM Sean Christopherson
15 siblings, 0 replies; 17+ messages in thread
From: Sean Christopherson @ 2022-12-01 23:26 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
Sean Christopherson, Paolo Bonzini
Cc: H. Peter Anvin, linux-kernel, kvm, Andrew Cooper
Move cpu_svm_disable() into KVM proper now that all hardware
virtualization management is routed through KVM. Remove the now-empty
virtext.h.
No functional change intended.
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
arch/x86/include/asm/virtext.h | 47 ----------------------------------
arch/x86/kvm/svm/svm.c | 25 +++++++++++++++---
2 files changed, 22 insertions(+), 50 deletions(-)
delete mode 100644 arch/x86/include/asm/virtext.h
diff --git a/arch/x86/include/asm/virtext.h b/arch/x86/include/asm/virtext.h
deleted file mode 100644
index 683d20411335..000000000000
--- a/arch/x86/include/asm/virtext.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/* CPU virtualization extensions handling
- *
- * This should carry the code for handling CPU virtualization extensions
- * that needs to live in the kernel core.
- *
- * Author: Eduardo Habkost <ehabkost@redhat.com>
- *
- * Copyright (C) 2008, Red Hat Inc.
- *
- * Contains code from KVM, Copyright (C) 2006 Qumranet, Inc.
- */
-#ifndef _ASM_X86_VIRTEX_H
-#define _ASM_X86_VIRTEX_H
-
-#include <asm/processor.h>
-
-#include <asm/vmx.h>
-#include <asm/svm.h>
-#include <asm/tlbflush.h>
-
-/*
- * SVM functions:
- */
-/** Disable SVM on the current CPU
- */
-static inline void cpu_svm_disable(void)
-{
- uint64_t efer;
-
- wrmsrl(MSR_VM_HSAVE_PA, 0);
- rdmsrl(MSR_EFER, efer);
- if (efer & EFER_SVME) {
- /*
- * Force GIF=1 prior to disabling SVM, e.g. to ensure INIT and
- * NMI aren't blocked. Eat faults on STGI, as it #UDs if SVM
- * isn't enabled and SVM can be disabled by an NMI callback.
- */
- asm_volatile_goto("1: stgi\n\t"
- _ASM_EXTABLE(1b, %l[fault])
- ::: "memory" : fault);
-fault:
- wrmsrl(MSR_EFER, efer & ~EFER_SVME);
- }
-}
-
-#endif /* _ASM_X86_VIRTEX_H */
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index ba281651dee4..2aec27b34487 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -41,7 +41,6 @@
#include <asm/reboot.h>
#include <asm/fpu/api.h>
-#include <asm/virtext.h>
#include "trace.h"
#include "svm.h"
@@ -571,9 +570,29 @@ void __svm_write_tsc_multiplier(u64 multiplier)
preempt_enable();
}
+static inline void kvm_cpu_svm_disable(void)
+{
+ uint64_t efer;
+
+ wrmsrl(MSR_VM_HSAVE_PA, 0);
+ rdmsrl(MSR_EFER, efer);
+ if (efer & EFER_SVME) {
+ /*
+ * Force GIF=1 prior to disabling SVM, e.g. to ensure INIT and
+ * NMI aren't blocked. Eat faults on STGI, as it #UDs if SVM
+ * isn't enabled and SVM can be disabled by an NMI callback.
+ */
+ asm_volatile_goto("1: stgi\n\t"
+ _ASM_EXTABLE(1b, %l[fault])
+ ::: "memory" : fault);
+fault:
+ wrmsrl(MSR_EFER, efer & ~EFER_SVME);
+ }
+}
+
static void svm_emergency_disable(void)
{
- cpu_svm_disable();
+ kvm_cpu_svm_disable();
}
static void svm_hardware_disable(void)
@@ -582,7 +601,7 @@ static void svm_hardware_disable(void)
if (tsc_scaling)
__svm_write_tsc_multiplier(SVM_TSC_RATIO_DEFAULT);
- cpu_svm_disable();
+ kvm_cpu_svm_disable();
amd_pmu_disable_virt();
}
--
2.39.0.rc0.267.gcb52ba06e7-goog
^ permalink raw reply [flat|nested] 17+ messages in thread* [PATCH 15/16] KVM: x86: Force kvm_rebooting=true during emergency reboot/crash
2022-12-01 23:26 [PATCH 00/16] x86/reboot: KVM: Clean up "emergency" virt code Sean Christopherson
` (13 preceding siblings ...)
2022-12-01 23:26 ` [PATCH 14/16] x86/virt: KVM: Move "disable SVM" helper into KVM SVM Sean Christopherson
@ 2022-12-01 23:26 ` Sean Christopherson
2022-12-01 23:26 ` [PATCH 16/16] KVM: SVM: Use "standard" stgi() helper when disabling SVM Sean Christopherson
15 siblings, 0 replies; 17+ messages in thread
From: Sean Christopherson @ 2022-12-01 23:26 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
Sean Christopherson, Paolo Bonzini
Cc: H. Peter Anvin, linux-kernel, kvm, Andrew Cooper
Set kvm_rebooting when virtualization is disabled in an emergency so that
KVM eats faults on virtualization instructions even if kvm_reboot() isn't
reached.
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
arch/x86/kvm/svm/svm.c | 2 ++
arch/x86/kvm/vmx/vmx.c | 2 ++
2 files changed, 4 insertions(+)
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index 2aec27b34487..08ed4679903a 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -592,6 +592,8 @@ static inline void kvm_cpu_svm_disable(void)
static void svm_emergency_disable(void)
{
+ kvm_rebooting = true;
+
kvm_cpu_svm_disable();
}
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index 8be99651dcc9..7f8147a7d126 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -770,6 +770,8 @@ static void vmx_emergency_disable(void)
int cpu = raw_smp_processor_id();
struct loaded_vmcs *v;
+ kvm_rebooting = true;
+
list_for_each_entry(v, &per_cpu(loaded_vmcss_on_cpu, cpu),
loaded_vmcss_on_cpu_link)
vmcs_clear(v->vmcs);
--
2.39.0.rc0.267.gcb52ba06e7-goog
^ permalink raw reply [flat|nested] 17+ messages in thread* [PATCH 16/16] KVM: SVM: Use "standard" stgi() helper when disabling SVM
2022-12-01 23:26 [PATCH 00/16] x86/reboot: KVM: Clean up "emergency" virt code Sean Christopherson
` (14 preceding siblings ...)
2022-12-01 23:26 ` [PATCH 15/16] KVM: x86: Force kvm_rebooting=true during emergency reboot/crash Sean Christopherson
@ 2022-12-01 23:26 ` Sean Christopherson
15 siblings, 0 replies; 17+ messages in thread
From: Sean Christopherson @ 2022-12-01 23:26 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
Sean Christopherson, Paolo Bonzini
Cc: H. Peter Anvin, linux-kernel, kvm, Andrew Cooper
Now that kvm_rebooting is guaranteed to be true prior to disabling SVM
in an emergency, use the existing stgi() helper instead of open coding
STGI. In effect, eat faults on STGI if and only if kvm_rebooting==true.
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
arch/x86/kvm/svm/svm.c | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index 08ed4679903a..72899a61f708 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -579,13 +579,9 @@ static inline void kvm_cpu_svm_disable(void)
if (efer & EFER_SVME) {
/*
* Force GIF=1 prior to disabling SVM, e.g. to ensure INIT and
- * NMI aren't blocked. Eat faults on STGI, as it #UDs if SVM
- * isn't enabled and SVM can be disabled by an NMI callback.
+ * NMI aren't blocked.
*/
- asm_volatile_goto("1: stgi\n\t"
- _ASM_EXTABLE(1b, %l[fault])
- ::: "memory" : fault);
-fault:
+ stgi();
wrmsrl(MSR_EFER, efer & ~EFER_SVME);
}
}
--
2.39.0.rc0.267.gcb52ba06e7-goog
^ permalink raw reply [flat|nested] 17+ messages in thread