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