From: Joerg Roedel <jroe...@suse.de>

Add a play_dead handler when running under SEV-ES. This is needed
because the hypervisor can't deliver an SIPI request to restart the AP.
Instead the kernel has to issue a VMGEXIT to halt the VCPU. When the
hypervisor would deliver and SIPI is wakes up the VCPU instead.

Signed-off-by: Joerg Roedel <jroe...@suse.de>
---
 arch/x86/include/uapi/asm/svm.h |  1 +
 arch/x86/kernel/sev-es.c        | 46 +++++++++++++++++++++++++++++++++
 2 files changed, 47 insertions(+)

diff --git a/arch/x86/include/uapi/asm/svm.h b/arch/x86/include/uapi/asm/svm.h
index a19ce9681ec2..20a05839dd9a 100644
--- a/arch/x86/include/uapi/asm/svm.h
+++ b/arch/x86/include/uapi/asm/svm.h
@@ -84,6 +84,7 @@
 /* SEV-ES software-defined VMGEXIT events */
 #define SVM_VMGEXIT_MMIO_READ                  0x80000001
 #define SVM_VMGEXIT_MMIO_WRITE                 0x80000002
+#define SVM_VMGEXIT_AP_HLT_LOOP                        0x80000004
 #define SVM_VMGEXIT_AP_JUMP_TABLE              0x80000005
 #define                SVM_VMGEXIT_SET_AP_JUMP_TABLE                   0
 #define                SVM_VMGEXIT_GET_AP_JUMP_TABLE                   1
diff --git a/arch/x86/kernel/sev-es.c b/arch/x86/kernel/sev-es.c
index d8193d37ed2b..755708f72824 100644
--- a/arch/x86/kernel/sev-es.c
+++ b/arch/x86/kernel/sev-es.c
@@ -22,6 +22,8 @@
 #include <asm/processor.h>
 #include <asm/traps.h>
 #include <asm/svm.h>
+#include <asm/smp.h>
+#include <asm/cpu.h>
 
 #define DR7_RESET_VALUE        0x400
 
@@ -252,6 +254,48 @@ static bool __init setup_ghcb(void)
        return true;
 }
 
+#ifdef CONFIG_HOTPLUG_CPU
+static void sev_es_ap_hlt_loop(void)
+{
+       struct ghcb *ghcb;
+
+       ghcb = this_cpu_ptr(&ghcb_page);
+
+       while (true) {
+               ghcb_invalidate(ghcb);
+               ghcb_set_sw_exit_code(ghcb, SVM_VMGEXIT_AP_HLT_LOOP);
+               ghcb_set_sw_exit_info_1(ghcb, 0);
+               ghcb_set_sw_exit_info_2(ghcb, 0);
+
+               write_ghcb_msr(__pa(ghcb));
+               VMGEXIT();
+
+               /* Wakup Signal? */
+               if (ghcb_is_valid_sw_exit_info_2(ghcb) &&
+                   ghcb->save.sw_exit_info_2 != 0)
+                       break;
+       }
+}
+
+void sev_es_play_dead(void)
+{
+       play_dead_common();
+
+       /* IRQs now disabled */
+
+       sev_es_ap_hlt_loop();
+
+       /*
+        * If we get here, the VCPU was woken up again. Jump to CPU
+        * startup code to get it back online.
+        */
+
+       start_cpu();
+}
+#else  /* CONFIG_HOTPLUG_CPU */
+#define sev_es_play_dead       native_play_dead
+#endif /* CONFIG_HOTPLUG_CPU */
+
 void encrypted_state_init_ghcbs(void)
 {
        int cpu;
@@ -267,6 +311,8 @@ void encrypted_state_init_ghcbs(void)
                                     sizeof(ghcb_page) >> PAGE_SHIFT);
                memset(ghcb, 0, sizeof(*ghcb));
        }
+
+       smp_ops.play_dead = sev_es_play_dead;
 }
 
 static void __init early_forward_exception(struct es_em_ctxt *ctxt)
-- 
2.17.1

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

Reply via email to