[v7,09/13] x86: Secure Launch SMP bringup support

Message ID 20231110222751.219836-10-ross.philipson@oracle.com
State New
Headers
Series x86: Trenchboot secure dynamic launch Linux kernel support |

Commit Message

Ross Philipson Nov. 10, 2023, 10:27 p.m. UTC
  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 <ross.philipson@oracle.com>
---
 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(-)
  

Comments

kernel test robot Nov. 11, 2023, 10:41 a.m. UTC | #1
Hi Ross,

kernel test robot noticed the following build warnings:

[auto build test WARNING on tip/x86/core]
[also build test WARNING on herbert-cryptodev-2.6/master herbert-crypto-2.6/master linus/master v6.6 next-20231110]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Ross-Philipson/x86-boot-Place-kernel_info-at-a-fixed-offset/20231111-063453
base:   tip/x86/core
patch link:    https://lore.kernel.org/r/20231110222751.219836-10-ross.philipson%40oracle.com
patch subject: [PATCH v7 09/13] x86: Secure Launch SMP bringup support
config: x86_64-rhel-8.3-rust (https://download.01.org/0day-ci/archive/20231111/202311111806.sbmcWUN1-lkp@intel.com/config)
compiler: clang version 16.0.4 (https://github.com/llvm/llvm-project.git ae42196bc493ffe877a7e3dff8be32035dea4d07)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20231111/202311111806.sbmcWUN1-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202311111806.sbmcWUN1-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> arch/x86/kernel/smpboot.c:1097:6: warning: variable 'ret' is used uninitialized whenever 'if' condition is true [-Wsometimes-uninitialized]
           if (slaunch_is_txt_launch())
               ^~~~~~~~~~~~~~~~~~~~~~~
   arch/x86/kernel/smpboot.c:1107:6: note: uninitialized use occurs here
           if (ret)
               ^~~
   arch/x86/kernel/smpboot.c:1097:2: note: remove the 'if' if its condition is always false
           if (slaunch_is_txt_launch())
           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
   arch/x86/kernel/smpboot.c:1046:9: note: initialize the variable 'ret' to silence this warning
           int ret;
                  ^
                   = 0
   1 warning generated.


vim +1097 arch/x86/kernel/smpboot.c

  1036	
  1037	/*
  1038	 * NOTE - on most systems this is a PHYSICAL apic ID, but on multiquad
  1039	 * (ie clustered apic addressing mode), this is a LOGICAL apic ID.
  1040	 * Returns zero if startup was successfully sent, else error code from
  1041	 * ->wakeup_secondary_cpu.
  1042	 */
  1043	static int do_boot_cpu(u32 apicid, int cpu, struct task_struct *idle)
  1044	{
  1045		unsigned long start_ip = real_mode_header->trampoline_start;
  1046		int ret;
  1047	
  1048	#ifdef CONFIG_X86_64
  1049		/* If 64-bit wakeup method exists, use the 64-bit mode trampoline IP */
  1050		if (apic->wakeup_secondary_cpu_64)
  1051			start_ip = real_mode_header->trampoline_start64;
  1052	#endif
  1053		idle->thread.sp = (unsigned long)task_pt_regs(idle);
  1054		initial_code = (unsigned long)start_secondary;
  1055	
  1056		if (IS_ENABLED(CONFIG_X86_32)) {
  1057			early_gdt_descr.address = (unsigned long)get_cpu_gdt_rw(cpu);
  1058			initial_stack  = idle->thread.sp;
  1059		} else if (!(smpboot_control & STARTUP_PARALLEL_MASK)) {
  1060			smpboot_control = cpu;
  1061		}
  1062	
  1063		/* Enable the espfix hack for this CPU */
  1064		init_espfix_ap(cpu);
  1065	
  1066		/* So we see what's up */
  1067		announce_cpu(cpu, apicid);
  1068	
  1069		/*
  1070		 * This grunge runs the startup process for
  1071		 * the targeted processor.
  1072		 */
  1073		if (x86_platform.legacy.warm_reset) {
  1074	
  1075			pr_debug("Setting warm reset code and vector.\n");
  1076	
  1077			smpboot_setup_warm_reset_vector(start_ip);
  1078			/*
  1079			 * Be paranoid about clearing APIC errors.
  1080			*/
  1081			if (APIC_INTEGRATED(boot_cpu_apic_version)) {
  1082				apic_write(APIC_ESR, 0);
  1083				apic_read(APIC_ESR);
  1084			}
  1085		}
  1086	
  1087		smp_mb();
  1088	
  1089		/*
  1090		 * Wake up a CPU in difference cases:
  1091		 * - Intel TXT DRTM launch uses its own method to wake the APs
  1092		 * - Use a method from the APIC driver if one defined, with wakeup
  1093		 *   straight to 64-bit mode preferred over wakeup to RM.
  1094		 * Otherwise,
  1095		 * - Use an INIT boot APIC message
  1096		 */
> 1097		if (slaunch_is_txt_launch())
  1098			slaunch_wakeup_cpu_from_txt(cpu, apicid);
  1099		else if (apic->wakeup_secondary_cpu_64)
  1100			ret = apic->wakeup_secondary_cpu_64(apicid, start_ip);
  1101		else if (apic->wakeup_secondary_cpu)
  1102			ret = apic->wakeup_secondary_cpu(apicid, start_ip);
  1103		else
  1104			ret = wakeup_secondary_cpu_via_init(apicid, start_ip);
  1105	
  1106		/* If the wakeup mechanism failed, cleanup the warm reset vector */
  1107		if (ret)
  1108			arch_cpuhp_cleanup_kick_cpu(cpu);
  1109		return ret;
  1110	}
  1111
  

Patch

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 <linux/stackprotector.h>
 #include <linux/cpuhotplug.h>
 #include <linux/mc146818rtc.h>
+#include <linux/slaunch.h>
 
 #include <asm/acpi.h>
 #include <asm/cacheinfo.h>
@@ -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 <linux/memblock.h>
 #include <linux/cc_platform.h>
 #include <linux/pgtable.h>
+#include <linux/slaunch.h>
 
 #include <asm/set_memory.h>
 #include <asm/realmode.h>
@@ -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,9 @@  SYM_DATA_START(real_mode_header)
 #ifdef CONFIG_X86_64
 	.long	__KERNEL32_CS
 #endif
+#ifdef CONFIG_SECURE_LAUNCH
+	.long	pa_sl_trampoline_start32
+#endif
 SYM_DATA_END(real_mode_header)
 
 	/* End signature, used to verify integrity */
diff --git a/arch/x86/realmode/rm/trampoline_64.S b/arch/x86/realmode/rm/trampoline_64.S
index c9f76fae902e..526d449d5383 100644
--- a/arch/x86/realmode/rm/trampoline_64.S
+++ b/arch/x86/realmode/rm/trampoline_64.S
@@ -120,6 +120,38 @@  SYM_CODE_END(sev_es_trampoline_start)
 
 	.section ".text32","ax"
 	.code32
+#ifdef CONFIG_SECURE_LAUNCH
+	.balign 4
+SYM_CODE_START(sl_trampoline_start32)
+	/*
+	 * The early secure launch stub AP wakeup code has taken care of all
+	 * the vagaries of launching out of TXT. This bit just mimics what the
+	 * 16b entry code does and jumps off to the real startup_32.
+	 */
+	cli
+	wbinvd
+
+	/*
+	 * The %ebx provided is not terribly useful since it is the physical
+	 * address of tb_trampoline_start and not the base of the image.
+	 * Use pa_real_mode_base, which is fixed up, to get a run time
+	 * base register to use for offsets to location that do not have
+	 * pa_ symbols.
+	 */
+	movl    $pa_real_mode_base, %ebx
+
+	LOCK_AND_LOAD_REALMODE_ESP lock_pa=1
+
+	lgdt    tr_gdt(%ebx)
+	lidt    tr_idt(%ebx)
+
+	movw	$__KERNEL_DS, %dx	# Data segment descriptor
+
+	/* Jump to where the 16b code would have jumped */
+	ljmpl	$__KERNEL32_CS, $pa_startup_32
+SYM_CODE_END(sl_trampoline_start32)
+#endif
+
 	.balign 4
 SYM_CODE_START(startup_32)
 	movl	%edx, %ss