[RFC PATCH 6/9] x86: Prepare CPUs for post SKINIT launch

From: Sergii Dmytruk
Date: Thu Dec 12 2024 - 09:12:37 EST


From: Ross Philipson <ross.philipson@xxxxxxxxxx>

The SKINIT instruction disables the GIF and it must be re-enabled
on the BSP and APs as they are started. Since enabling GIF also
re-enables NMIs, it should be done after a valid IDT is loaded for
each CPU.

SKINIT also already performed #INIT on the APs and it should be
bypassed before issuing the startup IPIs.

Signed-off-by: Ross Philipson <ross.philipson@xxxxxxxxxx>
Signed-off-by: Sergii Dmytruk <sergii.dmytruk@xxxxxxxxx>
---
arch/x86/kernel/slaunch.c | 23 +++++++++++++++++++++++
arch/x86/kernel/smpboot.c | 15 ++++++++++++++-
arch/x86/kernel/traps.c | 4 ++++
3 files changed, 41 insertions(+), 1 deletion(-)

diff --git a/arch/x86/kernel/slaunch.c b/arch/x86/kernel/slaunch.c
index ff05f032e44f..3a6e4d22b54d 100644
--- a/arch/x86/kernel/slaunch.c
+++ b/arch/x86/kernel/slaunch.c
@@ -17,6 +17,7 @@
#include <asm/sections.h>
#include <asm/tlbflush.h>
#include <asm/e820/api.h>
+#include <asm/svm.h>
#include <asm/setup.h>
#include <asm/svm.h>
#include <asm/realmode.h>
@@ -716,3 +717,25 @@ void slaunch_finalize(int do_sexit)
else if (boot_cpu_has(X86_FEATURE_SKINIT))
slaunch_finalize_skinit();
}
+
+/*
+ * AMD specific SKINIT CPU setup and initialization.
+ */
+void slaunch_cpu_setup_skinit(void)
+{
+ u64 val;
+
+ if (!slaunch_is_skinit_launch())
+ return;
+
+ /*
+ * We don't yet handle #SX. Disable INIT_REDIRECTION first, before
+ * enabling GIF, so a pending INIT resets us, rather than causing a
+ * panic due to an unknown exception.
+ */
+ rdmsrl(MSR_VM_CR, val);
+ wrmsrl(MSR_VM_CR, val & ~(1 << SVM_VM_CR_INIT_REDIRECTION));
+
+ /* Enable Global Interrupts flag */
+ asm volatile ("stgi" ::: "memory");
+}
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 0c915e105a9b..a0e5971725d9 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -249,6 +249,12 @@ static void notrace start_secondary(void *unused)

cpu_init_exception_handling();

+ /*
+ * If this is an AMD SKINIT secure launch, some extra work is done
+ * to prepare to start the secondary CPUs.
+ */
+ slaunch_cpu_setup_skinit();
+
/*
* Load the microcode before reaching the AP alive synchronization
* point below so it is not part of the full per CPU serialized
@@ -735,7 +741,14 @@ static int wakeup_secondary_cpu_via_init(u32 phys_apicid, unsigned long start_ei

preempt_disable();
maxlvt = lapic_get_maxlvt();
- send_init_sequence(phys_apicid);
+
+ /*
+ * If this is an SKINIT secure launch, #INIT is already done on the APs
+ * by issuing the SKINIT instruction. For security reasons #INIT
+ * should not be done again.
+ */
+ if (!slaunch_is_skinit_launch())
+ send_init_sequence(phys_apicid);

mb();

diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index 4fa0b17e5043..1603b2e6faa5 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -42,6 +42,7 @@
#include <linux/hardirq.h>
#include <linux/atomic.h>
#include <linux/iommu.h>
+#include <linux/slaunch.h>

#include <asm/stacktrace.h>
#include <asm/processor.h>
@@ -1443,5 +1444,8 @@ void __init trap_init(void)
if (!cpu_feature_enabled(X86_FEATURE_FRED))
idt_setup_traps();

+ /* If SKINIT was done on the BSP, this is the spot to enable GIF */
+ slaunch_cpu_setup_skinit();
+
cpu_init();
}
--
2.47.1