2222#include <asm/reboot_fixups.h>
2323#include <asm/reboot.h>
2424#include <asm/pci_x86.h>
25- #include <asm/virtext.h>
2625#include <asm/cpu.h>
2726#include <asm/nmi.h>
2827#include <asm/smp.h>
@@ -530,9 +529,54 @@ static inline void kb_wait(void)
530529
531530static inline void nmi_shootdown_cpus_on_restart (void );
532531
532+ #if IS_ENABLED (CONFIG_KVM_INTEL ) || IS_ENABLED (CONFIG_KVM_AMD )
533+ /* RCU-protected callback to disable virtualization prior to reboot. */
534+ static cpu_emergency_virt_cb __rcu * cpu_emergency_virt_callback ;
535+
536+ void cpu_emergency_register_virt_callback (cpu_emergency_virt_cb * callback )
537+ {
538+ if (WARN_ON_ONCE (rcu_access_pointer (cpu_emergency_virt_callback )))
539+ return ;
540+
541+ rcu_assign_pointer (cpu_emergency_virt_callback , callback );
542+ }
543+ EXPORT_SYMBOL_GPL (cpu_emergency_register_virt_callback );
544+
545+ void cpu_emergency_unregister_virt_callback (cpu_emergency_virt_cb * callback )
546+ {
547+ if (WARN_ON_ONCE (rcu_access_pointer (cpu_emergency_virt_callback ) != callback ))
548+ return ;
549+
550+ rcu_assign_pointer (cpu_emergency_virt_callback , NULL );
551+ synchronize_rcu ();
552+ }
553+ EXPORT_SYMBOL_GPL (cpu_emergency_unregister_virt_callback );
554+
555+ /*
556+ * Disable virtualization, i.e. VMX or SVM, to ensure INIT is recognized during
557+ * reboot. VMX blocks INIT if the CPU is post-VMXON, and SVM blocks INIT if
558+ * GIF=0, i.e. if the crash occurred between CLGI and STGI.
559+ */
560+ void cpu_emergency_disable_virtualization (void )
561+ {
562+ cpu_emergency_virt_cb * callback ;
563+
564+ /*
565+ * IRQs must be disabled as KVM enables virtualization in hardware via
566+ * function call IPIs, i.e. IRQs need to be disabled to guarantee
567+ * virtualization stays disabled.
568+ */
569+ lockdep_assert_irqs_disabled ();
570+
571+ rcu_read_lock ();
572+ callback = rcu_dereference (cpu_emergency_virt_callback );
573+ if (callback )
574+ callback ();
575+ rcu_read_unlock ();
576+ }
577+
533578static void emergency_reboot_disable_virtualization (void )
534579{
535- /* Just make sure we won't change CPUs while doing this */
536580 local_irq_disable ();
537581
538582 /*
@@ -545,15 +589,17 @@ static void emergency_reboot_disable_virtualization(void)
545589 * Do the NMI shootdown even if virtualization is off on _this_ CPU, as
546590 * other CPUs may have virtualization enabled.
547591 */
548- if (cpu_has_vmx () || cpu_has_svm ( NULL )) {
592+ if (rcu_access_pointer ( cpu_emergency_virt_callback )) {
549593 /* Safely force _this_ CPU out of VMX/SVM operation. */
550594 cpu_emergency_disable_virtualization ();
551595
552596 /* Disable VMX/SVM and halt on other CPUs. */
553597 nmi_shootdown_cpus_on_restart ();
554598 }
555599}
556-
600+ #else
601+ static void emergency_reboot_disable_virtualization (void ) { }
602+ #endif /* CONFIG_KVM_INTEL || CONFIG_KVM_AMD */
557603
558604void __attribute__((weak )) mach_reboot_fixups (void )
559605{
@@ -787,21 +833,9 @@ void machine_crash_shutdown(struct pt_regs *regs)
787833}
788834#endif
789835
790-
791836/* This is the CPU performing the emergency shutdown work. */
792837int crashing_cpu = -1 ;
793838
794- /*
795- * Disable virtualization, i.e. VMX or SVM, to ensure INIT is recognized during
796- * reboot. VMX blocks INIT if the CPU is post-VMXON, and SVM blocks INIT if
797- * GIF=0, i.e. if the crash occurred between CLGI and STGI.
798- */
799- void cpu_emergency_disable_virtualization (void )
800- {
801- cpu_emergency_vmxoff ();
802- cpu_emergency_svm_disable ();
803- }
804-
805839#if defined(CONFIG_SMP )
806840
807841static nmi_shootdown_cb shootdown_callback ;
0 commit comments