mpboot.S revision 46129
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 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by Jack F. Vogel
16 * 4. The name of the developer may be used to endorse or promote products
17 *    derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 * mpboot.s:	FreeBSD machine support for the Intel MP Spec
32 *		multiprocessor systems.
33 *
34 *	$Id: mpboot.s,v 1.9 1999/04/10 22:58:29 tegge Exp $
35 */
36
37#include "opt_vm86.h"
38
39#include <machine/asmacros.h>		/* miscellaneous asm macros */
40#include <machine/apic.h>
41#include <machine/specialreg.h>
42
43#include "assym.s"
44
45/*
46 * this code MUST be enabled here and in mp_machdep.c
47 * it follows the very early stages of AP boot by placing values in CMOS ram.
48 * it NORMALLY will never be needed and thus the primitive method for enabling.
49 *
50#define CHECK_POINTS
51 */
52
53#if defined(CHECK_POINTS) && !defined(PC98)
54
55#define CMOS_REG	(0x70)
56#define CMOS_DATA	(0x71)
57
58#define CHECKPOINT(A,D)		\
59	movb	$(A),%al ;	\
60	outb	%al,$CMOS_REG ;	\
61	movb	$(D),%al ;	\
62	outb	%al,$CMOS_DATA
63
64#else
65
66#define CHECKPOINT(A,D)
67
68#endif /* CHECK_POINTS */
69
70
71/*
72 * the APs enter here from their trampoline code (bootMP, below)
73 */
74	.p2align 4
75
76NON_GPROF_ENTRY(MPentry)
77	CHECKPOINT(0x36, 3)
78	/* Now enable paging mode */
79	movl	_IdlePTD-KERNBASE, %eax
80	movl	%eax,%cr3
81	movl	%cr0,%eax
82	orl	$CR0_PE|CR0_PG,%eax		/* enable paging */
83	movl	%eax,%cr0			/* let the games begin! */
84	movl	_bootSTK,%esp			/* boot stack end loc. */
85
86	pushl	$mp_begin			/* jump to high mem */
87	ret
88
89	/*
90	 * Wait for the booting CPU to signal startup
91	 */
92mp_begin:	/* now running relocated at KERNBASE */
93	CHECKPOINT(0x37, 4)
94	call	_init_secondary			/* load i386 tables */
95	CHECKPOINT(0x38, 5)
96
97#ifdef VM86
98	/*
99	 * If the [BSP] CPU has support for VME, turn it on.
100	 */
101	testl	$CPUID_VME, _cpu_feature	/* XXX WRONG! BSP! */
102	jz	1f
103	movl	%cr4, %eax
104	orl	$CR4_VME, %eax
105	movl	%eax, %cr4
1061:
107#endif
108
109	/* disable the APIC, just to be SURE */
110	movl	lapic_svr, %eax			/* get spurious vector reg. */
111	andl	$~APIC_SVR_SWEN, %eax		/* clear software enable bit */
112	movl	%eax, lapic_svr
113
114	/* signal our startup to the BSP */
115	movl	lapic_ver, %eax			/* our version reg contents */
116	movl	%eax, _cpu_apic_versions	/* into [ 0 ] */
117	incl	_mp_ncpus			/* signal BSP */
118
119	CHECKPOINT(0x39, 6)
120
121	/* wait till we can get into the kernel */
122	call	_boot_get_mplock
123
124	/* Now, let's prepare for some REAL WORK :-) */
125	call	_ap_init
126
127	call	_rel_mplock
1282:
129	cmpl	$0, CNAME(smp_started)	/* Wait for last AP to be ready */
130	jz	2b
131	call _get_mplock
132
133	/* let her rip! (loads new stack) */
134	jmp 	_cpu_switch
135
136NON_GPROF_ENTRY(wait_ap)
137	pushl	%ebp
138	movl	%esp, %ebp
139	call	_rel_mplock
140	movl	%eax, 8(%ebp)
1411:
142	cmpl	$0, CNAME(smp_started)
143	jnz	2f
144	decl	%eax
145	cmpl	$0, %eax
146	jge	1b
1472:
148	call	_get_mplock
149	movl	%ebp, %esp
150	popl	%ebp
151	ret
152
153
154/*
155 * This is the embedded trampoline or bootstrap that is
156 * copied into 'real-mode' low memory, it is where the
157 * secondary processor "wakes up". When it is executed
158 * the processor will eventually jump into the routine
159 * MPentry, which resides in normal kernel text above
160 * 1Meg.		-jackv
161 */
162
163#define data32	.byte 0x66
164#define addr32	.byte 0x67
165
166	.data
167	ALIGN_DATA				/* just to be sure */
168
169BOOTMP1:
170
171NON_GPROF_ENTRY(bootMP)
172	cli
173	CHECKPOINT(0x34, 1)
174	/* First guarantee a 'clean slate' */
175	data32
176	xorl	%eax, %eax
177	data32
178	movl	%eax, %ebx
179	data32
180	movl	%eax, %ecx
181	data32
182 	movl	%eax, %edx
183	data32
184	movl	%eax, %esi
185	data32
186	movl	%eax, %edi
187
188	/* set up data segments */
189	mov	%cs, %ax
190	mov	%ax, %ds
191	mov	%ax, %es
192	mov	%ax, %fs
193	mov	%ax, %gs
194	mov	%ax, %ss
195	mov	$(boot_stk-_bootMP), %sp
196
197	/* Now load the global descriptor table */
198	addr32
199	data32
200	/* XXX: sigh: lgdt	MP_GDTptr-_bootMP GAS BUG! */
201	.byte	0x0f, 0x01, 0x15		/* XXX hand assemble! */
202	.long	MP_GDTptr-_bootMP		/* XXX hand assemble! */
203
204	/* Enable protected mode */
205	data32
206	movl	%cr0, %eax
207	data32
208	orl	$CR0_PE, %eax
209	data32
210	movl	%eax, %cr0
211
212	/*
213	 * make intrasegment jump to flush the processor pipeline and
214	 * reload CS register
215	 */
216	data32
217	pushl	$0x18
218	data32
219	pushl	$(protmode-_bootMP)
220	data32
221	lret
222
223protmode:
224	CHECKPOINT(0x35, 2)
225
226	/*
227	 * we are NOW running for the first time with %eip
228	 * having the full physical address, BUT we still
229	 * are using a segment descriptor with the origin
230	 * not matching the booting kernel.
231	 *
232 	 * SO NOW... for the BIG Jump into kernel's segment
233	 * and physical text above 1 Meg.
234	 */
235	mov	$0x10, %ebx
236	movw	%bx, %ds
237	movw	%bx, %es
238	movw	%bx, %fs
239	movw	%bx, %gs
240	movw	%bx, %ss
241
242	.globl	_bigJump
243_bigJump:
244	/* this will be modified by mpInstallTramp() */
245	ljmp	$0x08, $0			/* far jmp to MPentry() */
246
247dead:	hlt /* We should never get here */
248	jmp	dead
249
250/*
251 * MP boot strap Global Descriptor Table
252 */
253	.p2align 4
254	.globl	_MP_GDT
255	.globl	_bootCodeSeg
256	.globl	_bootDataSeg
257_MP_GDT:
258
259nulldesc:		/* offset = 0x0 */
260
261	.word	0x0
262	.word	0x0
263	.byte	0x0
264	.byte	0x0
265	.byte	0x0
266	.byte	0x0
267
268kernelcode:		/* offset = 0x08 */
269
270	.word	0xffff	/* segment limit 0..15 */
271	.word	0x0000	/* segment base 0..15 */
272	.byte	0x0	/* segment base 16..23; set for 0K */
273	.byte	0x9f	/* flags; Type	*/
274	.byte	0xcf	/* flags; Limit	*/
275	.byte	0x0	/* segment base 24..32 */
276
277kerneldata:		/* offset = 0x10 */
278
279	.word	0xffff	/* segment limit 0..15 */
280	.word	0x0000	/* segment base 0..15 */
281	.byte	0x0	/* segment base 16..23; set for 0k */
282	.byte	0x93	/* flags; Type  */
283	.byte	0xcf	/* flags; Limit */
284	.byte	0x0	/* segment base 24..32 */
285
286bootcode:		/* offset = 0x18 */
287
288	.word	0xffff	/* segment limit 0..15 */
289_bootCodeSeg:		/* this will be modified by mpInstallTramp() */
290	.word	0x0000	/* segment base 0..15 */
291	.byte	0x00	/* segment base 16...23; set for 0x000xx000 */
292	.byte	0x9e	/* flags; Type  */
293	.byte	0xcf	/* flags; Limit */
294	.byte	0x0	/*segment base 24..32 */
295
296bootdata:		/* offset = 0x20 */
297
298	.word	0xffff
299_bootDataSeg:		/* this will be modified by mpInstallTramp() */
300	.word	0x0000	/* segment base 0..15 */
301	.byte	0x00	/* segment base 16...23; set for 0x000xx000 */
302	.byte	0x92
303	.byte	0xcf
304	.byte	0x0
305
306/*
307 * GDT pointer for the lgdt call
308 */
309	.globl	_mp_gdtbase
310
311MP_GDTptr:
312_mp_gdtlimit:
313	.word	0x0028
314_mp_gdtbase:		/* this will be modified by mpInstallTramp() */
315	.long	0
316
317	.space	0x100	/* space for boot_stk - 1st temporary stack */
318boot_stk:
319
320BOOTMP2:
321	.globl	_bootMP_size
322_bootMP_size:
323	.long	BOOTMP2 - BOOTMP1
324