mpboot.S revision 64325
1102166Stjr/*
2102166Stjr * Copyright (c) 1995, Jack F. Vogel
3102166Stjr * All rights reserved.
4102166Stjr *
5102166Stjr * Redistribution and use in source and binary forms, with or without
6102166Stjr * modification, are permitted provided that the following conditions
7102166Stjr * are met:
8102166Stjr * 1. Redistributions of source code must retain the above copyright
9102166Stjr *    notice, this list of conditions and the following disclaimer.
10102166Stjr * 2. Redistributions in binary form must reproduce the above copyright
11102166Stjr *    notice, this list of conditions and the following disclaimer in the
12102166Stjr *    documentation and/or other materials provided with the distribution.
13102166Stjr * 3. All advertising materials mentioning features or use of this software
14102166Stjr *    must display the following acknowledgement:
15102166Stjr *	This product includes software developed by Jack F. Vogel
16102166Stjr * 4. The name of the developer may be used to endorse or promote products
17102166Stjr *    derived from this software without specific prior written permission.
18102166Stjr *
19102166Stjr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20102166Stjr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21102166Stjr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22102166Stjr * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23102166Stjr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24102166Stjr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25102166Stjr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26107706Sru * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27107706Sru * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28102166Stjr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29102166Stjr * SUCH DAMAGE.
30102166Stjr *
31102166Stjr * mpboot.s:	FreeBSD machine support for the Intel MP Spec
32102166Stjr *		multiprocessor systems.
33102166Stjr *
34102166Stjr * $FreeBSD: head/sys/amd64/amd64/mpboot.S 64325 2000-08-07 02:28:37Z tegge $
35102166Stjr */
36102166Stjr
37102166Stjr#include <machine/asmacros.h>		/* miscellaneous asm macros */
38102166Stjr#include <machine/apic.h>
39102166Stjr#include <machine/specialreg.h>
40102166Stjr
41102166Stjr#include "assym.s"
42102166Stjr
43102166Stjr/*
44102166Stjr * this code MUST be enabled here and in mp_machdep.c
45102166Stjr * it follows the very early stages of AP boot by placing values in CMOS ram.
46102166Stjr * it NORMALLY will never be needed and thus the primitive method for enabling.
47102166Stjr *
48102166Stjr#define CHECK_POINTS
49102166Stjr */
50102166Stjr
51102166Stjr#if defined(CHECK_POINTS) && !defined(PC98)
52102166Stjr
53107706Sru#define CMOS_REG	(0x70)
54102166Stjr#define CMOS_DATA	(0x71)
55102166Stjr
56102166Stjr#define CHECKPOINT(A,D)		\
57102166Stjr	movb	$(A),%al ;	\
58102166Stjr	outb	%al,$CMOS_REG ;	\
59102166Stjr	movb	$(D),%al ;	\
60102166Stjr	outb	%al,$CMOS_DATA
61102166Stjr
62102166Stjr#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
124	lock				/* Avoid livelock (PIII Errata 39) */
125	addl	$0,-4(%esp)
1262:
127	cmpl	$0, CNAME(smp_started)	/* Wait for last AP to be ready */
128	jz	2b
129	call _get_mplock
130
131	/* let her rip! (loads new stack) */
132	jmp 	_cpu_switch
133
134NON_GPROF_ENTRY(wait_ap)
135	pushl	%ebp
136	movl	%esp, %ebp
137	call	_rel_mplock
138	lock				/* Avoid livelock (PIII Errata 39) */
139	addl	$0,0(%esp)
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	.data
164	ALIGN_DATA				/* just to be sure */
165
166BOOTMP1:
167
168NON_GPROF_ENTRY(bootMP)
169	.code16
170	cli
171	CHECKPOINT(0x34, 1)
172	/* First guarantee a 'clean slate' */
173	xorl	%eax, %eax
174	movl	%eax, %ebx
175	movl	%eax, %ecx
176 	movl	%eax, %edx
177	movl	%eax, %esi
178	movl	%eax, %edi
179
180	/* set up data segments */
181	mov	%cs, %ax
182	mov	%ax, %ds
183	mov	%ax, %es
184	mov	%ax, %fs
185	mov	%ax, %gs
186	mov	%ax, %ss
187	mov	$(boot_stk-_bootMP), %esp
188
189	/* Now load the global descriptor table */
190	lgdt	MP_GDTptr-_bootMP
191
192	/* Enable protected mode */
193	movl	%cr0, %eax
194	orl	$CR0_PE, %eax
195	movl	%eax, %cr0
196
197	/*
198	 * make intrasegment jump to flush the processor pipeline and
199	 * reload CS register
200	 */
201	pushl	$0x18
202	pushl	$(protmode-_bootMP)
203	lretl
204
205       .code32
206protmode:
207	CHECKPOINT(0x35, 2)
208
209	/*
210	 * we are NOW running for the first time with %eip
211	 * having the full physical address, BUT we still
212	 * are using a segment descriptor with the origin
213	 * not matching the booting kernel.
214	 *
215 	 * SO NOW... for the BIG Jump into kernel's segment
216	 * and physical text above 1 Meg.
217	 */
218	mov	$0x10, %ebx
219	movw	%bx, %ds
220	movw	%bx, %es
221	movw	%bx, %fs
222	movw	%bx, %gs
223	movw	%bx, %ss
224
225	.globl	_bigJump
226_bigJump:
227	/* this will be modified by mpInstallTramp() */
228	ljmp	$0x08, $0			/* far jmp to MPentry() */
229
230dead:	hlt /* We should never get here */
231	jmp	dead
232
233/*
234 * MP boot strap Global Descriptor Table
235 */
236	.p2align 4
237	.globl	_MP_GDT
238	.globl	_bootCodeSeg
239	.globl	_bootDataSeg
240_MP_GDT:
241
242nulldesc:		/* offset = 0x0 */
243
244	.word	0x0
245	.word	0x0
246	.byte	0x0
247	.byte	0x0
248	.byte	0x0
249	.byte	0x0
250
251kernelcode:		/* offset = 0x08 */
252
253	.word	0xffff	/* segment limit 0..15 */
254	.word	0x0000	/* segment base 0..15 */
255	.byte	0x0	/* segment base 16..23; set for 0K */
256	.byte	0x9f	/* flags; Type	*/
257	.byte	0xcf	/* flags; Limit	*/
258	.byte	0x0	/* segment base 24..32 */
259
260kerneldata:		/* offset = 0x10 */
261
262	.word	0xffff	/* segment limit 0..15 */
263	.word	0x0000	/* segment base 0..15 */
264	.byte	0x0	/* segment base 16..23; set for 0k */
265	.byte	0x93	/* flags; Type  */
266	.byte	0xcf	/* flags; Limit */
267	.byte	0x0	/* segment base 24..32 */
268
269bootcode:		/* offset = 0x18 */
270
271	.word	0xffff	/* segment limit 0..15 */
272_bootCodeSeg:		/* this will be modified by mpInstallTramp() */
273	.word	0x0000	/* segment base 0..15 */
274	.byte	0x00	/* segment base 16...23; set for 0x000xx000 */
275	.byte	0x9e	/* flags; Type  */
276	.byte	0xcf	/* flags; Limit */
277	.byte	0x0	/*segment base 24..32 */
278
279bootdata:		/* offset = 0x20 */
280
281	.word	0xffff
282_bootDataSeg:		/* this will be modified by mpInstallTramp() */
283	.word	0x0000	/* segment base 0..15 */
284	.byte	0x00	/* segment base 16...23; set for 0x000xx000 */
285	.byte	0x92
286	.byte	0xcf
287	.byte	0x0
288
289/*
290 * GDT pointer for the lgdt call
291 */
292	.globl	_mp_gdtbase
293
294MP_GDTptr:
295_mp_gdtlimit:
296	.word	0x0028
297_mp_gdtbase:		/* this will be modified by mpInstallTramp() */
298	.long	0
299
300	.space	0x100	/* space for boot_stk - 1st temporary stack */
301boot_stk:
302
303BOOTMP2:
304	.globl	_bootMP_size
305_bootMP_size:
306	.long	BOOTMP2 - BOOTMP1
307