blob: 6a3df9c1a0aa7732165464e55085ebe4945d7276 [file] [log] [blame]
/*
* 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