mpboot.S revision 25164
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.18 1997/04/25 03:11:27 fsmp Exp $
35 */
36
37
38#include <machine/asmacros.h>		/* miscellaneous asm macros */
39#include <machine/apic.h>
40#include <machine/specialreg.h>
41
42#include "assym.s"
43
44/*
45 * this code MUST be enabled here and in mp_machdep.c
46 * it follows the very early stages of AP boot by placing values in CMOS ram.
47 * it NORMALLY will never be needed and thus the primitive method for enabling.
48 *
49#define CHECK_POINTS
50 */
51
52#if defined(CHECK_POINTS)
53
54#define CMOS_REG	(0x70)
55#define CMOS_DATA	(0x71)
56
57#define CHECKPOINT(A,D)		\
58	movb	$(A),%al ;	\
59	outb	%al,$CMOS_REG ;	\
60	movb	$(D),%al ;	\
61	outb	%al,$CMOS_DATA
62
63#else
64
65#define CHECKPOINT(A,D)
66
67#endif /* CHECK_POINTS */
68
69
70/*
71 * the APs enter here from their trampoline code (bootMP, below)
72 */
73	.align	4
74
75NON_GPROF_ENTRY(MPentry)
76	CHECKPOINT(0x36, 3)
77	movl	$mp_stk-KERNBASE,%esp		/* mp boot stack end loc. */
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	$0x80000011,%eax
84	movl	%eax,%cr0			/* let the games begin! */
85	movl	$mp_stk,%esp			/* mp boot stack end loc. */
86
87	pushl	$mp_begin			/* jump to high mem */
88	ret
89
90	/*
91	 * Wait for the booting CPU to signal startup
92	 */
93mp_begin:	/* now running relocated at KERNBASE */
94	CHECKPOINT(0x37, 4)
95	call	_init_secondary			/* load i386 tables */
96	CHECKPOINT(0x38, 5)
97
98	/* disable the APIC, just to be SURE */
99	movl	_apic_base, %esi
100	movl	APIC_SVR(%esi), %eax		/* get spurious vector reg. */
101	andl	$~APIC_SVR_SWEN, %eax		/* clear software enable bit */
102	movl	%eax, APIC_SVR(%esi)
103
104	/* signal our startup to the BSP */
105	movl	APIC_VER(%esi), %eax		/* our version reg contents */
106	movl	%eax, _cpu_apic_versions	/* into [ 0 ] */
107	incl	_mp_ncpus			/* signal BSP */
108
109	/* One at a time, we are running on the shared mp_stk */
110	/* This is the Intel reccomended semaphore method */
111#define BL_SET	0xff
112#define BL_CLR	0x00
113	movb	$BL_SET, %al
1141:
115	xchgb	%al, bootlock		/* xchg is implicitly locked */
116	cmpb	$BL_SET, %al		/* was is set? */
117	jz	1b			/* yes, keep trying... */
118	CHECKPOINT(0x39, 6)
119
120	/* Now, let's do some REAL WORK :-) */
121	call	_secondary_main
122/* NOT REACHED */
1232:	hlt
124	jmp 	2b
125
126/*
127 * Let a CPU past the semaphore so it can use mp_stk
128 */
129ENTRY(boot_unlock)
130	movb	$BL_CLR, %al
131	xchgb	%al, bootlock		/* xchg is implicitly locked */
132	ret
133
134/*
135 * This is the embedded trampoline or bootstrap that is
136 * copied into 'real-mode' low memory, it is where the
137 * secondary processor "wakes up". When it is executed
138 * the processor will eventually jump into the routine
139 * MPentry, which resides in normal kernel text above
140 * 1Meg.		-jackv
141 */
142
143#define data32	.byte 0x66
144#define addr32	.byte 0x67
145
146	.data
147	ALIGN_DATA				/* just to be sure */
148
149BOOTMP1:
150
151NON_GPROF_ENTRY(bootMP)
152	cli
153	CHECKPOINT(0x34, 1)
154	/* First guarantee a 'clean slate' */
155	data32
156	xorl	%eax, %eax
157	data32
158	movl	%eax, %ebx
159	data32
160	movl	%eax, %ecx
161	data32
162 	movl	%eax, %edx
163	data32
164	movl	%eax, %esi
165	data32
166	movl	%eax, %edi
167
168	/* set up data segments */
169	mov	%cs, %ax
170	mov	%ax, %ds
171	mov	%ax, %es
172	mov	%ax, %fs
173	mov	%ax, %gs
174	mov	%ax, %ss
175	mov	$(boot_stk-_bootMP), %sp
176
177	/* Now load the global descriptor table */
178	addr32
179	data32
180	/* XXX: sigh: lgdt	MP_GDTptr-_bootMP GAS BUG! */
181	.byte	0x0f, 0x01, 0x15		/* XXX hand assemble! */
182	.long	MP_GDTptr-_bootMP		/* XXX hand assemble! */
183
184	/* Enable protected mode */
185	data32
186	movl	%cr0, %eax
187	data32
188	orl	$CR0_PE, %eax
189	data32
190	movl	%eax, %cr0
191
192	/*
193	 * make intrasegment jump to flush the processor pipeline and
194	 * reload CS register
195	 */
196	data32
197	pushl	$0x18
198	data32
199	pushl	$(protmode-_bootMP)
200	data32
201	lret
202
203protmode:
204	CHECKPOINT(0x35, 2)
205
206	/*
207	 * we are NOW running for the first time with %eip
208	 * having the full physical address, BUT we still
209	 * are using a segment descriptor with the origin
210	 * not matching the booting kernel.
211	 *
212 	 * SO NOW... for the BIG Jump into kernel's segment
213	 * and physical text above 1 Meg.
214	 */
215	mov	$0x10, %ebx
216	movw	%bx, %ds
217	movw	%bx, %es
218	movw	%bx, %fs
219	movw	%bx, %gs
220	movw	%bx, %ss
221
222	.globl	_bigJump
223_bigJump:
224	/* this will be modified by mpInstallTramp() */
225	ljmp	$0x08, $0			/* far jmp to MPentry() */
226
227dead:	hlt /* We should never get here */
228	jmp	dead
229
230/*
231 * MP boot strap Global Descriptor Table
232 */
233	.align	4
234	.globl	_MP_GDT
235	.globl	_bootCodeSeg
236	.globl	_bootDataSeg
237_MP_GDT:
238
239nulldesc:		/* offset = 0x0 */
240
241	.word	0x0
242	.word	0x0
243	.byte	0x0
244	.byte	0x0
245	.byte	0x0
246	.byte	0x0
247
248kernelcode:		/* offset = 0x08 */
249
250	.word	0xffff	/* segment limit 0..15 */
251	.word	0x0000	/* segment base 0..15 */
252	.byte	0x0	/* segment base 16..23; set for 0K */
253	.byte	0x9f	/* flags; Type	*/
254	.byte	0xcf	/* flags; Limit	*/
255	.byte	0x0	/* segment base 24..32 */
256
257kerneldata:		/* offset = 0x10 */
258
259	.word	0xffff	/* segment limit 0..15 */
260	.word	0x0000	/* segment base 0..15 */
261	.byte	0x0	/* segment base 16..23; set for 0k */
262	.byte	0x93	/* flags; Type  */
263	.byte	0xcf	/* flags; Limit */
264	.byte	0x0	/* segment base 24..32 */
265
266bootcode:		/* offset = 0x18 */
267
268	.word	0xffff	/* segment limit 0..15 */
269_bootCodeSeg:		/* this will be modified by mpInstallTramp() */
270	.word	0x0000	/* segment base 0..15 */
271	.byte	0x00	/* segment base 16...23; set for 0x000xx000 */
272	.byte	0x9e	/* flags; Type  */
273	.byte	0xcf	/* flags; Limit */
274	.byte	0x0	/*segment base 24..32 */
275
276bootdata:		/* offset = 0x20 */
277
278	.word	0xffff
279_bootDataSeg:		/* this will be modified by mpInstallTramp() */
280	.word	0x0000	/* segment base 0..15 */
281	.byte	0x00	/* segment base 16...23; set for 0x000xx000 */
282	.byte	0x92
283	.byte	0xcf
284	.byte	0x0
285
286/*
287 * GDT pointer for the lgdt call
288 */
289	.globl	_mp_gdtbase
290
291MP_GDTptr:
292_mp_gdtlimit:
293	.word	0x0028
294_mp_gdtbase:		/* this will be modified by mpInstallTramp() */
295	.long	0
296
297	.space	0x100	/* space for boot_stk - 1st temporary stack */
298boot_stk:
299
300BOOTMP2:
301	.globl	_bootMP_size
302_bootMP_size:
303	.long	BOOTMP2 - BOOTMP1
304
305	/*
306	 * Temporary stack used while booting AP's
307	 * It is protected by:
308	 * 1: only one cpu is started at a time and it ends up waiting
309	 *    for smp_active before continuing.
310	 * 2: Once smp_active != 0; further access is limited by _bootlock.
311	 */
312	.globl	mp_stk
313	.space	0x2000	/* space for mp_stk - 2nd temporary stack */
314mp_stk:
315
316	.globl	bootlock
317bootlock:	.byte BL_SET
318