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