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