@@ -321,11 +321,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;
}
@@ -152,6 +152,8 @@ void smp_reset_apic(void)
#ifdef CONFIG_EFI
extern u8 gdt32_descr, gdt32, gdt32_end;
extern u8 ap_start32;
+extern u32 smp_stacktop;
+extern u8 stacktop;
#endif
void ap_init(void)
@@ -172,6 +174,8 @@ void ap_init(void)
idt_entry_t *gate_descr;
u16 *gdt32_descr_reladdr = (u16 *) (PAGE_SIZE - sizeof(u16));
+ smp_stacktop = ((u64) (&stacktop)) - 4096;
+
/*
* gdt32_descr for CONFIG_EFI needs to be filled here dynamically
* since compile time calculation of offsets is not allowed when
@@ -58,6 +58,9 @@ _start:
popq %rdi
popq %rsi
+ /* Switch away from EFI stack. */
+ lea stacktop(%rip), %rsp
+
call efi_main
addq $8, %rsp
@@ -6,6 +6,17 @@
.data
+max_cpus = MAX_TEST_CPUS
+
+/* Reserve stack in .data */
+ . = . + 4096 * max_cpus
+ .align 16
+.globl stacktop
+stacktop:
+
+.globl smp_stacktop
+smp_stacktop: .long 0
+
.align PAGE_SIZE
.globl ptl2
ptl2:
@@ -85,6 +96,10 @@ gdt32_descr:
sipi_end:
.code32
-.globl ap_start32
-ap_start32:
- jmp ap_start32
+
+#include "../start32.S"
+
+.code64:
+
+ap_start64:
+ jmp ap_start64
@@ -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
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. Signed-off-by: Varad Gautam <varad.gautam@suse.com> --- lib/x86/setup.c | 2 +- lib/x86/smp.c | 4 ++++ x86/efi/crt0-efi-x86_64.S | 3 +++ x86/efi/efistart64.S | 21 +++++++++++++++--- x86/start32.S | 46 ++++++++++++++++++++++++++++++++++++--- 5 files changed, 69 insertions(+), 7 deletions(-)