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