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