/* * Common bootstrapping code to transition from 16-bit to 32-bit code, and to * transition from 32-bit to 64-bit code (x86-64 only) */ /* EFI provides it's own SIPI sequence to handle relocation. */ #ifndef CONFIG_EFI .code16 .globl rm_trampoline rm_trampoline: /* Store SIPI vector code at the beginning of trampoline. */ sipi_entry: mov %cr0, %eax or $1, %eax mov %eax, %cr0 lgdtl ap_rm_gdt_descr - sipi_entry ljmpl $8, $ap_start32 sipi_end: .globl ap_rm_gdt_descr ap_rm_gdt_descr: #ifdef __i386__ .word 0 .long 0 #else .word gdt32_end - gdt32 - 1 .long gdt32 #endif .globl rm_trampoline_end rm_trampoline_end: #endif /* The 32-bit => 64-bit trampoline is x86-64 only. */ #ifdef __x86_64__ .code32 /* * EFI builds with "-shared -fPIC" and so cannot directly reference any absolute * address. In 64-bit mode, RIP-relative addressing neatly solves the problem, * but 32-bit code doesn't have that luxury. Make a dummy CALL to get RIP into * a GPR in order to emulate RIP-relative for 32-bit transition code. */ .macro load_absolute_addr, addr, reg #ifdef CONFIG_EFI call 1f 1: pop \reg add \addr - 1b, \reg #else mov \addr, \reg #endif .endm MSR_GS_BASE = 0xc0000101 .macro setup_percpu_area lea -4096(%esp), %eax mov $0, %edx mov $MSR_GS_BASE, %ecx wrmsr .endm .macro setup_segments mov $MSR_GS_BASE, %ecx rdmsr mov $0x10, %bx mov %bx, %ds mov %bx, %es mov %bx, %fs mov %bx, %gs mov %bx, %ss /* restore MSR_GS_BASE */ wrmsr .endm prepare_64: load_absolute_addr $gdt_descr, %edx lgdtl (%edx) setup_segments xor %eax, %eax mov %eax, %cr4 enter_long_mode: mov %cr4, %eax bts $5, %eax // pae mov %eax, %cr4 /* Note, EFI doesn't yet support 5-level paging. */ #ifdef CONFIG_EFI load_absolute_addr $ptl4, %eax #else mov pt_root, %eax #endif mov %eax, %cr3 efer = 0xc0000080 mov $efer, %ecx rdmsr bts $8, %eax wrmsr mov %cr0, %eax bts $0, %eax bts $31, %eax mov %eax, %cr0 ret .globl ap_start32 ap_start32: setup_segments load_absolute_addr $smp_stacktop, %edx mov $-4096, %esp lock xaddl %esp, (%edx) setup_percpu_area call prepare_64 load_absolute_addr $ap_start64, %edx pushl $0x08 pushl %edx lretl #endif