mpboot.S revision 262748
1/*- 2 * Copyright (c) 2003 Peter Wemm 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD: head/sys/amd64/amd64/mpboot.S 262748 2014-03-04 20:07:36Z jkim $ 27 */ 28 29#include <machine/asmacros.h> /* miscellaneous asm macros */ 30#include <machine/specialreg.h> 31 32#include "assym.s" 33 34 .data /* So we can modify it */ 35 36 .p2align 4,0 37 .globl mptramp_start 38mptramp_start: 39#ifndef __clang__ 40 .code16 41 /* 42 * The AP enters here in response to the startup IPI. 43 * We are in real mode. %cs is the only segment register set. 44 */ 45 cli /* make sure no interrupts */ 46 mov %cs, %ax /* copy %cs to %ds. Remember these */ 47 mov %ax, %ds /* are offsets rather than selectors */ 48 mov %ax, %ss 49 50 /* 51 * Find relocation base and patch the gdt descript and ljmp targets 52 */ 53 xorl %ebx,%ebx 54 mov %cs, %bx 55 sall $4, %ebx /* %ebx is now our relocation base */ 56 orl %ebx, lgdt_desc-mptramp_start+2 57 orl %ebx, jmp_32-mptramp_start+2 58 orl %ebx, jmp_64-mptramp_start+1 59 60 /* 61 * Load the descriptor table pointer. We'll need it when running 62 * in 16 bit protected mode. 63 */ 64 lgdt lgdt_desc-mptramp_start 65 66 /* Enable protected mode */ 67 movl $CR0_PE, %eax 68 mov %eax, %cr0 69#else 70 /* 71 * The AP enters here in response to the startup IPI. 72 * We are in real mode. %cs is the only segment register set. 73 */ 74 cli /* make sure no interrupts */ 75 mov %cs, %eax /* copy %cs to %ds. Remember these */ 76 mov %eax, %ds /* are offsets rather than selectors */ 77 mov %eax, %ss 78 79 /* 80 * Find relocation base and patch the gdt descript and ljmp targets 81 */ 82 .byte 0x66 83 xorl %ebx, %ebx 84 mov %cs, %ebx 85 .byte 0x66 86 sall $4, %ebx /* %ebx is now our relocation base */ 87 .byte 0x66, 0x09, 0x1e 88 .word lgdt_desc-mptramp_start+2 89 .byte 0x66, 0x09, 0x1e 90 .word jmp_32-mptramp_start+2 91 .byte 0x66, 0x09, 0x1e 92 .word jmp_64-mptramp_start+1 93 94 /* 95 * Load the descriptor table pointer. We'll need it when running 96 * in 16 bit protected mode. 97 */ 98 .byte 0x0f, 0x01, 0x16 99 .word lgdt_desc-mptramp_start 100 101 /* Enable protected mode */ 102 .byte 0x66 103 movl $CR0_PE, %eax 104 mov %eax, %cr0 105#endif 106 107 /* 108 * Now execute a far jump to turn on protected mode. This 109 * causes the segment registers to turn into selectors and causes 110 * %cs to be loaded from the gdt. 111 * 112 * The following instruction is: 113 * ljmpl $bootcode-gdt, $protmode-mptramp_start 114 * but gas cannot assemble that. And besides, we patch the targets 115 * in early startup and its a little clearer what we are patching. 116 */ 117jmp_32: 118 .byte 0x66 /* size override to 32 bits */ 119 .byte 0xea /* opcode for far jump */ 120 .long protmode-mptramp_start /* offset in segment */ 121 .word bootcode-gdt /* index in gdt for 32 bit code */ 122 123 /* 124 * At this point, we are running in 32 bit legacy protected mode. 125 */ 126 .code32 127protmode: 128 mov $bootdata-gdt, %eax 129 mov %eax, %ds 130 131 /* Turn on the PAE, PSE and PGE bits for when paging is enabled */ 132 mov %cr4, %eax 133 orl $(CR4_PAE | CR4_PSE), %eax 134 mov %eax, %cr4 135 136 /* 137 * Enable EFER.LME so that we get long mode when all the prereqs are 138 * in place. In this case, it turns on when CR0_PG is finally enabled. 139 * Pick up a few other EFER bits that we'll use need we're here. 140 */ 141 movl $MSR_EFER, %ecx 142 rdmsr 143 orl $EFER_LME | EFER_SCE, %eax 144 wrmsr 145 146 /* 147 * Point to the embedded page tables for startup. Note that this 148 * only gets accessed after we're actually in 64 bit mode, however 149 * we can only set the bottom 32 bits of %cr3 in this state. This 150 * means we are required to use a temporary page table that is below 151 * the 4GB limit. %ebx is still our relocation base. We could just 152 * subtract 3 * PAGE_SIZE, but that would be too easy. 153 */ 154 leal mptramp_pagetables-mptramp_start(%ebx),%eax 155 movl (%eax), %eax 156 mov %eax, %cr3 157 158 /* 159 * Finally, switch to long bit mode by enabling paging. We have 160 * to be very careful here because all the segmentation disappears 161 * out from underneath us. The spec says we can depend on the 162 * subsequent pipelined branch to execute, but *only if* everthing 163 * is still identity mapped. If any mappings change, the pipeline 164 * will flush. 165 */ 166 mov %cr0, %eax 167 orl $CR0_PG, %eax 168 mov %eax, %cr0 169 170 /* 171 * At this point paging is enabled, and we are in "compatability" mode. 172 * We do another far jump to reload %cs with the 64 bit selector. 173 * %cr3 points to a 4-level page table page. 174 * We cannot yet jump all the way to the kernel because we can only 175 * specify a 32 bit linear address. So, yet another trampoline. 176 * 177 * The following instruction is: 178 * ljmp $kernelcode-gdt, $tramp_64-mptramp_start 179 * but gas cannot assemble that. And besides, we patch the targets 180 * in early startup and its a little clearer what we are patching. 181 */ 182jmp_64: 183 .byte 0xea /* opcode for far jump */ 184 .long tramp_64-mptramp_start /* offset in segment */ 185 .word kernelcode-gdt /* index in gdt for 64 bit code */ 186 187 /* 188 * Yeehar! We're running in 64 bit mode! We can mostly ignore our 189 * segment registers, and get on with it. 190 * Note that we are running at the correct virtual address, but with 191 * a 1:1 1GB mirrored mapping over entire address space. We had better 192 * switch to a real %cr3 promptly so that we can get to the direct map 193 * space. Remember that jmp is relative and that we've been relocated, 194 * so use an indirect jump. 195 */ 196 .code64 197tramp_64: 198 movabsq $entry_64,%rax /* 64 bit immediate load */ 199 jmp *%rax 200 201 .p2align 4,0 202gdt: 203 /* 204 * All segment descriptor tables start with a null descriptor 205 */ 206 .long 0x00000000 207 .long 0x00000000 208 209 /* 210 * This is the 64 bit long mode code descriptor. There is no 211 * 64 bit data descriptor. 212 */ 213kernelcode: 214 .long 0x00000000 215 .long 0x00209800 216 217 /* 218 * This is the descriptor for the 32 bit boot code. 219 * %cs: +A, +R, -C, DPL=0, +P, +D, +G 220 * Accessed, Readable, Present, 32 bit, 4G granularity 221 */ 222bootcode: 223 .long 0x0000ffff 224 .long 0x00cf9b00 225 226 /* 227 * This is the descriptor for the 32 bit boot data. 228 * We load it into %ds and %ss. The bits for each selector 229 * are interpreted slightly differently. 230 * %ds: +A, +W, -E, DPL=0, +P, +D, +G 231 * %ss: +A, +W, -E, DPL=0, +P, +B, +G 232 * Accessed, Writeable, Expand up, Present, 32 bit, 4GB 233 * For %ds, +D means 'default operand size is 32 bit'. 234 * For %ss, +B means the stack register is %esp rather than %sp. 235 */ 236bootdata: 237 .long 0x0000ffff 238 .long 0x00cf9300 239 240gdtend: 241 242 /* 243 * The address of our page table pages that the boot code 244 * uses to trampoline up to kernel address space. 245 */ 246 .globl mptramp_pagetables 247mptramp_pagetables: 248 .long 0 249 250 /* 251 * The pseudo descriptor for lgdt to use. 252 */ 253lgdt_desc: 254 .word gdtend-gdt /* Length */ 255 .long gdt-mptramp_start /* Offset plus %ds << 4 */ 256 257 .globl mptramp_end 258mptramp_end: 259 260 /* 261 * From here on down is executed in the kernel .text section. 262 * 263 * Load a real %cr3 that has all the direct map stuff and switches 264 * off the 1GB replicated mirror. Load a stack pointer and jump 265 * into AP startup code in C. 266 */ 267 .text 268 .code64 269 .p2align 4,0 270entry_64: 271 movq KPML4phys, %rax 272 movq %rax, %cr3 273 movq bootSTK, %rsp 274 jmp init_secondary 275