@@ -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;
}
@@ -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);
@@ -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
@@ -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. 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(-)