1250661Sdavidcs/*- 2250661Sdavidcs * Copyright (c) 1995 Jack F. Vogel 3250661Sdavidcs * All rights reserved. 4250661Sdavidcs * 5250661Sdavidcs * Redistribution and use in source and binary forms, with or without 6250661Sdavidcs * modification, are permitted provided that the following conditions 7250661Sdavidcs * are met: 8250661Sdavidcs * 1. Redistributions of source code must retain the above copyright 9250661Sdavidcs * notice, this list of conditions and the following disclaimer. 10250661Sdavidcs * 2. Redistributions in binary form must reproduce the above copyright 11250661Sdavidcs * notice, this list of conditions and the following disclaimer in the 12250661Sdavidcs * documentation and/or other materials provided with the distribution. 13250661Sdavidcs * 14250661Sdavidcs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15250661Sdavidcs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16250661Sdavidcs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17250661Sdavidcs * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 18250661Sdavidcs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19250661Sdavidcs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20250661Sdavidcs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21250661Sdavidcs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22250661Sdavidcs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23250661Sdavidcs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24250661Sdavidcs * SUCH DAMAGE. 25250661Sdavidcs * 26250661Sdavidcs * mpboot.s: FreeBSD machine support for the Intel MP Spec 27250661Sdavidcs * multiprocessor systems. 28250661Sdavidcs */ 29250661Sdavidcs 30250661Sdavidcs#include "opt_pmap.h" 31250661Sdavidcs 32250661Sdavidcs#include <machine/asmacros.h> /* miscellaneous asm macros */ 33250661Sdavidcs#include <x86/apicreg.h> 34250661Sdavidcs#include <machine/specialreg.h> 35250661Sdavidcs 36250661Sdavidcs#include "assym.inc" 37250661Sdavidcs 38250661Sdavidcs/* 39250661Sdavidcs * this code MUST be enabled here and in mp_machdep.c 40250661Sdavidcs * it follows the very early stages of AP boot by placing values in CMOS ram. 41250661Sdavidcs * it NORMALLY will never be needed and thus the primitive method for enabling. 42250661Sdavidcs * 43250661Sdavidcs#define CHECK_POINTS 44250661Sdavidcs */ 45250661Sdavidcs 46250661Sdavidcs#if defined(CHECK_POINTS) 47250661Sdavidcs 48250661Sdavidcs#define CMOS_REG (0x70) 49250661Sdavidcs#define CMOS_DATA (0x71) 50250661Sdavidcs 51250661Sdavidcs#define CHECKPOINT(A,D) \ 52250661Sdavidcs movb $(A),%al ; \ 53250661Sdavidcs outb %al,$CMOS_REG ; \ 54250661Sdavidcs movb $(D),%al ; \ 55250661Sdavidcs outb %al,$CMOS_DATA 56250661Sdavidcs 57250661Sdavidcs#else 58250661Sdavidcs 59250661Sdavidcs#define CHECKPOINT(A,D) 60250661Sdavidcs 61250661Sdavidcs#endif /* CHECK_POINTS */ 62250661Sdavidcs 63250661Sdavidcs 64250661Sdavidcs/* 65250661Sdavidcs * the APs enter here from their trampoline code (bootMP, below) 66250661Sdavidcs */ 67250661Sdavidcs .p2align 4 68250661Sdavidcs 69250661SdavidcsENTRY(MPentry) 70250661Sdavidcs CHECKPOINT(0x36, 3) 71250661Sdavidcs /* 72250661Sdavidcs * Enable features on this processor. We don't support SMP on 73250661Sdavidcs * CPUs older than a Pentium, so we know that we can use the cpuid 74250661Sdavidcs * instruction. 75250661Sdavidcs */ 76250661Sdavidcs movl $1,%eax 77250661Sdavidcs cpuid /* Retrieve features */ 78250661Sdavidcs movl %cr4,%eax 79250661Sdavidcs testl $CPUID_PSE,%edx 80250661Sdavidcs jz 1f 81250661Sdavidcs orl $CR4_PSE,%eax /* Enable PSE */ 82250661Sdavidcs1: testl $CPUID_PGE,%edx 83250661Sdavidcs jz 2f 84250661Sdavidcs orl $CR4_PGE,%eax /* Enable PGE */ 85250661Sdavidcs2: testl $CPUID_VME,%edx 86250661Sdavidcs jz 3f 87250661Sdavidcs orl $CR4_VME,%eax /* Enable VME */ 88250661Sdavidcs3: movl %eax,%cr4 89250661Sdavidcs 90250661Sdavidcs /* Now enable paging mode */ 91250661Sdavidcs cmpl $0, pae_mode 92250661Sdavidcs je 4f 93250661Sdavidcs movl IdlePDPT, %eax 94250661Sdavidcs movl %eax, %cr3 95250661Sdavidcs movl %cr4, %eax 96250661Sdavidcs orl $CR4_PAE, %eax 97250661Sdavidcs movl %eax, %cr4 98250661Sdavidcs movl $0x80000000, %eax 99250661Sdavidcs cpuid 100250661Sdavidcs movl $0x80000001, %ebx 101250661Sdavidcs cmpl %ebx, %eax 102250661Sdavidcs jb 5f 103250661Sdavidcs movl %ebx, %eax 104250661Sdavidcs cpuid 105250661Sdavidcs testl $AMDID_NX, %edx 106250661Sdavidcs je 5f 107250661Sdavidcs movl $MSR_EFER, %ecx 108250661Sdavidcs rdmsr 109250661Sdavidcs orl $EFER_NXE,%eax 110250661Sdavidcs wrmsr 111250661Sdavidcs jmp 5f 112250661Sdavidcs4: movl IdlePTD_nopae, %eax 113250661Sdavidcs movl %eax,%cr3 114250661Sdavidcs5: movl %cr0,%eax 115250661Sdavidcs orl $CR0_PE|CR0_PG,%eax /* enable paging */ 116250661Sdavidcs movl %eax,%cr0 /* let the games begin! */ 117250661Sdavidcs movl bootSTK,%esp /* boot stack end loc. */ 118250661Sdavidcs 119250661Sdavidcs pushl $mp_begin /* jump to high mem */ 120250661Sdavidcs ret 121250661Sdavidcs 122250661Sdavidcs /* 123250661Sdavidcs * Wait for the booting CPU to signal startup 124250661Sdavidcs */ 125250661Sdavidcsmp_begin: /* now running relocated at KERNBASE */ 126250661Sdavidcs CHECKPOINT(0x37, 4) 127250661Sdavidcs call init_secondary /* load i386 tables */ 128250661Sdavidcs 129250661Sdavidcs/* 130250661Sdavidcs * This is the embedded trampoline or bootstrap that is 131250661Sdavidcs * copied into 'real-mode' low memory, it is where the 132250661Sdavidcs * secondary processor "wakes up". When it is executed 133250661Sdavidcs * the processor will eventually jump into the routine 134250661Sdavidcs * MPentry, which resides in normal kernel text above 135250661Sdavidcs * 1Meg. -jackv 136250661Sdavidcs */ 137250661Sdavidcs 138250661Sdavidcs .data 139250661Sdavidcs ALIGN_DATA /* just to be sure */ 140250661Sdavidcs 141250661SdavidcsBOOTMP1: 142250661Sdavidcs 143250661SdavidcsENTRY(bootMP) 144250661Sdavidcs .code16 145250661Sdavidcs cli 146250661Sdavidcs CHECKPOINT(0x34, 1) 147250661Sdavidcs /* First guarantee a 'clean slate' */ 148250661Sdavidcs xorl %eax, %eax 149250661Sdavidcs movl %eax, %ebx 150250661Sdavidcs movl %eax, %ecx 151250661Sdavidcs movl %eax, %edx 152250661Sdavidcs movl %eax, %esi 153250661Sdavidcs movl %eax, %edi 154250661Sdavidcs 155250661Sdavidcs /* set up data segments */ 156250661Sdavidcs mov %cs, %ax 157250661Sdavidcs mov %ax, %ds 158250661Sdavidcs mov %ax, %es 159250661Sdavidcs mov %ax, %fs 160250661Sdavidcs mov %ax, %gs 161250661Sdavidcs mov %ax, %ss 162250661Sdavidcs mov $(boot_stk-bootMP), %esp 163250661Sdavidcs 164250661Sdavidcs /* Now load the global descriptor table */ 165250661Sdavidcs lgdt MP_GDTptr-bootMP 166250661Sdavidcs 167250661Sdavidcs /* Enable protected mode */ 168250661Sdavidcs movl %cr0, %eax 169250661Sdavidcs orl $CR0_PE, %eax 170250661Sdavidcs movl %eax, %cr0 171250661Sdavidcs 172250661Sdavidcs /* 173250661Sdavidcs * make intrasegment jump to flush the processor pipeline and 174250661Sdavidcs * reload CS register 175250661Sdavidcs */ 176250661Sdavidcs pushl $0x18 177250661Sdavidcs pushl $(protmode-bootMP) 178250661Sdavidcs lretl 179250661Sdavidcs 180250661Sdavidcs .code32 181250661Sdavidcsprotmode: 182250661Sdavidcs CHECKPOINT(0x35, 2) 183250661Sdavidcs 184250661Sdavidcs /* 185250661Sdavidcs * we are NOW running for the first time with %eip 186250661Sdavidcs * having the full physical address, BUT we still 187250661Sdavidcs * are using a segment descriptor with the origin 188250661Sdavidcs * not matching the booting kernel. 189250661Sdavidcs * 190250661Sdavidcs * SO NOW... for the BIG Jump into kernel's segment 191250661Sdavidcs * and physical text above 1 Meg. 192250661Sdavidcs */ 193250661Sdavidcs mov $0x10, %ebx 194250661Sdavidcs movw %bx, %ds 195250661Sdavidcs movw %bx, %es 196250661Sdavidcs movw %bx, %fs 197250661Sdavidcs movw %bx, %gs 198250661Sdavidcs movw %bx, %ss 199250661Sdavidcs 200250661Sdavidcs .globl bigJump 201250661SdavidcsbigJump: 202250661Sdavidcs /* this will be modified by mpInstallTramp() */ 203250661Sdavidcs ljmp $0x08, $0 /* far jmp to MPentry() */ 204250661Sdavidcs 205250661Sdavidcsdead: hlt /* We should never get here */ 206250661Sdavidcs jmp dead 207250661Sdavidcs 208250661Sdavidcs/* 209250661Sdavidcs * MP boot strap Global Descriptor Table 210250661Sdavidcs */ 211250661Sdavidcs .p2align 4 212250661Sdavidcs .globl MP_GDT 213250661Sdavidcs .globl bootCodeSeg 214250661Sdavidcs .globl bootDataSeg 215250661SdavidcsMP_GDT: 216250661Sdavidcs 217250661Sdavidcsnulldesc: /* offset = 0x0 */ 218250661Sdavidcs 219250661Sdavidcs .word 0x0 220250661Sdavidcs .word 0x0 221250661Sdavidcs .byte 0x0 222250661Sdavidcs .byte 0x0 223250661Sdavidcs .byte 0x0 224250661Sdavidcs .byte 0x0 225250661Sdavidcs 226250661Sdavidcskernelcode: /* offset = 0x08 */ 227250661Sdavidcs 228250661Sdavidcs .word 0xffff /* segment limit 0..15 */ 229250661Sdavidcs .word 0x0000 /* segment base 0..15 */ 230250661Sdavidcs .byte 0x0 /* segment base 16..23; set for 0K */ 231250661Sdavidcs .byte 0x9f /* flags; Type */ 232250661Sdavidcs .byte 0xcf /* flags; Limit */ 233250661Sdavidcs .byte 0x0 /* segment base 24..32 */ 234250661Sdavidcs 235250661Sdavidcskerneldata: /* offset = 0x10 */ 236250661Sdavidcs 237250661Sdavidcs .word 0xffff /* segment limit 0..15 */ 238250661Sdavidcs .word 0x0000 /* segment base 0..15 */ 239250661Sdavidcs .byte 0x0 /* segment base 16..23; set for 0k */ 240250661Sdavidcs .byte 0x93 /* flags; Type */ 241250661Sdavidcs .byte 0xcf /* flags; Limit */ 242250661Sdavidcs .byte 0x0 /* segment base 24..32 */ 243250661Sdavidcs 244250661Sdavidcsbootcode: /* offset = 0x18 */ 245250661Sdavidcs 246250661Sdavidcs .word 0xffff /* segment limit 0..15 */ 247250661SdavidcsbootCodeSeg: /* this will be modified by mpInstallTramp() */ 248250661Sdavidcs .word 0x0000 /* segment base 0..15 */ 249250661Sdavidcs .byte 0x00 /* segment base 16...23; set for 0x000xx000 */ 250250661Sdavidcs .byte 0x9e /* flags; Type */ 251250661Sdavidcs .byte 0xcf /* flags; Limit */ 252250661Sdavidcs .byte 0x0 /*segment base 24..32 */ 253250661Sdavidcs 254250661Sdavidcsbootdata: /* offset = 0x20 */ 255250661Sdavidcs 256250661Sdavidcs .word 0xffff 257250661SdavidcsbootDataSeg: /* this will be modified by mpInstallTramp() */ 258250661Sdavidcs .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