]>
Commit | Line | Data |
---|---|---|
55e303ae | 1 | /* |
b0d623f7 | 2 | * Copyright (c) 2003-2009 Apple Inc. All rights reserved. |
55e303ae | 3 | * |
2d21ac55 | 4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
55e303ae | 5 | * |
2d21ac55 A |
6 | * This file contains Original Code and/or Modifications of Original Code |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. The rights granted to you under the License | |
10 | * may not be used to create, or enable the creation or redistribution of, | |
11 | * unlawful or unlicensed copies of an Apple operating system, or to | |
12 | * circumvent, violate, or enable the circumvention or violation of, any | |
13 | * terms of an Apple operating system software license agreement. | |
8f6c56a5 | 14 | * |
2d21ac55 A |
15 | * Please obtain a copy of the License at |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
17 | * | |
18 | * The Original Code and all software distributed under the License are | |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
8f6c56a5 A |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
2d21ac55 A |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. |
23 | * Please see the License for the specific language governing rights and | |
24 | * limitations under the License. | |
8f6c56a5 | 25 | * |
2d21ac55 | 26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
55e303ae A |
27 | */ |
28 | /* | |
29 | * @OSF_COPYRIGHT@ | |
30 | */ | |
31 | /* | |
32 | * Mach Operating System | |
33 | * Copyright (c) 1991,1990,1989, 1988 Carnegie Mellon University | |
34 | * All Rights Reserved. | |
35 | * | |
36 | * Permission to use, copy, modify and distribute this software and its | |
37 | * documentation is hereby granted, provided that both the copyright | |
38 | * notice and this permission notice appear in all copies of the | |
39 | * software, derivative works or modified versions, and any portions | |
40 | * thereof, and that both notices appear in supporting documentation. | |
41 | * | |
42 | * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" | |
43 | * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR | |
44 | * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. | |
45 | * | |
46 | * Carnegie Mellon requests users of this software to return to | |
47 | * | |
48 | * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU | |
49 | * School of Computer Science | |
50 | * Carnegie Mellon University | |
51 | * Pittsburgh PA 15213-3890 | |
52 | * | |
53 | * any improvements or extensions that they make and grant Carnegie Mellon | |
54 | * the rights to redistribute these changes. | |
55 | */ | |
56 | ||
55e303ae A |
57 | #include <platforms.h> |
58 | #include <mach_kdb.h> | |
55e303ae A |
59 | |
60 | #include <mach/i386/vm_param.h> | |
61 | ||
62 | #include <string.h> | |
63 | #include <mach/vm_param.h> | |
64 | #include <mach/vm_prot.h> | |
65 | #include <mach/machine.h> | |
66 | #include <mach/time_value.h> | |
55e303ae A |
67 | #include <kern/spl.h> |
68 | #include <kern/assert.h> | |
69 | #include <kern/debug.h> | |
70 | #include <kern/misc_protos.h> | |
71 | #include <kern/startup.h> | |
72 | #include <kern/clock.h> | |
0c530ab8 | 73 | #include <kern/pms.h> |
55e303ae A |
74 | #include <kern/xpr.h> |
75 | #include <kern/cpu_data.h> | |
76 | #include <kern/processor.h> | |
0c530ab8 | 77 | #include <console/serial_protos.h> |
55e303ae A |
78 | #include <vm/vm_page.h> |
79 | #include <vm/pmap.h> | |
80 | #include <vm/vm_kern.h> | |
81 | #include <i386/fpu.h> | |
82 | #include <i386/pmap.h> | |
83 | #include <i386/ipl.h> | |
55e303ae | 84 | #include <i386/misc_protos.h> |
b0d623f7 | 85 | #include <i386/cpu_threads.h> |
55e303ae | 86 | #include <i386/cpuid.h> |
b0d623f7 | 87 | #include <i386/lapic.h> |
55e303ae | 88 | #include <i386/mp.h> |
0c530ab8 | 89 | #include <i386/mp_desc.h> |
b0d623f7 | 90 | #include <i386/mtrr.h> |
91447636 | 91 | #include <i386/machine_routines.h> |
b0d623f7 | 92 | #if CONFIG_MCA |
0c530ab8 | 93 | #include <i386/machine_check.h> |
b0d623f7 | 94 | #endif |
91447636 | 95 | #include <i386/postcode.h> |
0c530ab8 A |
96 | #include <i386/Diagnostics.h> |
97 | #include <i386/pmCPU.h> | |
98 | #include <i386/tsc.h> | |
2d21ac55 | 99 | #include <i386/locks.h> /* LcksOpts */ |
b0d623f7 A |
100 | #ifdef __i386__ |
101 | #include <i386/cpu_capabilities.h> | |
102 | #if MACH_KDB | |
103 | #include <machine/db_machdep.h> | |
104 | #endif | |
105 | #endif | |
106 | ||
107 | #if DEBUG | |
108 | #define DBG(x...) kprintf(x) | |
109 | #else | |
110 | #define DBG(x...) | |
111 | #endif | |
55e303ae A |
112 | #if MACH_KDB |
113 | #include <ddb/db_aout.h> | |
114 | #endif /* MACH_KDB */ | |
55e303ae | 115 | |
b0d623f7 A |
116 | int debug_task; |
117 | ||
118 | static boot_args *kernelBootArgs; | |
119 | ||
120 | extern int disableConsoleOutput; | |
121 | extern const char version[]; | |
122 | extern const char version_variant[]; | |
123 | extern int nx_enabled; | |
124 | ||
125 | extern int noVMX; /* if set, rosetta should not emulate altivec */ | |
126 | ||
127 | #ifdef __x86_64__ | |
128 | extern void *low_eintstack; | |
129 | #endif | |
130 | ||
131 | extern void serial_init(void); | |
132 | ||
133 | void *KPTphys; | |
134 | pd_entry_t *IdlePTD; | |
135 | #ifdef __i386__ | |
136 | pd_entry_t *IdlePDPT64; | |
137 | #endif | |
138 | ||
139 | ||
140 | char *physfree; | |
141 | ||
142 | /* | |
143 | * Note: ALLOCPAGES() can only be used safely within Idle_PTs_init() | |
144 | * due to the mutation of physfree. | |
145 | */ | |
146 | static void * | |
147 | ALLOCPAGES(int npages) | |
148 | { | |
149 | uintptr_t tmp = (uintptr_t)physfree; | |
150 | bzero(physfree, npages * PAGE_SIZE); | |
151 | physfree += npages * PAGE_SIZE; | |
152 | #ifdef __x86_64__ | |
153 | tmp += VM_MIN_KERNEL_ADDRESS & ~LOW_4GB_MASK; | |
154 | #endif | |
155 | return (void *)tmp; | |
156 | } | |
157 | ||
158 | static void | |
159 | fillkpt(pt_entry_t *base, int prot, uintptr_t src, int index, int count) | |
160 | { | |
161 | int i; | |
162 | for (i=0; i<count; i++) { | |
163 | base[index] = src | prot | INTEL_PTE_VALID; | |
164 | src += PAGE_SIZE; | |
165 | index++; | |
166 | } | |
167 | } | |
168 | ||
169 | extern vm_offset_t first_avail; | |
170 | ||
171 | #ifdef __x86_64__ | |
172 | int break_kprintf = 0; | |
173 | ||
174 | uint64_t | |
175 | x86_64_pre_sleep(void) | |
176 | { | |
177 | IdlePML4[0] = IdlePML4[KERNEL_PML4_INDEX]; | |
178 | uint64_t oldcr3 = get_cr3(); | |
179 | set_cr3((uint32_t) (uintptr_t)ID_MAP_VTOP(IdlePML4)); | |
180 | return oldcr3; | |
181 | } | |
182 | ||
183 | void | |
184 | x86_64_post_sleep(uint64_t new_cr3) | |
185 | { | |
186 | IdlePML4[0] = 0; | |
187 | set_cr3((uint32_t) new_cr3); | |
188 | } | |
189 | ||
190 | #endif | |
191 | ||
192 | #ifdef __i386__ | |
193 | #define ID_MAP_VTOP(x) x | |
194 | #endif | |
195 | ||
55e303ae | 196 | |
2d21ac55 | 197 | |
b0d623f7 A |
198 | #ifdef __x86_64__ |
199 | // Set up the physical mapping - NPHYSMAP GB of memory mapped at a high address | |
200 | // NPHYSMAP is determined by the maximum supported RAM size plus 4GB to account | |
201 | // the PCI hole (which is less 4GB but not more). | |
202 | #define NPHYSMAP MAX(K64_MAXMEM/GB + 4, 4) | |
203 | // Compile-time guard: | |
204 | extern int maxphymapsupported[NPHYSMAP <= PTE_PER_PAGE ? 1 : -1]; | |
205 | static void | |
206 | physmap_init(void) | |
207 | { | |
208 | pt_entry_t *physmapL3 = ALLOCPAGES(1); | |
209 | struct { | |
210 | pt_entry_t entries[PTE_PER_PAGE]; | |
211 | } * physmapL2 = ALLOCPAGES(NPHYSMAP); | |
212 | ||
213 | uintptr_t i; | |
214 | for(i=0;i<NPHYSMAP;i++) { | |
215 | physmapL3[i] = ((uintptr_t)ID_MAP_VTOP(&physmapL2[i])) | |
216 | | INTEL_PTE_VALID | |
217 | | INTEL_PTE_WRITE; | |
218 | uintptr_t j; | |
219 | for(j=0;j<PTE_PER_PAGE;j++) { | |
220 | physmapL2[i].entries[j] = (((i*PTE_PER_PAGE+j)<<PDSHIFT) | |
221 | | INTEL_PTE_PS | |
222 | | INTEL_PTE_VALID | |
223 | | INTEL_PTE_WRITE); | |
224 | } | |
225 | } | |
226 | ||
227 | IdlePML4[KERNEL_PHYSMAP_INDEX] = ((uintptr_t)ID_MAP_VTOP(physmapL3)) | |
228 | | INTEL_PTE_VALID | |
229 | | INTEL_PTE_WRITE; | |
230 | DBG("physical map idlepml4[%d]: 0x%llx\n", | |
231 | KERNEL_PHYSMAP_INDEX, IdlePML4[KERNEL_PHYSMAP_INDEX]); | |
232 | } | |
233 | #endif | |
234 | ||
235 | static void | |
236 | Idle_PTs_init(void) | |
237 | { | |
238 | /* Allocate the "idle" kernel page tables: */ | |
239 | KPTphys = ALLOCPAGES(NKPT); /* level 1 */ | |
240 | IdlePTD = ALLOCPAGES(NPGPTD); /* level 2 */ | |
241 | ||
242 | #ifdef __x86_64__ | |
243 | physmap_init(); | |
244 | #else | |
245 | IdlePDPT64 = ALLOCPAGES(1); | |
246 | ||
247 | // Recursive mapping of PTEs | |
248 | fillkpt(IdlePTD, INTEL_PTE_WRITE, (uintptr_t)IdlePTD, PTDPTDI, NPGPTD); | |
249 | // commpage | |
250 | fillkpt(IdlePTD, INTEL_PTE_WRITE|INTEL_PTE_USER, (uintptr_t)ALLOCPAGES(1), _COMM_PAGE32_BASE_ADDRESS >> PDESHIFT,1); | |
251 | #endif | |
252 | // Fill the lowest level with everything up to physfree | |
253 | fillkpt(KPTphys, | |
254 | INTEL_PTE_WRITE, 0, 0, (int)(((uintptr_t)physfree) >> PAGE_SHIFT)); | |
255 | ||
256 | // Rewrite the 2nd-lowest level to point to pages of KPTphys. | |
257 | // This was previously filled statically by idle_pt.c, and thus | |
258 | // must be done after the KPTphys fill since IdlePTD is in use | |
259 | fillkpt(IdlePTD, | |
260 | INTEL_PTE_WRITE, (uintptr_t)ID_MAP_VTOP(KPTphys), 0, NKPT); | |
261 | ||
262 | // IdlePDPT entries | |
263 | #ifdef __i386__ | |
264 | fillkpt(IdlePDPT, 0, (uintptr_t)IdlePTD, 0, NPGPTD); | |
265 | #else | |
266 | fillkpt(IdlePDPT, INTEL_PTE_WRITE, (uintptr_t)ID_MAP_VTOP(IdlePTD), 0, NPGPTD); | |
267 | #endif | |
268 | ||
269 | // Flush the TLB now we're done rewriting the page tables.. | |
270 | set_cr3(get_cr3()); | |
271 | } | |
272 | ||
273 | /* | |
274 | * vstart() is called in the natural mode (64bit for K64, 32 for K32) | |
275 | * on a set of bootstrap pagetables which use large, 2MB pages to map | |
276 | * all of physical memory in both. See idle_pt.c for details. | |
277 | * | |
278 | * In K64 this identity mapping is mirrored the top and bottom 512GB | |
279 | * slots of PML4. | |
280 | * | |
281 | * The bootstrap processor called with argument boot_args_start pointing to | |
282 | * the boot-args block. The kernel's (4K page) page tables are allocated and | |
283 | * initialized before switching to these. | |
284 | * | |
285 | * Non-bootstrap processors are called with argument boot_args_start NULL. | |
286 | * These processors switch immediately to the existing kernel page tables. | |
287 | */ | |
288 | void | |
289 | vstart(vm_offset_t boot_args_start) | |
290 | { | |
291 | boolean_t is_boot_cpu = !(boot_args_start == 0); | |
292 | int cpu; | |
293 | uint32_t lphysfree; | |
294 | ||
295 | postcode(VSTART_ENTRY); | |
296 | ||
297 | if (is_boot_cpu) { | |
298 | /* | |
299 | * Get startup parameters. | |
300 | */ | |
301 | kernelBootArgs = (boot_args *)boot_args_start; | |
302 | lphysfree = kernelBootArgs->kaddr + kernelBootArgs->ksize; | |
303 | physfree = (void *)(uintptr_t)((lphysfree + PAGE_SIZE - 1) &~ (PAGE_SIZE - 1)); | |
304 | #if DEBUG | |
305 | serial_init(); | |
306 | #endif | |
307 | DBG("revision 0x%x\n", kernelBootArgs->Revision); | |
308 | DBG("version 0x%x\n", kernelBootArgs->Version); | |
309 | DBG("command line %s\n", kernelBootArgs->CommandLine); | |
310 | DBG("memory map 0x%x\n", kernelBootArgs->MemoryMap); | |
311 | DBG("memory map sz 0x%x\n", kernelBootArgs->MemoryMapSize); | |
312 | DBG("kaddr 0x%x\n", kernelBootArgs->kaddr); | |
313 | DBG("ksize 0x%x\n", kernelBootArgs->ksize); | |
314 | DBG("physfree %p\n", physfree); | |
315 | DBG("bootargs: %p, &ksize: %p &kaddr: %p\n", | |
316 | kernelBootArgs, | |
317 | &kernelBootArgs->ksize, | |
318 | &kernelBootArgs->kaddr); | |
319 | ||
320 | postcode(PSTART_PAGE_TABLES); | |
321 | ||
322 | Idle_PTs_init(); | |
323 | ||
324 | first_avail = (vm_offset_t)ID_MAP_VTOP(physfree); | |
325 | ||
326 | cpu = 0; | |
327 | } else { | |
328 | /* Find our logical cpu number */ | |
329 | cpu = lapic_to_cpu[(LAPIC_READ(ID)>>LAPIC_ID_SHIFT) & LAPIC_ID_MASK]; | |
330 | } | |
8ad349bb | 331 | |
b0d623f7 A |
332 | if(is_boot_cpu) cpu_data_alloc(TRUE); |
333 | #ifdef __x86_64__ | |
334 | if(is_boot_cpu) | |
335 | cpu_desc_init64(cpu_datap(cpu)); | |
336 | cpu_desc_load64(cpu_datap(cpu)); | |
337 | #else | |
338 | if(is_boot_cpu) | |
339 | cpu_desc_init(cpu_datap(cpu)); | |
340 | cpu_desc_load(cpu_datap(cpu)); | |
341 | #endif | |
342 | cpu_mode_init(current_cpu_datap()); | |
343 | ||
344 | /* enable NX/XD */ | |
345 | if (cpuid_extfeatures() & CPUID_EXTFEATURE_XD) | |
346 | wrmsr64(MSR_IA32_EFER, rdmsr64(MSR_IA32_EFER) | MSR_IA32_EFER_NXE); | |
347 | DBG("vstart() NX/XD enabled\n"); | |
348 | ||
349 | ||
350 | #ifdef __x86_64__ | |
351 | /* Done with identity mapping */ | |
352 | IdlePML4[0] = 0; | |
353 | #endif | |
354 | ||
355 | postcode(VSTART_EXIT); | |
356 | #ifdef __i386__ | |
357 | if (is_boot_cpu) | |
358 | i386_init(boot_args_start); | |
359 | else | |
360 | i386_init_slave(); | |
361 | /*NOTREACHED*/ | |
362 | #else | |
363 | /* We need to switch to a new per-cpu stack, but we must do this atomically with | |
364 | * the call to ensure the compiler doesn't assume anything about the stack before | |
365 | * e.g. tail-call optimisations | |
366 | */ | |
367 | if (is_boot_cpu) | |
368 | { | |
369 | asm volatile( | |
370 | "mov %1, %%rdi;" | |
371 | "mov %0, %%rsp;" | |
372 | "call _i386_init;" : : "r" | |
373 | (cpu_datap(cpu)->cpu_int_stack_top), "r" (boot_args_start)); | |
374 | } | |
375 | else | |
376 | { | |
377 | asm volatile( | |
378 | "mov %0, %%rsp;" | |
379 | "call _i386_init_slave;" : : "r" | |
380 | (cpu_datap(cpu)->cpu_int_stack_top)); | |
381 | } | |
382 | /*NOTREACHED*/ | |
383 | #endif | |
384 | } | |
21362eb3 | 385 | |
55e303ae A |
386 | /* |
387 | * Cpu initialization. Running virtual, but without MACH VM | |
b0d623f7 | 388 | * set up. |
55e303ae A |
389 | */ |
390 | void | |
0c530ab8 | 391 | i386_init(vm_offset_t boot_args_start) |
55e303ae A |
392 | { |
393 | unsigned int maxmem; | |
0c530ab8 | 394 | uint64_t maxmemtouse; |
b0d623f7 | 395 | unsigned int cpus = 0; |
935ed37a | 396 | boolean_t fidn; |
b0d623f7 A |
397 | #ifdef __i386__ |
398 | boolean_t legacy_mode; | |
399 | #endif | |
400 | boolean_t IA32e = TRUE; | |
91447636 A |
401 | |
402 | postcode(I386_INIT_ENTRY); | |
55e303ae | 403 | |
b0d623f7 | 404 | #if CONFIG_MCA |
0c530ab8 A |
405 | /* Initialize machine-check handling */ |
406 | mca_cpu_init(); | |
b0d623f7 | 407 | #endif |
4452a7af | 408 | |
6601e61a | 409 | /* |
0c530ab8 | 410 | * Setup boot args given the physical start address. |
6601e61a | 411 | */ |
0c530ab8 A |
412 | kernelBootArgs = (boot_args *) |
413 | ml_static_ptovirt(boot_args_start); | |
b0d623f7 A |
414 | DBG("i386_init(0x%lx) kernelBootArgs=%p\n", |
415 | (unsigned long)boot_args_start, kernelBootArgs); | |
6601e61a | 416 | |
0c530ab8 | 417 | master_cpu = 0; |
0c530ab8 | 418 | cpu_init(); |
b0d623f7 | 419 | |
0c530ab8 A |
420 | postcode(CPU_INIT_D); |
421 | ||
b0d623f7 | 422 | |
55e303ae | 423 | PE_init_platform(FALSE, kernelBootArgs); |
91447636 | 424 | postcode(PE_INIT_PLATFORM_D); |
55e303ae | 425 | |
b0d623f7 | 426 | |
55e303ae A |
427 | printf_init(); /* Init this in case we need debugger */ |
428 | panic_init(); /* Init this in case we need debugger */ | |
429 | ||
b0d623f7 | 430 | |
55e303ae A |
431 | /* setup debugging output if one has been chosen */ |
432 | PE_init_kprintf(FALSE); | |
55e303ae | 433 | |
593a1d5f | 434 | if (!PE_parse_boot_argn("diag", &dgWork.dgFlags, sizeof (dgWork.dgFlags))) |
0c530ab8 A |
435 | dgWork.dgFlags = 0; |
436 | ||
437 | serialmode = 0; | |
593a1d5f | 438 | if(PE_parse_boot_argn("serial", &serialmode, sizeof (serialmode))) { |
0c530ab8 A |
439 | /* We want a serial keyboard and/or console */ |
440 | kprintf("Serial mode specified: %08X\n", serialmode); | |
441 | } | |
442 | if(serialmode & 1) { | |
443 | (void)switch_to_serial_console(); | |
444 | disableConsoleOutput = FALSE; /* Allow printfs to happen */ | |
445 | } | |
446 | ||
55e303ae A |
447 | /* setup console output */ |
448 | PE_init_printf(FALSE); | |
449 | ||
450 | kprintf("version_variant = %s\n", version_variant); | |
451 | kprintf("version = %s\n", version); | |
2d21ac55 | 452 | |
593a1d5f A |
453 | if (!PE_parse_boot_argn("maxmem", &maxmem, sizeof (maxmem))) |
454 | maxmemtouse = 0; | |
55e303ae | 455 | else |
b0d623f7 | 456 | maxmemtouse = ((uint64_t)maxmem) * MB; |
55e303ae | 457 | |
593a1d5f | 458 | if (PE_parse_boot_argn("cpus", &cpus, sizeof (cpus))) { |
91447636 A |
459 | if ((0 < cpus) && (cpus < max_ncpus)) |
460 | max_ncpus = cpus; | |
461 | } | |
55e303ae | 462 | |
b0d623f7 | 463 | |
0c530ab8 A |
464 | /* |
465 | * debug support for > 4G systems | |
466 | */ | |
593a1d5f | 467 | if (!PE_parse_boot_argn("himemory_mode", &vm_himemory_mode, sizeof (vm_himemory_mode))) |
0c530ab8 A |
468 | vm_himemory_mode = 0; |
469 | ||
935ed37a | 470 | if (!PE_parse_boot_argn("immediate_NMI", &fidn, sizeof (fidn))) |
2d21ac55 | 471 | force_immediate_debugger_NMI = FALSE; |
935ed37a A |
472 | else |
473 | force_immediate_debugger_NMI = fidn; | |
b0d623f7 | 474 | #ifdef __i386__ |
0c530ab8 A |
475 | /* |
476 | * At this point we check whether we are a 64-bit processor | |
477 | * and that we're not restricted to legacy mode, 32-bit operation. | |
478 | */ | |
0c530ab8 A |
479 | if (cpuid_extfeatures() & CPUID_EXTFEATURE_EM64T) { |
480 | kprintf("EM64T supported"); | |
593a1d5f | 481 | if (PE_parse_boot_argn("-legacy", &legacy_mode, sizeof (legacy_mode))) { |
2d21ac55 | 482 | kprintf(" but legacy mode forced\n"); |
b0d623f7 | 483 | IA32e = FALSE; |
0c530ab8 | 484 | } else { |
0c530ab8 A |
485 | kprintf(" and will be enabled\n"); |
486 | } | |
b0d623f7 A |
487 | } else |
488 | IA32e = FALSE; | |
489 | #endif | |
2d21ac55 | 490 | |
0c530ab8 A |
491 | if (!(cpuid_extfeatures() & CPUID_EXTFEATURE_XD)) |
492 | nx_enabled = 0; | |
493 | ||
2d21ac55 | 494 | /* Obtain "lcks" options:this currently controls lock statistics */ |
593a1d5f | 495 | if (!PE_parse_boot_argn("lcks", &LcksOpts, sizeof (LcksOpts))) |
2d21ac55 A |
496 | LcksOpts = 0; |
497 | ||
498 | /* | |
499 | * VM initialization, after this we're using page tables... | |
500 | * The maximum number of cpus must be set beforehand. | |
501 | */ | |
0c530ab8 A |
502 | i386_vm_init(maxmemtouse, IA32e, kernelBootArgs); |
503 | ||
593a1d5f | 504 | if ( ! PE_parse_boot_argn("novmx", &noVMX, sizeof (noVMX))) |
0c530ab8 A |
505 | noVMX = 0; /* OK to support Altivec in rosetta? */ |
506 | ||
0b4c1975 A |
507 | tsc_init(); |
508 | power_management_init(); | |
509 | ||
060df5ea A |
510 | PE_init_platform(TRUE, kernelBootArgs); |
511 | ||
512 | /* create the console for verbose or pretty mode */ | |
513 | PE_create_console(); | |
514 | ||
0c530ab8 A |
515 | processor_bootstrap(); |
516 | thread_bootstrap(); | |
517 | ||
55e303ae | 518 | machine_startup(); |
55e303ae | 519 | } |
b0d623f7 A |
520 | |
521 | static void | |
522 | do_init_slave(boolean_t fast_restart) | |
523 | { | |
524 | void *init_param = FULL_SLAVE_INIT; | |
525 | ||
526 | postcode(I386_INIT_SLAVE); | |
527 | ||
528 | if (!fast_restart) { | |
529 | /* Ensure that caching and write-through are enabled */ | |
530 | set_cr0(get_cr0() & ~(CR0_NW|CR0_CD)); | |
531 | ||
532 | DBG("i386_init_slave() CPU%d: phys (%d) active.\n", | |
533 | get_cpu_number(), get_cpu_phys_number()); | |
534 | ||
535 | assert(!ml_get_interrupts_enabled()); | |
536 | ||
537 | cpu_mode_init(current_cpu_datap()); | |
538 | ||
539 | #if CONFIG_MCA | |
540 | mca_cpu_init(); | |
541 | #endif | |
542 | ||
543 | lapic_configure(); | |
544 | LAPIC_DUMP(); | |
545 | LAPIC_CPU_MAP_DUMP(); | |
546 | ||
547 | init_fpu(); | |
548 | ||
549 | mtrr_update_cpu(); | |
550 | } else | |
551 | init_param = FAST_SLAVE_INIT; | |
552 | ||
553 | #if CONFIG_VMX | |
554 | /* resume VT operation */ | |
555 | vmx_resume(); | |
556 | #endif | |
557 | ||
558 | if (!fast_restart) | |
559 | pat_init(); | |
560 | ||
561 | cpu_thread_init(); /* not strictly necessary */ | |
562 | ||
563 | #ifdef __x86_64__ | |
564 | /* Re-zero the identity-map for the idle PT's. This MUST be done before | |
565 | * cpu_running is set so that other slaves can set up their own | |
566 | * identity-map */ | |
567 | if (!fast_restart) | |
568 | IdlePML4[0] = 0; | |
569 | #endif | |
570 | ||
571 | cpu_init(); /* Sets cpu_running which starter cpu waits for */ | |
572 | ||
573 | slave_main(init_param); | |
574 | ||
575 | panic("do_init_slave() returned from slave_main()"); | |
576 | } | |
577 | ||
578 | /* | |
579 | * i386_init_slave() is called from pstart. | |
580 | * We're in the cpu's interrupt stack with interrupts disabled. | |
581 | * At this point we are in legacy mode. We need to switch on IA32e | |
582 | * if the mode is set to 64-bits. | |
583 | */ | |
584 | void | |
585 | i386_init_slave(void) | |
586 | { | |
587 | do_init_slave(FALSE); | |
588 | } | |
589 | ||
590 | /* | |
591 | * i386_init_slave_fast() is called from pmCPUHalt. | |
592 | * We're running on the idle thread and need to fix up | |
593 | * some accounting and get it so that the scheduler sees this | |
594 | * CPU again. | |
595 | */ | |
596 | void | |
597 | i386_init_slave_fast(void) | |
598 | { | |
599 | do_init_slave(TRUE); | |
600 | } | |
601 | ||
602 |