diff mbox series

[kvm-unit-tests,v3,10/11] x86: efi, smp: Transition APs from 32-bit to 64-bit mode

Message ID 20220426114352.1262-11-varad.gautam@suse.com (mailing list archive)
State New, archived
Headers show
Series SMP Support for x86 UEFI Tests | expand

Commit Message

Varad Gautam April 26, 2022, 11:43 a.m. UTC
Reaching 64-bit mode requires setting up a valid stack and percpu
regions for each CPU and configuring a page table before far-jumping to
the 64-bit entrypoint.

This functionality is already present as prepare_64() and ap_start32()
routines in start32.S for non-EFI test builds.

However since EFI builds (-fPIC) cannot use absolute addressing, and
32-bit mode does not allow RIP-relative addressing, these routines need
some changes.

Modify prepare_64() and ap_start32() asm routines to calculate label
addresses during runtime on CONFIG_EFI. To ease the common case, replace
the far-jump to ap_start64() with a far-return.

This brings the APs into 64-bit mode to loop at a known location.

Signed-off-by: Varad Gautam <varad.gautam@suse.com>
---
 lib/x86/setup.c      |  2 +-
 lib/x86/smp.c        |  6 ++++++
 x86/efi/efistart64.S | 13 ++++++++++---
 x86/start32.S        | 46 +++++++++++++++++++++++++++++++++++++++++---
 4 files changed, 60 insertions(+), 7 deletions(-)

Comments

Sean Christopherson June 15, 2022, 11:12 p.m. UTC | #1
On Tue, Apr 26, 2022, Varad Gautam wrote:
> diff --git a/x86/start32.S b/x86/start32.S
> index 9e00474..2089be7 100644
> --- a/x86/start32.S
> +++ b/x86/start32.S
> @@ -27,7 +27,16 @@ MSR_GS_BASE = 0xc0000101
>  .endm
>  
>  prepare_64:
> -	lgdt gdt_descr
> +#ifdef CONFIG_EFI
> +	call prepare_64_1
> +prepare_64_1:

Use "1:" for the label, and 1f / 1b, that way it's obvious it's a relatively transient
thing.

> +	pop %edx
> +	add $gdt_descr - prepare_64_1, %edx
> +#else
> +	mov $gdt_descr, %edx
> +#endif

Rather than have #ifdefs everyway, add a macro to hide the differences, e.g.
load_absolute_addr.
diff mbox series

Patch

diff --git a/lib/x86/setup.c b/lib/x86/setup.c
index c34a8bb..7ca0fab 100644
--- a/lib/x86/setup.c
+++ b/lib/x86/setup.c
@@ -347,11 +347,11 @@  efi_status_t setup_efi(efi_bootinfo_t *efi_bootinfo)
 	setup_idt();
 	load_idt();
 	mask_pic_interrupts();
+	setup_page_table();
 	enable_apic();
 	ap_init();
 	enable_x2apic();
 	smp_init();
-	setup_page_table();
 
 	return EFI_SUCCESS;
 }
diff --git a/lib/x86/smp.c b/lib/x86/smp.c
index 360ae82..8e5c6e8 100644
--- a/lib/x86/smp.c
+++ b/lib/x86/smp.c
@@ -27,6 +27,8 @@  extern u8 ap_rm_gdt_descr;
 #ifdef CONFIG_EFI
 extern u8 ap_rm_gdt, ap_rm_gdt_end;
 extern u8 ap_start32;
+extern u32 smp_stacktop;
+extern u8 stacktop;
 #endif
 atomic_t cpu_online_count = { .counter = 1 };
 
@@ -250,6 +252,10 @@  void ap_init(void)
 
 	setup_rm_gdt();
 
+#ifdef CONFIG_EFI
+	smp_stacktop = ((u64) (&stacktop)) - PAGE_SIZE;
+#endif
+
 	/* INIT */
 	apic_icr_write(APIC_DEST_ALLBUT | APIC_DEST_PHYSICAL | APIC_DM_INIT | APIC_INT_ASSERT, 0);
 
diff --git a/x86/efi/efistart64.S b/x86/efi/efistart64.S
index c6b1a5b..d82e3fc 100644
--- a/x86/efi/efistart64.S
+++ b/x86/efi/efistart64.S
@@ -12,6 +12,9 @@ 
 .globl stacktop
 stacktop:
 
+.globl smp_stacktop
+smp_stacktop:	.long 0
+
 .align PAGE_SIZE
 .globl ptl2
 ptl2:
@@ -71,6 +74,10 @@  sipi_end:
 rm_trampoline_end:
 
 .code32
-.globl ap_start32
-ap_start32:
-	jmp ap_start32
+
+#include "../start32.S"
+
+.code64:
+
+ap_start64:
+	jmp ap_start64
diff --git a/x86/start32.S b/x86/start32.S
index 9e00474..2089be7 100644
--- a/x86/start32.S
+++ b/x86/start32.S
@@ -27,7 +27,16 @@  MSR_GS_BASE = 0xc0000101
 .endm
 
 prepare_64:
-	lgdt gdt_descr
+#ifdef CONFIG_EFI
+	call prepare_64_1
+prepare_64_1:
+	pop %edx
+	add $gdt_descr - prepare_64_1, %edx
+#else
+	mov $gdt_descr, %edx
+#endif
+	lgdtl (%edx)
+
 	setup_segments
 
 	xor %eax, %eax
@@ -38,7 +47,14 @@  enter_long_mode:
 	bts $5, %eax  // pae
 	mov %eax, %cr4
 
+#ifdef CONFIG_EFI
+	call prepare_64_2
+prepare_64_2:
+	pop %eax
+	add $ptl4 - prepare_64_2, %eax
+#else
 	mov pt_root, %eax
+#endif
 	mov %eax, %cr3
 
 efer = 0xc0000080
@@ -53,10 +69,34 @@  efer = 0xc0000080
 	mov %eax, %cr0
 	ret
 
+.globl ap_start32
 ap_start32:
 	setup_segments
+
+#ifdef CONFIG_EFI
+	call ap_start32_1
+ap_start32_1:
+	pop %edx
+	add $smp_stacktop - ap_start32_1, %edx
+#else
+	mov $smp_stacktop, %edx
+#endif
 	mov $-4096, %esp
-	lock xaddl %esp, smp_stacktop
+	lock xaddl %esp, (%edx)
+
 	setup_percpu_area
 	call prepare_64
-	ljmpl $8, $ap_start64
+
+#ifdef CONFIG_EFI
+	call ap_start32_2
+ap_start32_2:
+	pop %edx
+	add $ap_start64 - ap_start32_2, %edx
+#else
+	mov $ap_start64, %edx
+#endif
+
+	pushl $0x08
+	pushl %edx
+
+	lretl