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