1/*- 2 * Copyright (c) 1995 Jack F. Vogel 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 REGENTS 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 * mpboot.s: FreeBSD machine support for the Intel MP Spec 27 * multiprocessor systems. 28 */ 29 30#include "opt_pmap.h" 31 32#include <machine/asmacros.h> /* miscellaneous asm macros */ 33#include <x86/apicreg.h> 34#include <machine/specialreg.h> 35 36#include "assym.inc" 37 38/* 39 * this code MUST be enabled here and in mp_machdep.c 40 * it follows the very early stages of AP boot by placing values in CMOS ram. 41 * it NORMALLY will never be needed and thus the primitive method for enabling. 42 * 43#define CHECK_POINTS 44 */ 45 46#if defined(CHECK_POINTS) 47 48#define CMOS_REG (0x70) 49#define CMOS_DATA (0x71) 50 51#define CHECKPOINT(A,D) \ 52 movb $(A),%al ; \ 53 outb %al,$CMOS_REG ; \ 54 movb $(D),%al ; \ 55 outb %al,$CMOS_DATA 56 57#else 58 59#define CHECKPOINT(A,D) 60 61#endif /* CHECK_POINTS */ 62 63 64/* 65 * the APs enter here from their trampoline code (bootMP, below) 66 */ 67 .p2align 4 68 69ENTRY(MPentry) 70 CHECKPOINT(0x36, 3) 71 /* 72 * Enable features on this processor. We don't support SMP on 73 * CPUs older than a Pentium, so we know that we can use the cpuid 74 * instruction. 75 */ 76 movl $1,%eax 77 cpuid /* Retrieve features */ 78 movl %cr4,%eax 79 testl $CPUID_PSE,%edx 80 jz 1f 81 orl $CR4_PSE,%eax /* Enable PSE */ 821: testl $CPUID_PGE,%edx 83 jz 2f 84 orl $CR4_PGE,%eax /* Enable PGE */ 852: testl $CPUID_VME,%edx 86 jz 3f 87 orl $CR4_VME,%eax /* Enable VME */ 883: movl %eax,%cr4 89 90 /* Now enable paging mode */ 91 cmpl $0, pae_mode 92 je 4f 93 movl IdlePDPT, %eax 94 movl %eax, %cr3 95 movl %cr4, %eax 96 orl $CR4_PAE, %eax 97 movl %eax, %cr4 98 movl $0x80000000, %eax 99 cpuid 100 movl $0x80000001, %ebx 101 cmpl %ebx, %eax 102 jb 5f 103 movl %ebx, %eax 104 cpuid 105 testl $AMDID_NX, %edx 106 je 5f 107 movl $MSR_EFER, %ecx 108 rdmsr 109 orl $EFER_NXE,%eax 110 wrmsr 111 jmp 5f 1124: movl IdlePTD_nopae, %eax 113 movl %eax,%cr3 1145: movl %cr0,%eax 115 orl $CR0_PE|CR0_PG,%eax /* enable paging */ 116 movl %eax,%cr0 /* let the games begin! */ 117 movl bootSTK,%esp /* boot stack end loc. */ 118 119 pushl $mp_begin /* jump to high mem */ 120 ret 121 122 /* 123 * Wait for the booting CPU to signal startup 124 */ 125mp_begin: /* now running relocated at KERNBASE */ 126 CHECKPOINT(0x37, 4) 127 call init_secondary /* load i386 tables */ 128 129/* 130 * This is the embedded trampoline or bootstrap that is 131 * copied into 'real-mode' low memory, it is where the 132 * secondary processor "wakes up". When it is executed 133 * the processor will eventually jump into the routine 134 * MPentry, which resides in normal kernel text above 135 * 1Meg. -jackv 136 */ 137 138 .data 139 ALIGN_DATA /* just to be sure */ 140 141BOOTMP1: 142 143ENTRY(bootMP) 144 .code16 145 cli 146 CHECKPOINT(0x34, 1) 147 /* First guarantee a 'clean slate' */ 148 xorl %eax, %eax 149 movl %eax, %ebx 150 movl %eax, %ecx 151 movl %eax, %edx 152 movl %eax, %esi 153 movl %eax, %edi 154 155 /* set up data segments */ 156 mov %cs, %ax 157 mov %ax, %ds 158 mov %ax, %es 159 mov %ax, %fs 160 mov %ax, %gs 161 mov %ax, %ss 162 mov $(boot_stk-bootMP), %esp 163 164 /* Now load the global descriptor table */ 165 lgdt MP_GDTptr-bootMP 166 167 /* Enable protected mode */ 168 movl %cr0, %eax 169 orl $CR0_PE, %eax 170 movl %eax, %cr0 171 172 /* 173 * make intrasegment jump to flush the processor pipeline and 174 * reload CS register 175 */ 176 pushl $0x18 177 pushl $(protmode-bootMP) 178 lretl 179 180 .code32 181protmode: 182 CHECKPOINT(0x35, 2) 183 184 /* 185 * we are NOW running for the first time with %eip 186 * having the full physical address, BUT we still 187 * are using a segment descriptor with the origin 188 * not matching the booting kernel. 189 * 190 * SO NOW... for the BIG Jump into kernel's segment 191 * and physical text above 1 Meg. 192 */ 193 mov $0x10, %ebx 194 movw %bx, %ds 195 movw %bx, %es 196 movw %bx, %fs 197 movw %bx, %gs 198 movw %bx, %ss 199 200 .globl bigJump 201bigJump: 202 /* this will be modified by mpInstallTramp() */ 203 ljmp $0x08, $0 /* far jmp to MPentry() */ 204 205dead: hlt /* We should never get here */ 206 jmp dead 207 208/* 209 * MP boot strap Global Descriptor Table 210 */ 211 .p2align 4 212 .globl MP_GDT 213 .globl bootCodeSeg 214 .globl bootDataSeg 215MP_GDT: 216 217nulldesc: /* offset = 0x0 */ 218 219 .word 0x0 220 .word 0x0 221 .byte 0x0 222 .byte 0x0 223 .byte 0x0 224 .byte 0x0 225 226kernelcode: /* offset = 0x08 */ 227 228 .word 0xffff /* segment limit 0..15 */ 229 .word 0x0000 /* segment base 0..15 */ 230 .byte 0x0 /* segment base 16..23; set for 0K */ 231 .byte 0x9f /* flags; Type */ 232 .byte 0xcf /* flags; Limit */ 233 .byte 0x0 /* segment base 24..32 */ 234 235kerneldata: /* offset = 0x10 */ 236 237 .word 0xffff /* segment limit 0..15 */ 238 .word 0x0000 /* segment base 0..15 */ 239 .byte 0x0 /* segment base 16..23; set for 0k */ 240 .byte 0x93 /* flags; Type */ 241 .byte 0xcf /* flags; Limit */ 242 .byte 0x0 /* segment base 24..32 */ 243 244bootcode: /* offset = 0x18 */ 245 246 .word 0xffff /* segment limit 0..15 */ 247bootCodeSeg: /* this will be modified by mpInstallTramp() */ 248 .word 0x0000 /* segment base 0..15 */ 249 .byte 0x00 /* segment base 16...23; set for 0x000xx000 */ 250 .byte 0x9e /* flags; Type */ 251 .byte 0xcf /* flags; Limit */ 252 .byte 0x0 /*segment base 24..32 */ 253 254bootdata: /* offset = 0x20 */ 255 256 .word 0xffff 257bootDataSeg: /* this will be modified by mpInstallTramp() */ 258 .word 0x0000 /* segment base 0..15 */ 259 .byte 0x00 /* segment base 16...23; set for 0x000xx000 */ 260 .byte 0x92 261 .byte 0xcf 262 .byte 0x0 263 264/* 265 * GDT pointer for the lgdt call 266 */ 267 .globl mp_gdtbase 268 269MP_GDTptr: 270mp_gdtlimit: 271 .word 0x0028 272mp_gdtbase: /* this will be modified by mpInstallTramp() */ 273 .long 0 274 275 .space 0x100 /* space for boot_stk - 1st temporary stack */ 276boot_stk: 277 278BOOTMP2: 279 .globl bootMP_size 280bootMP_size: 281 .long BOOTMP2 - BOOTMP1 282