1/* 2 * Common bootstrapping code to transition from 16-bit to 32-bit code, and to 3 * transition from 32-bit to 64-bit code (x86-64 only) 4 */ 5 6 /* EFI provides it's own SIPI sequence to handle relocation. */ 7#ifndef CONFIG_EFI 8.code16 9.globl rm_trampoline 10rm_trampoline: 11 12/* Store SIPI vector code at the beginning of trampoline. */ 13sipi_entry: 14 mov %cr0, %eax 15 or $1, %eax 16 mov %eax, %cr0 17 lgdtl ap_rm_gdt_descr - sipi_entry 18 ljmpl $8, $ap_start32 19sipi_end: 20 21.globl ap_rm_gdt_descr 22ap_rm_gdt_descr: 23#ifdef __i386__ 24 .word 0 25 .long 0 26#else 27 .word gdt32_end - gdt32 - 1 28 .long gdt32 29#endif 30 31.globl rm_trampoline_end 32rm_trampoline_end: 33#endif 34 35/* The 32-bit => 64-bit trampoline is x86-64 only. */ 36#ifdef __x86_64__ 37.code32 38 39/* 40 * EFI builds with "-shared -fPIC" and so cannot directly reference any absolute 41 * address. In 64-bit mode, RIP-relative addressing neatly solves the problem, 42 * but 32-bit code doesn't have that luxury. Make a dummy CALL to get RIP into 43 * a GPR in order to emulate RIP-relative for 32-bit transition code. 44 */ 45.macro load_absolute_addr, addr, reg 46#ifdef CONFIG_EFI 47 call 1f 481: 49 pop \reg 50 add \addr - 1b, \reg 51#else 52 mov \addr, \reg 53#endif 54.endm 55 56MSR_GS_BASE = 0xc0000101 57 58.macro setup_percpu_area 59 lea -4096(%esp), %eax 60 mov $0, %edx 61 mov $MSR_GS_BASE, %ecx 62 wrmsr 63.endm 64 65.macro setup_segments 66 mov $MSR_GS_BASE, %ecx 67 rdmsr 68 69 mov $0x10, %bx 70 mov %bx, %ds 71 mov %bx, %es 72 mov %bx, %fs 73 mov %bx, %gs 74 mov %bx, %ss 75 76 /* restore MSR_GS_BASE */ 77 wrmsr 78.endm 79 80prepare_64: 81 load_absolute_addr $gdt_descr, %edx 82 lgdtl (%edx) 83 84 setup_segments 85 86 xor %eax, %eax 87 mov %eax, %cr4 88 89enter_long_mode: 90 mov %cr4, %eax 91 bts $5, %eax // pae 92 mov %eax, %cr4 93 94 /* Note, EFI doesn't yet support 5-level paging. */ 95#ifdef CONFIG_EFI 96 load_absolute_addr $ptl4, %eax 97#else 98 mov pt_root, %eax 99#endif 100 mov %eax, %cr3 101 102efer = 0xc0000080 103 mov $efer, %ecx 104 rdmsr 105 bts $8, %eax 106 wrmsr 107 108 mov %cr0, %eax 109 bts $0, %eax 110 bts $31, %eax 111 mov %eax, %cr0 112 ret 113 114.globl ap_start32 115ap_start32: 116 setup_segments 117 118 load_absolute_addr $smp_stacktop, %edx 119 mov $-4096, %esp 120 lock xaddl %esp, (%edx) 121 122 setup_percpu_area 123 call prepare_64 124 125 load_absolute_addr $ap_start64, %edx 126 pushl $0x08 127 pushl %edx 128 lretl 129#endif 130