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