FreeBSD/Linux Kernel Cross Reference
sys/i386/i386/mpboot.s
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
71 NON_GPROF_ENTRY(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 */
84 1:
85 testl $CPUID_PGE,%edx
86 jz 1f
87 orl $CR4_PGE,%eax /* Enable PGE */
88 1:
89 testl $CPUID_VME,%edx
90 jz 1f
91 orl $CR4_VME,%eax /* Enable VME */
92 1:
93 movl %eax,%cr4
94
95 /* Now enable paging mode */
96 #if defined(PAE) || defined(PAE_TABLES)
97 movl IdlePDPT, %eax
98 movl %eax, %cr3
99 movl %cr4, %eax
100 orl $CR4_PAE, %eax
101 movl %eax, %cr4
102 movl $0x80000000, %eax
103 cpuid
104 movl $0x80000001, %ebx
105 cmpl %ebx, %eax
106 jb 1f
107 movl %ebx, %eax
108 cpuid
109 testl $AMDID_NX, %edx
110 je 1f
111 movl $MSR_EFER, %ecx
112 rdmsr
113 orl $EFER_NXE,%eax
114 wrmsr
115 1:
116 #else
117 movl IdlePTD, %eax
118 movl %eax,%cr3
119 #endif
120 movl %cr0,%eax
121 orl $CR0_PE|CR0_PG,%eax /* enable paging */
122 movl %eax,%cr0 /* let the games begin! */
123 movl bootSTK,%esp /* boot stack end loc. */
124
125 pushl $mp_begin /* jump to high mem */
126 ret
127
128 /*
129 * Wait for the booting CPU to signal startup
130 */
131 mp_begin: /* now running relocated at KERNBASE */
132 CHECKPOINT(0x37, 4)
133 call init_secondary /* load i386 tables */
134
135 /*
136 * This is the embedded trampoline or bootstrap that is
137 * copied into 'real-mode' low memory, it is where the
138 * secondary processor "wakes up". When it is executed
139 * the processor will eventually jump into the routine
140 * MPentry, which resides in normal kernel text above
141 * 1Meg. -jackv
142 */
143
144 .data
145 ALIGN_DATA /* just to be sure */
146
147 BOOTMP1:
148
149 NON_GPROF_ENTRY(bootMP)
150 .code16
151 cli
152 CHECKPOINT(0x34, 1)
153 /* First guarantee a 'clean slate' */
154 xorl %eax, %eax
155 movl %eax, %ebx
156 movl %eax, %ecx
157 movl %eax, %edx
158 movl %eax, %esi
159 movl %eax, %edi
160
161 /* set up data segments */
162 mov %cs, %ax
163 mov %ax, %ds
164 mov %ax, %es
165 mov %ax, %fs
166 mov %ax, %gs
167 mov %ax, %ss
168 mov $(boot_stk-bootMP), %esp
169
170 /* Now load the global descriptor table */
171 lgdt MP_GDTptr-bootMP
172
173 /* Enable protected mode */
174 movl %cr0, %eax
175 orl $CR0_PE, %eax
176 movl %eax, %cr0
177
178 /*
179 * make intrasegment jump to flush the processor pipeline and
180 * reload CS register
181 */
182 pushl $0x18
183 pushl $(protmode-bootMP)
184 lretl
185
186 .code32
187 protmode:
188 CHECKPOINT(0x35, 2)
189
190 /*
191 * we are NOW running for the first time with %eip
192 * having the full physical address, BUT we still
193 * are using a segment descriptor with the origin
194 * not matching the booting kernel.
195 *
196 * SO NOW... for the BIG Jump into kernel's segment
197 * and physical text above 1 Meg.
198 */
199 mov $0x10, %ebx
200 movw %bx, %ds
201 movw %bx, %es
202 movw %bx, %fs
203 movw %bx, %gs
204 movw %bx, %ss
205
206 .globl bigJump
207 bigJump:
208 /* this will be modified by mpInstallTramp() */
209 ljmp $0x08, $0 /* far jmp to MPentry() */
210
211 dead: hlt /* We should never get here */
212 jmp dead
213
214 /*
215 * MP boot strap Global Descriptor Table
216 */
217 .p2align 4
218 .globl MP_GDT
219 .globl bootCodeSeg
220 .globl bootDataSeg
221 MP_GDT:
222
223 nulldesc: /* offset = 0x0 */
224
225 .word 0x0
226 .word 0x0
227 .byte 0x0
228 .byte 0x0
229 .byte 0x0
230 .byte 0x0
231
232 kernelcode: /* offset = 0x08 */
233
234 .word 0xffff /* segment limit 0..15 */
235 .word 0x0000 /* segment base 0..15 */
236 .byte 0x0 /* segment base 16..23; set for 0K */
237 .byte 0x9f /* flags; Type */
238 .byte 0xcf /* flags; Limit */
239 .byte 0x0 /* segment base 24..32 */
240
241 kerneldata: /* offset = 0x10 */
242
243 .word 0xffff /* segment limit 0..15 */
244 .word 0x0000 /* segment base 0..15 */
245 .byte 0x0 /* segment base 16..23; set for 0k */
246 .byte 0x93 /* flags; Type */
247 .byte 0xcf /* flags; Limit */
248 .byte 0x0 /* segment base 24..32 */
249
250 bootcode: /* offset = 0x18 */
251
252 .word 0xffff /* segment limit 0..15 */
253 bootCodeSeg: /* this will be modified by mpInstallTramp() */
254 .word 0x0000 /* segment base 0..15 */
255 .byte 0x00 /* segment base 16...23; set for 0x000xx000 */
256 .byte 0x9e /* flags; Type */
257 .byte 0xcf /* flags; Limit */
258 .byte 0x0 /*segment base 24..32 */
259
260 bootdata: /* offset = 0x20 */
261
262 .word 0xffff
263 bootDataSeg: /* this will be modified by mpInstallTramp() */
264 .word 0x0000 /* segment base 0..15 */
265 .byte 0x00 /* segment base 16...23; set for 0x000xx000 */
266 .byte 0x92
267 .byte 0xcf
268 .byte 0x0
269
270 /*
271 * GDT pointer for the lgdt call
272 */
273 .globl mp_gdtbase
274
275 MP_GDTptr:
276 mp_gdtlimit:
277 .word 0x0028
278 mp_gdtbase: /* this will be modified by mpInstallTramp() */
279 .long 0
280
281 .space 0x100 /* space for boot_stk - 1st temporary stack */
282 boot_stk:
283
284 BOOTMP2:
285 .globl bootMP_size
286 bootMP_size:
287 .long BOOTMP2 - BOOTMP1
Cache object: 181ac6ff852c89d16552f6491035701d
|