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