[kvm-unit-tests RFC v2 11/18] x86 TDX: Add multi processor support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Zhenzhong Duan <zhenzhong.duan@xxxxxxxxx>

In TD-guest, multiprocessor support is different from normal guest.

In normal guest, BSP send startup IPI to all APs to trigger APs starting
from 16bit real mode.

While in TD-guest, TDVF initializes APs into 64bit mode before pass to
OS/bootloader. OS enumerates uid/apicid mapping information through MADT
table and wake up APs one by one through MP wakeup mechanism. So the
entry code for APs is 64bit.

Signed-off-by: Zhenzhong Duan <zhenzhong.duan@xxxxxxxxx>
Reviewed-by: Yu Zhang <yu.c.zhang@xxxxxxxxx>
Link: https://lore.kernel.org/r/20220303071907.650203-11-zhenzhong.duan@xxxxxxxxx
Co-developed-by: Qian Wen <qian.wen@xxxxxxxxx>
Signed-off-by: Qian Wen <qian.wen@xxxxxxxxx>
---
 lib/x86/setup.c      | 16 +++++++++++----
 lib/x86/smp.c        | 26 +++++++++++++++++++++++++
 lib/x86/smp.h        |  2 ++
 x86/efi/efistart64.S | 46 ++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 86 insertions(+), 4 deletions(-)

diff --git a/lib/x86/setup.c b/lib/x86/setup.c
index 406d04e3..82a563a3 100644
--- a/lib/x86/setup.c
+++ b/lib/x86/setup.c
@@ -407,17 +407,25 @@ void save_id(void)
 void ap_start64(void)
 {
 	setup_gdt_tss();
-	reset_apic();
 	load_idt();
-	save_id();
-	enable_apic();
+	if (!is_tdx_guest()) {
+		reset_apic();
+		save_id();
+		enable_apic();
+	}
 	enable_x2apic();
 	ap_online();
 }
 
+extern void tdx_ap_start64(void);
 void bsp_rest_init(void)
 {
-	bringup_aps();
+	if (!is_tdx_guest()) {
+		bringup_aps();
+	} else {
+		/* TDX uses ACPI WAKE UP mechanism to wake up APs instead of SIPI */
+		bringup_aps_acpi((u64)tdx_ap_start64);
+	}
 	enable_x2apic();
 	smp_init();
 	pmu_init();
diff --git a/lib/x86/smp.c b/lib/x86/smp.c
index e297016c..7147cf6b 100644
--- a/lib/x86/smp.c
+++ b/lib/x86/smp.c
@@ -11,6 +11,7 @@
 #include "desc.h"
 #include "alloc_page.h"
 #include "asm/page.h"
+#include "acpi.h"
 
 #define IPI_VECTOR 0x20
 
@@ -288,3 +289,28 @@ void bringup_aps(void)
 	while (_cpu_count != atomic_read(&cpu_online_count))
 		cpu_relax();
 }
+
+/* wakeup APs by sending the OS commands to ACPI mailbox. */
+efi_status_t bringup_aps_acpi(unsigned long start_ip)
+{
+	u32 i;
+	_cpu_count = fwcfg_get_nb_cpus();
+
+	/* BSP is already online */
+	set_bit(id_map[0], online_cpus);
+
+#ifdef CONFIG_EFI
+	smp_stacktop = ((u64) (&stacktop)) - PAGE_SIZE;
+#endif
+
+	for (i = 1; i < _cpu_count; i++) {
+		if (acpi_wakeup_cpu(id_map[i], start_ip, online_cpus))
+			return EFI_DEVICE_ERROR;
+		set_bit(id_map[i], online_cpus);
+	}
+
+	while (atomic_read(&cpu_online_count) != _cpu_count)
+		cpu_relax();
+
+	return EFI_SUCCESS;
+}
diff --git a/lib/x86/smp.h b/lib/x86/smp.h
index 08a440b3..a0a6b3f6 100644
--- a/lib/x86/smp.h
+++ b/lib/x86/smp.h
@@ -6,6 +6,7 @@
 #include "libcflat.h"
 #include "atomic.h"
 #include "apic-defs.h"
+#include "efi.h"
 
 /* Address where to store the address of realmode GDT descriptor. */
 #define REALMODE_GDT_LOWMEM (PAGE_SIZE - 2)
@@ -86,6 +87,7 @@ void on_cpus(void (*function)(void *data), void *data);
 void smp_reset_apic(void);
 void bringup_aps(void);
 void ap_online(void);
+efi_status_t bringup_aps_acpi(unsigned long start_ip);
 
 extern atomic_t cpu_online_count;
 extern unsigned char online_cpus[(MAX_TEST_CPUS + 7) / 8];
diff --git a/x86/efi/efistart64.S b/x86/efi/efistart64.S
index 3fc16016..e3add79a 100644
--- a/x86/efi/efistart64.S
+++ b/x86/efi/efistart64.S
@@ -35,6 +35,52 @@ ptl4:
 .code64
 .text
 
+.macro load_absolute_addr64, addr, reg
+	call 1f
+1:
+	popq \reg
+	addq \addr - 1b, \reg
+.endm
+
+MSR_GS_BASE = 0xc0000101
+
+.macro setup_percpu_area_64
+	lea -4096(%rsp), %rax
+	movq $0, %rdx
+	movq $MSR_GS_BASE, %rcx
+	wrmsr
+.endm
+
+.macro prepare_td
+	load_absolute_addr64 $gdt_descr, %rdx
+	lgdt (%rdx)
+
+	movq $MSR_GS_BASE, %rcx
+	rdmsr
+
+	/* Update data segments */
+	mov $0x10, %bx
+	mov %bx, %ds
+	mov %bx, %es
+	mov %bx, %fs
+	mov %bx, %gs
+	mov %bx, %ss
+
+	/* restore MSR_GS_BASE */
+	wrmsr
+.endm
+
+.globl tdx_ap_start64
+tdx_ap_start64:
+	movq $-PAGE_SIZE, %rsp
+	lock xadd %rsp, smp_stacktop(%rip)
+	setup_percpu_area_64
+	prepare_td
+	load_absolute_addr64 $ap_start64, %rdx
+	pushq $0x08
+	pushq %rdx
+	lretq
+
 .code16
 REALMODE_GDT_LOWMEM = PAGE_SIZE - 2
 
-- 
2.25.1





[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux