On Intel, the APs are left in a well documented state after TXT performs
the late launch. Specifically they cannot have #INIT asserted on them so
a standard startup via INIT/SIPI/SIPI cannot be performed. Instead the
early SL stub code uses MONITOR and MWAIT to park the APs. The realmode/init.c
code updates the jump address for the waiting APs with the location of the
Secure Launch entry point in the RM piggy after it is loaded and fixed up.
As the APs are woken up by writing the monitor, the APs jump to the Secure
Launch entry point in the RM piggy which mimics what the real mode code would
do then jumps to the standard RM piggy protected mode entry point.
Signed-off-by: Ross Philipson
---
arch/x86/include/asm/realmode.h | 3 ++
arch/x86/kernel/smpboot.c| 56 +++-
arch/x86/realmode/init.c | 3 ++
arch/x86/realmode/rm/header.S| 3 ++
arch/x86/realmode/rm/trampoline_64.S | 32
5 files changed, 96 insertions(+), 1 deletion(-)
diff --git a/arch/x86/include/asm/realmode.h b/arch/x86/include/asm/realmode.h
index 87e5482acd0d..339b48e2543d 100644
--- a/arch/x86/include/asm/realmode.h
+++ b/arch/x86/include/asm/realmode.h
@@ -38,6 +38,9 @@ struct real_mode_header {
#ifdef CONFIG_X86_64
u32 machine_real_restart_seg;
#endif
+#ifdef CONFIG_SECURE_LAUNCH
+ u32 sl_trampoline_start32;
+#endif
};
/* This must match data at realmode/rm/trampoline_{32,64}.S */
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 2cc2aa120b4b..6f2a5ee458ce 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -60,6 +60,7 @@
#include
#include
#include
+#include
#include
#include
@@ -986,6 +987,56 @@ int common_cpu_up(unsigned int cpu, struct task_struct
*idle)
return 0;
}
+#ifdef CONFIG_SECURE_LAUNCH
+
+static bool slaunch_is_txt_launch(void)
+{
+ if ((slaunch_get_flags() & (SL_FLAG_ACTIVE|SL_FLAG_ARCH_TXT)) ==
+ (SL_FLAG_ACTIVE | SL_FLAG_ARCH_TXT))
+ return true;
+
+ return false;
+}
+
+/*
+ * TXT AP startup is quite different than normal. The APs cannot have #INIT
+ * asserted on them or receive SIPIs. The early Secure Launch code has parked
+ * the APs using monitor/mwait. This will wake the APs by writing the monitor
+ * and have them jump to the protected mode code in the rmpiggy where the rest
+ * of the SMP boot of the AP will proceed normally.
+ */
+static void slaunch_wakeup_cpu_from_txt(int cpu, int apicid)
+{
+ struct sl_ap_wake_info *ap_wake_info;
+ struct sl_ap_stack_and_monitor *stack_monitor = NULL;
+
+ ap_wake_info = slaunch_get_ap_wake_info();
+
+ stack_monitor = (struct sl_ap_stack_and_monitor
*)__va(ap_wake_info->ap_wake_block +
+
ap_wake_info->ap_stacks_offset);
+
+ for (unsigned int i = TXT_MAX_CPUS - 1; i >= 0; i--) {
+ if (stack_monitor[i].apicid == apicid) {
+ /* Write the monitor */
+ stack_monitor[i].monitor = 1;
+ break;
+ }
+ }
+}
+
+#else
+
+static inline bool slaunch_is_txt_launch(void)
+{
+ return false;
+}
+
+static inline void slaunch_wakeup_cpu_from_txt(int cpu, int apicid)
+{
+}
+
+#endif /* !CONFIG_SECURE_LAUNCH */
+
/*
* NOTE - on most systems this is a PHYSICAL apic ID, but on multiquad
* (ie clustered apic addressing mode), this is a LOGICAL apic ID.
@@ -1040,12 +1091,15 @@ static int do_boot_cpu(u32 apicid, int cpu, struct
task_struct *idle)
/*
* Wake up a CPU in difference cases:
+* - Intel TXT DRTM launch uses its own method to wake the APs
* - Use a method from the APIC driver if one defined, with wakeup
* straight to 64-bit mode preferred over wakeup to RM.
* Otherwise,
* - Use an INIT boot APIC message
*/
- if (apic->wakeup_secondary_cpu_64)
+ if (slaunch_is_txt_launch())
+ slaunch_wakeup_cpu_from_txt(cpu, apicid);
+ else if (apic->wakeup_secondary_cpu_64)
ret = apic->wakeup_secondary_cpu_64(apicid, start_ip);
else if (apic->wakeup_secondary_cpu)
ret = apic->wakeup_secondary_cpu(apicid, start_ip);
diff --git a/arch/x86/realmode/init.c b/arch/x86/realmode/init.c
index 788e5559549f..b548b3376765 100644
--- a/arch/x86/realmode/init.c
+++ b/arch/x86/realmode/init.c
@@ -4,6 +4,7 @@
#include
#include
#include
+#include
#include
#include
@@ -210,6 +211,8 @@ void __init init_real_mode(void)
setup_real_mode();
set_real_mode_permissions();
+
+ slaunch_fixup_jump_vector();
}
static int __init do_init_real_mode(void)
diff --git a/arch/x86/realmode/rm/header.S b/arch/x86/realmode/rm/header.S
index 2eb62be6d256..3b5cbcbbfc90 100644
--- a/arch/x86/realmode/rm/header.S
+++ b/arch/x86/realmode/rm/header.S
@@ -37,6 +37