2 * Copyright (c) 1995 Jack F. Vogel
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
26 * mpboot.s: FreeBSD machine support for the Intel MP Spec
27 * multiprocessor systems.
32 #include <machine/asmacros.h> /* miscellaneous asm macros */
33 #include <x86/apicreg.h>
34 #include <machine/specialreg.h>
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.
46 #if defined(CHECK_POINTS)
48 #define CMOS_REG (0x70)
49 #define CMOS_DATA (0x71)
51 #define CHECKPOINT(A,D) \
53 outb %al,$CMOS_REG ; \
59 #define CHECKPOINT(A,D)
61 #endif /* CHECK_POINTS */
65 * the APs enter here from their trampoline code (bootMP, below)
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
77 cpuid /* Retrieve features */
81 orl $CR4_PSE,%eax /* Enable PSE */
82 1: testl $CPUID_PGE,%edx
84 orl $CR4_PGE,%eax /* Enable PGE */
85 2: testl $CPUID_VME,%edx
87 orl $CR4_VME,%eax /* Enable VME */
90 /* Now enable paging mode */
98 movl $0x80000000, %eax
100 movl $0x80000001, %ebx
105 testl $AMDID_NX, %edx
112 4: movl IdlePTD_nopae, %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. */
119 pushl $mp_begin /* jump to high mem */
123 * Wait for the booting CPU to signal startup
125 mp_begin: /* now running relocated at KERNBASE */
127 call init_secondary /* load i386 tables */
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
139 ALIGN_DATA /* just to be sure */
147 /* First guarantee a 'clean slate' */
155 /* set up data segments */
162 mov $(boot_stk-bootMP), %esp
164 /* Now load the global descriptor table */
165 lgdt MP_GDTptr-bootMP
167 /* Enable protected mode */
173 * make intrasegment jump to flush the processor pipeline and
177 pushl $(protmode-bootMP)
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.
190 * SO NOW... for the BIG Jump into kernel's segment
191 * and physical text above 1 Meg.
202 /* this will be modified by mpInstallTramp() */
203 ljmp $0x08, $0 /* far jmp to MPentry() */
205 dead: hlt /* We should never get here */
209 * MP boot strap Global Descriptor Table
217 nulldesc: /* offset = 0x0 */
226 kernelcode: /* offset = 0x08 */
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 */
235 kerneldata: /* offset = 0x10 */
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 */
244 bootcode: /* offset = 0x18 */
246 .word 0xffff /* segment limit 0..15 */
247 bootCodeSeg: /* 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 */
254 bootdata: /* offset = 0x20 */
257 bootDataSeg: /* this will be modified by mpInstallTramp() */
258 .word 0x0000 /* segment base 0..15 */
259 .byte 0x00 /* segment base 16...23; set for 0x000xx000 */
265 * GDT pointer for the lgdt call
272 mp_gdtbase: /* this will be modified by mpInstallTramp() */
275 .space 0x100 /* space for boot_stk - 1st temporary stack */
281 .long BOOTMP2 - BOOTMP1