1250661Sdavidcs/*-
2250661Sdavidcs * Copyright (c) 1995 Jack F. Vogel
3250661Sdavidcs * All rights reserved.
4250661Sdavidcs *
5250661Sdavidcs * Redistribution and use in source and binary forms, with or without
6250661Sdavidcs * modification, are permitted provided that the following conditions
7250661Sdavidcs * are met:
8250661Sdavidcs * 1. Redistributions of source code must retain the above copyright
9250661Sdavidcs *    notice, this list of conditions and the following disclaimer.
10250661Sdavidcs * 2. Redistributions in binary form must reproduce the above copyright
11250661Sdavidcs *    notice, this list of conditions and the following disclaimer in the
12250661Sdavidcs *    documentation and/or other materials provided with the distribution.
13250661Sdavidcs *
14250661Sdavidcs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15250661Sdavidcs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16250661Sdavidcs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17250661Sdavidcs * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
18250661Sdavidcs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19250661Sdavidcs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20250661Sdavidcs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21250661Sdavidcs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22250661Sdavidcs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23250661Sdavidcs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24250661Sdavidcs * SUCH DAMAGE.
25250661Sdavidcs *
26250661Sdavidcs * mpboot.s:	FreeBSD machine support for the Intel MP Spec
27250661Sdavidcs *		multiprocessor systems.
28250661Sdavidcs */
29250661Sdavidcs
30250661Sdavidcs#include "opt_pmap.h"
31250661Sdavidcs
32250661Sdavidcs#include <machine/asmacros.h>		/* miscellaneous asm macros */
33250661Sdavidcs#include <x86/apicreg.h>
34250661Sdavidcs#include <machine/specialreg.h>
35250661Sdavidcs
36250661Sdavidcs#include "assym.inc"
37250661Sdavidcs
38250661Sdavidcs/*
39250661Sdavidcs * this code MUST be enabled here and in mp_machdep.c
40250661Sdavidcs * it follows the very early stages of AP boot by placing values in CMOS ram.
41250661Sdavidcs * it NORMALLY will never be needed and thus the primitive method for enabling.
42250661Sdavidcs *
43250661Sdavidcs#define CHECK_POINTS
44250661Sdavidcs */
45250661Sdavidcs
46250661Sdavidcs#if defined(CHECK_POINTS)
47250661Sdavidcs
48250661Sdavidcs#define CMOS_REG	(0x70)
49250661Sdavidcs#define CMOS_DATA	(0x71)
50250661Sdavidcs
51250661Sdavidcs#define CHECKPOINT(A,D)		\
52250661Sdavidcs	movb	$(A),%al ;	\
53250661Sdavidcs	outb	%al,$CMOS_REG ;	\
54250661Sdavidcs	movb	$(D),%al ;	\
55250661Sdavidcs	outb	%al,$CMOS_DATA
56250661Sdavidcs
57250661Sdavidcs#else
58250661Sdavidcs
59250661Sdavidcs#define CHECKPOINT(A,D)
60250661Sdavidcs
61250661Sdavidcs#endif /* CHECK_POINTS */
62250661Sdavidcs
63250661Sdavidcs
64250661Sdavidcs/*
65250661Sdavidcs * the APs enter here from their trampoline code (bootMP, below)
66250661Sdavidcs */
67250661Sdavidcs	.p2align 4
68250661Sdavidcs
69250661SdavidcsENTRY(MPentry)
70250661Sdavidcs	CHECKPOINT(0x36, 3)
71250661Sdavidcs	/*
72250661Sdavidcs	 * Enable features on this processor.  We don't support SMP on
73250661Sdavidcs	 * CPUs older than a Pentium, so we know that we can use the cpuid
74250661Sdavidcs	 * instruction.
75250661Sdavidcs	 */
76250661Sdavidcs	movl	$1,%eax
77250661Sdavidcs	cpuid					/* Retrieve features */
78250661Sdavidcs	movl	%cr4,%eax
79250661Sdavidcs	testl	$CPUID_PSE,%edx
80250661Sdavidcs	jz 1f
81250661Sdavidcs	orl	$CR4_PSE,%eax			/* Enable PSE  */
82250661Sdavidcs1:	testl	$CPUID_PGE,%edx
83250661Sdavidcs	jz 2f
84250661Sdavidcs	orl	$CR4_PGE,%eax			/* Enable PGE  */
85250661Sdavidcs2:	testl	$CPUID_VME,%edx
86250661Sdavidcs	jz 3f
87250661Sdavidcs	orl	$CR4_VME,%eax			/* Enable VME  */
88250661Sdavidcs3:	movl	%eax,%cr4
89250661Sdavidcs
90250661Sdavidcs	/* Now enable paging mode */
91250661Sdavidcs	cmpl	$0, pae_mode
92250661Sdavidcs	je	4f
93250661Sdavidcs	movl	IdlePDPT, %eax
94250661Sdavidcs	movl	%eax, %cr3
95250661Sdavidcs	movl	%cr4, %eax
96250661Sdavidcs	orl	$CR4_PAE, %eax
97250661Sdavidcs	movl	%eax, %cr4
98250661Sdavidcs	movl	$0x80000000, %eax
99250661Sdavidcs	cpuid
100250661Sdavidcs	movl	$0x80000001, %ebx
101250661Sdavidcs	cmpl	%ebx, %eax
102250661Sdavidcs	jb	5f
103250661Sdavidcs	movl	%ebx, %eax
104250661Sdavidcs	cpuid
105250661Sdavidcs	testl	$AMDID_NX, %edx
106250661Sdavidcs	je	5f
107250661Sdavidcs	movl	$MSR_EFER, %ecx
108250661Sdavidcs	rdmsr
109250661Sdavidcs	orl	$EFER_NXE,%eax
110250661Sdavidcs	wrmsr
111250661Sdavidcs	jmp	5f
112250661Sdavidcs4:	movl	IdlePTD_nopae, %eax
113250661Sdavidcs	movl	%eax,%cr3
114250661Sdavidcs5:	movl	%cr0,%eax
115250661Sdavidcs	orl	$CR0_PE|CR0_PG,%eax		/* enable paging */
116250661Sdavidcs	movl	%eax,%cr0			/* let the games begin! */
117250661Sdavidcs	movl	bootSTK,%esp			/* boot stack end loc. */
118250661Sdavidcs
119250661Sdavidcs	pushl	$mp_begin			/* jump to high mem */
120250661Sdavidcs	ret
121250661Sdavidcs
122250661Sdavidcs	/*
123250661Sdavidcs	 * Wait for the booting CPU to signal startup
124250661Sdavidcs	 */
125250661Sdavidcsmp_begin:	/* now running relocated at KERNBASE */
126250661Sdavidcs	CHECKPOINT(0x37, 4)
127250661Sdavidcs	call	init_secondary			/* load i386 tables */
128250661Sdavidcs
129250661Sdavidcs/*
130250661Sdavidcs * This is the embedded trampoline or bootstrap that is
131250661Sdavidcs * copied into 'real-mode' low memory, it is where the
132250661Sdavidcs * secondary processor "wakes up". When it is executed
133250661Sdavidcs * the processor will eventually jump into the routine
134250661Sdavidcs * MPentry, which resides in normal kernel text above
135250661Sdavidcs * 1Meg.		-jackv
136250661Sdavidcs */
137250661Sdavidcs
138250661Sdavidcs	.data
139250661Sdavidcs	ALIGN_DATA				/* just to be sure */
140250661Sdavidcs
141250661SdavidcsBOOTMP1:
142250661Sdavidcs
143250661SdavidcsENTRY(bootMP)
144250661Sdavidcs	.code16
145250661Sdavidcs	cli
146250661Sdavidcs	CHECKPOINT(0x34, 1)
147250661Sdavidcs	/* First guarantee a 'clean slate' */
148250661Sdavidcs	xorl	%eax, %eax
149250661Sdavidcs	movl	%eax, %ebx
150250661Sdavidcs	movl	%eax, %ecx
151250661Sdavidcs 	movl	%eax, %edx
152250661Sdavidcs	movl	%eax, %esi
153250661Sdavidcs	movl	%eax, %edi
154250661Sdavidcs
155250661Sdavidcs	/* set up data segments */
156250661Sdavidcs	mov	%cs, %ax
157250661Sdavidcs	mov	%ax, %ds
158250661Sdavidcs	mov	%ax, %es
159250661Sdavidcs	mov	%ax, %fs
160250661Sdavidcs	mov	%ax, %gs
161250661Sdavidcs	mov	%ax, %ss
162250661Sdavidcs	mov	$(boot_stk-bootMP), %esp
163250661Sdavidcs
164250661Sdavidcs	/* Now load the global descriptor table */
165250661Sdavidcs	lgdt	MP_GDTptr-bootMP
166250661Sdavidcs
167250661Sdavidcs	/* Enable protected mode */
168250661Sdavidcs	movl	%cr0, %eax
169250661Sdavidcs	orl	$CR0_PE, %eax
170250661Sdavidcs	movl	%eax, %cr0
171250661Sdavidcs
172250661Sdavidcs	/*
173250661Sdavidcs	 * make intrasegment jump to flush the processor pipeline and
174250661Sdavidcs	 * reload CS register
175250661Sdavidcs	 */
176250661Sdavidcs	pushl	$0x18
177250661Sdavidcs	pushl	$(protmode-bootMP)
178250661Sdavidcs	lretl
179250661Sdavidcs
180250661Sdavidcs       .code32
181250661Sdavidcsprotmode:
182250661Sdavidcs	CHECKPOINT(0x35, 2)
183250661Sdavidcs
184250661Sdavidcs	/*
185250661Sdavidcs	 * we are NOW running for the first time with %eip
186250661Sdavidcs	 * having the full physical address, BUT we still
187250661Sdavidcs	 * are using a segment descriptor with the origin
188250661Sdavidcs	 * not matching the booting kernel.
189250661Sdavidcs	 *
190250661Sdavidcs 	 * SO NOW... for the BIG Jump into kernel's segment
191250661Sdavidcs	 * and physical text above 1 Meg.
192250661Sdavidcs	 */
193250661Sdavidcs	mov	$0x10, %ebx
194250661Sdavidcs	movw	%bx, %ds
195250661Sdavidcs	movw	%bx, %es
196250661Sdavidcs	movw	%bx, %fs
197250661Sdavidcs	movw	%bx, %gs
198250661Sdavidcs	movw	%bx, %ss
199250661Sdavidcs
200250661Sdavidcs	.globl	bigJump
201250661SdavidcsbigJump:
202250661Sdavidcs	/* this will be modified by mpInstallTramp() */
203250661Sdavidcs	ljmp	$0x08, $0			/* far jmp to MPentry() */
204250661Sdavidcs
205250661Sdavidcsdead:	hlt /* We should never get here */
206250661Sdavidcs	jmp	dead
207250661Sdavidcs
208250661Sdavidcs/*
209250661Sdavidcs * MP boot strap Global Descriptor Table
210250661Sdavidcs */
211250661Sdavidcs	.p2align 4
212250661Sdavidcs	.globl	MP_GDT
213250661Sdavidcs	.globl	bootCodeSeg
214250661Sdavidcs	.globl	bootDataSeg
215250661SdavidcsMP_GDT:
216250661Sdavidcs
217250661Sdavidcsnulldesc:		/* offset = 0x0 */
218250661Sdavidcs
219250661Sdavidcs	.word	0x0
220250661Sdavidcs	.word	0x0
221250661Sdavidcs	.byte	0x0
222250661Sdavidcs	.byte	0x0
223250661Sdavidcs	.byte	0x0
224250661Sdavidcs	.byte	0x0
225250661Sdavidcs
226250661Sdavidcskernelcode:		/* offset = 0x08 */
227250661Sdavidcs
228250661Sdavidcs	.word	0xffff	/* segment limit 0..15 */
229250661Sdavidcs	.word	0x0000	/* segment base 0..15 */
230250661Sdavidcs	.byte	0x0	/* segment base 16..23; set for 0K */
231250661Sdavidcs	.byte	0x9f	/* flags; Type	*/
232250661Sdavidcs	.byte	0xcf	/* flags; Limit	*/
233250661Sdavidcs	.byte	0x0	/* segment base 24..32 */
234250661Sdavidcs
235250661Sdavidcskerneldata:		/* offset = 0x10 */
236250661Sdavidcs
237250661Sdavidcs	.word	0xffff	/* segment limit 0..15 */
238250661Sdavidcs	.word	0x0000	/* segment base 0..15 */
239250661Sdavidcs	.byte	0x0	/* segment base 16..23; set for 0k */
240250661Sdavidcs	.byte	0x93	/* flags; Type  */
241250661Sdavidcs	.byte	0xcf	/* flags; Limit */
242250661Sdavidcs	.byte	0x0	/* segment base 24..32 */
243250661Sdavidcs
244250661Sdavidcsbootcode:		/* offset = 0x18 */
245250661Sdavidcs
246250661Sdavidcs	.word	0xffff	/* segment limit 0..15 */
247250661SdavidcsbootCodeSeg:		/* this will be modified by mpInstallTramp() */
248250661Sdavidcs	.word	0x0000	/* segment base 0..15 */
249250661Sdavidcs	.byte	0x00	/* segment base 16...23; set for 0x000xx000 */
250250661Sdavidcs	.byte	0x9e	/* flags; Type  */
251250661Sdavidcs	.byte	0xcf	/* flags; Limit */
252250661Sdavidcs	.byte	0x0	/*segment base 24..32 */
253250661Sdavidcs
254250661Sdavidcsbootdata:		/* offset = 0x20 */
255250661Sdavidcs
256250661Sdavidcs	.word	0xffff
257250661SdavidcsbootDataSeg:		/* this will be modified by mpInstallTramp() */
258250661Sdavidcs	.word	0x0000	/* segment base 0..15 */
259	.byte	0x00	/* segment base 16...23; set for 0x000xx000 */
260	.byte	0x92
261	.byte	0xcf
262	.byte	0x0
263
264/*
265 * GDT pointer for the lgdt call
266 */
267	.globl	mp_gdtbase
268
269MP_GDTptr:
270mp_gdtlimit:
271	.word	0x0028
272mp_gdtbase:		/* this will be modified by mpInstallTramp() */
273	.long	0
274
275	.space	0x100	/* space for boot_stk - 1st temporary stack */
276boot_stk:
277
278BOOTMP2:
279	.globl	bootMP_size
280bootMP_size:
281	.long	BOOTMP2 - BOOTMP1
282