Force all CPUs to do VMXOFF (via NMI shootdown) during an emergency
reboot if VMX is _supported_, as VMX being off on the current CPU does
not prevent other CPUs from being in VMX root (post-VMXON).  This fixes
a bug where a crash/panic reboot could leave other CPUs in VMX root and
prevent them from being woken via INIT-SIPI-SIPI in the new kernel.

Fixes: d176720d34c7 ("x86: disable VMX on all CPUs on reboot")
Cc: sta...@vger.kernel.org
Suggested-by: Sean Christopherson <sea...@google.com>
Signed-off-by: David P. Reed <dpr...@deepplum.com>
[sean: reworked changelog and further tweaked comment]
Signed-off-by: Sean Christopherson <sea...@google.com>
---
 arch/x86/kernel/reboot.c | 30 ++++++++++--------------------
 1 file changed, 10 insertions(+), 20 deletions(-)

diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
index db115943e8bd..efbaef8b4de9 100644
--- a/arch/x86/kernel/reboot.c
+++ b/arch/x86/kernel/reboot.c
@@ -538,31 +538,21 @@ static void emergency_vmx_disable_all(void)
        local_irq_disable();
 
        /*
-        * We need to disable VMX on all CPUs before rebooting, otherwise
-        * we risk hanging up the machine, because the CPU ignores INIT
-        * signals when VMX is enabled.
+        * Disable VMX on all CPUs before rebooting, otherwise we risk hanging
+        * the machine, because the CPU blocks INIT when it's in VMX root.
         *
-        * We can't take any locks and we may be on an inconsistent
-        * state, so we use NMIs as IPIs to tell the other CPUs to disable
-        * VMX and halt.
+        * We can't take any locks and we may be on an inconsistent state, so
+        * use NMIs as IPIs to tell the other CPUs to exit VMX root and halt.
         *
-        * For safety, we will avoid running the nmi_shootdown_cpus()
-        * stuff unnecessarily, but we don't have a way to check
-        * if other CPUs have VMX enabled. So we will call it only if the
-        * CPU we are running on has VMX enabled.
-        *
-        * We will miss cases where VMX is not enabled on all CPUs. This
-        * shouldn't do much harm because KVM always enable VMX on all
-        * CPUs anyway. But we can miss it on the small window where KVM
-        * is still enabling VMX.
+        * Do the NMI shootdown even if VMX if off on _this_ CPU, as that
+        * doesn't prevent a different CPU from being in VMX root operation.
         */
-       if (cpu_has_vmx() && cpu_vmx_enabled()) {
-               /* Disable VMX on this CPU. */
-               cpu_vmxoff();
+       if (cpu_has_vmx()) {
+               /* Safely force _this_ CPU out of VMX root operation. */
+               __cpu_emergency_vmxoff();
 
-               /* Halt and disable VMX on the other CPUs */
+               /* Halt and exit VMX root operation on the other CPUs. */
                nmi_shootdown_cpus(vmxoff_nmi);
-
        }
 }
 
-- 
2.29.2.729.g45daf8777d-goog

Reply via email to