]>
Commit | Line | Data |
---|---|---|
55e303ae | 1 | /* |
39236c6e | 2 | * Copyright (c) 2003-2012 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 | 57 | #include <platforms.h> |
55e303ae A |
58 | |
59 | #include <mach/i386/vm_param.h> | |
60 | ||
61 | #include <string.h> | |
62 | #include <mach/vm_param.h> | |
63 | #include <mach/vm_prot.h> | |
64 | #include <mach/machine.h> | |
65 | #include <mach/time_value.h> | |
55e303ae A |
66 | #include <kern/spl.h> |
67 | #include <kern/assert.h> | |
68 | #include <kern/debug.h> | |
69 | #include <kern/misc_protos.h> | |
70 | #include <kern/startup.h> | |
71 | #include <kern/clock.h> | |
0c530ab8 | 72 | #include <kern/pms.h> |
55e303ae A |
73 | #include <kern/xpr.h> |
74 | #include <kern/cpu_data.h> | |
75 | #include <kern/processor.h> | |
0c530ab8 | 76 | #include <console/serial_protos.h> |
55e303ae A |
77 | #include <vm/vm_page.h> |
78 | #include <vm/pmap.h> | |
79 | #include <vm/vm_kern.h> | |
6d2010ae | 80 | #include <machine/pal_routines.h> |
55e303ae A |
81 | #include <i386/fpu.h> |
82 | #include <i386/pmap.h> | |
55e303ae | 83 | #include <i386/misc_protos.h> |
b0d623f7 | 84 | #include <i386/cpu_threads.h> |
55e303ae | 85 | #include <i386/cpuid.h> |
b0d623f7 | 86 | #include <i386/lapic.h> |
55e303ae | 87 | #include <i386/mp.h> |
0c530ab8 | 88 | #include <i386/mp_desc.h> |
6d2010ae | 89 | #if CONFIG_MTRR |
b0d623f7 | 90 | #include <i386/mtrr.h> |
6d2010ae | 91 | #endif |
91447636 | 92 | #include <i386/machine_routines.h> |
b0d623f7 | 93 | #if CONFIG_MCA |
0c530ab8 | 94 | #include <i386/machine_check.h> |
b0d623f7 | 95 | #endif |
6d2010ae | 96 | #include <i386/ucode.h> |
91447636 | 97 | #include <i386/postcode.h> |
0c530ab8 A |
98 | #include <i386/Diagnostics.h> |
99 | #include <i386/pmCPU.h> | |
100 | #include <i386/tsc.h> | |
2d21ac55 | 101 | #include <i386/locks.h> /* LcksOpts */ |
6d2010ae A |
102 | #if DEBUG |
103 | #include <machine/pal_routines.h> | |
104 | #endif | |
b0d623f7 A |
105 | #if DEBUG |
106 | #define DBG(x...) kprintf(x) | |
107 | #else | |
108 | #define DBG(x...) | |
109 | #endif | |
55e303ae | 110 | |
b0d623f7 A |
111 | int debug_task; |
112 | ||
113 | static boot_args *kernelBootArgs; | |
114 | ||
115 | extern int disableConsoleOutput; | |
116 | extern const char version[]; | |
117 | extern const char version_variant[]; | |
118 | extern int nx_enabled; | |
119 | ||
316670eb | 120 | uint64_t physmap_base, physmap_max; |
b0d623f7 | 121 | |
316670eb | 122 | pd_entry_t *KPTphys; |
b0d623f7 | 123 | pd_entry_t *IdlePTD; |
316670eb A |
124 | pdpt_entry_t *IdlePDPT; |
125 | pml4_entry_t *IdlePML4; | |
b0d623f7 | 126 | |
b0d623f7 A |
127 | char *physfree; |
128 | ||
129 | /* | |
130 | * Note: ALLOCPAGES() can only be used safely within Idle_PTs_init() | |
131 | * due to the mutation of physfree. | |
132 | */ | |
133 | static void * | |
134 | ALLOCPAGES(int npages) | |
135 | { | |
136 | uintptr_t tmp = (uintptr_t)physfree; | |
137 | bzero(physfree, npages * PAGE_SIZE); | |
138 | physfree += npages * PAGE_SIZE; | |
b0d623f7 | 139 | tmp += VM_MIN_KERNEL_ADDRESS & ~LOW_4GB_MASK; |
b0d623f7 A |
140 | return (void *)tmp; |
141 | } | |
142 | ||
143 | static void | |
144 | fillkpt(pt_entry_t *base, int prot, uintptr_t src, int index, int count) | |
145 | { | |
146 | int i; | |
147 | for (i=0; i<count; i++) { | |
148 | base[index] = src | prot | INTEL_PTE_VALID; | |
149 | src += PAGE_SIZE; | |
150 | index++; | |
151 | } | |
152 | } | |
153 | ||
6d2010ae | 154 | extern pmap_paddr_t first_avail; |
b0d623f7 | 155 | |
b0d623f7 A |
156 | int break_kprintf = 0; |
157 | ||
158 | uint64_t | |
159 | x86_64_pre_sleep(void) | |
160 | { | |
161 | IdlePML4[0] = IdlePML4[KERNEL_PML4_INDEX]; | |
6d2010ae A |
162 | uint64_t oldcr3 = get_cr3_raw(); |
163 | set_cr3_raw((uint32_t) (uintptr_t)ID_MAP_VTOP(IdlePML4)); | |
b0d623f7 A |
164 | return oldcr3; |
165 | } | |
166 | ||
167 | void | |
168 | x86_64_post_sleep(uint64_t new_cr3) | |
169 | { | |
170 | IdlePML4[0] = 0; | |
6d2010ae | 171 | set_cr3_raw((uint32_t) new_cr3); |
b0d623f7 A |
172 | } |
173 | ||
b0d623f7 | 174 | |
b0d623f7 | 175 | |
55e303ae | 176 | |
b0d623f7 A |
177 | // Set up the physical mapping - NPHYSMAP GB of memory mapped at a high address |
178 | // NPHYSMAP is determined by the maximum supported RAM size plus 4GB to account | |
179 | // the PCI hole (which is less 4GB but not more). | |
7ddcb079 | 180 | |
316670eb A |
181 | /* Compile-time guard: NPHYSMAP is capped to 256GiB, accounting for |
182 | * randomisation | |
183 | */ | |
184 | extern int maxphymapsupported[NPHYSMAP <= (PTE_PER_PAGE/2) ? 1 : -1]; | |
185 | ||
b0d623f7 A |
186 | static void |
187 | physmap_init(void) | |
188 | { | |
189 | pt_entry_t *physmapL3 = ALLOCPAGES(1); | |
190 | struct { | |
191 | pt_entry_t entries[PTE_PER_PAGE]; | |
192 | } * physmapL2 = ALLOCPAGES(NPHYSMAP); | |
193 | ||
316670eb A |
194 | uint64_t i; |
195 | uint8_t phys_random_L3 = ml_early_random() & 0xFF; | |
196 | ||
197 | /* We assume NX support. Mark all levels of the PHYSMAP NX | |
198 | * to avoid granting executability via a single bit flip. | |
199 | */ | |
200 | assert(cpuid_extfeatures() & CPUID_EXTFEATURE_XD); | |
201 | ||
202 | for(i = 0; i < NPHYSMAP; i++) { | |
203 | physmapL3[i + phys_random_L3] = | |
204 | ((uintptr_t)ID_MAP_VTOP(&physmapL2[i])) | |
b0d623f7 | 205 | | INTEL_PTE_VALID |
316670eb | 206 | | INTEL_PTE_NX |
b0d623f7 | 207 | | INTEL_PTE_WRITE; |
316670eb A |
208 | |
209 | uint64_t j; | |
210 | for(j = 0; j < PTE_PER_PAGE; j++) { | |
211 | physmapL2[i].entries[j] = | |
212 | ((i * PTE_PER_PAGE + j) << PDSHIFT) | |
b0d623f7 A |
213 | | INTEL_PTE_PS |
214 | | INTEL_PTE_VALID | |
316670eb A |
215 | | INTEL_PTE_NX |
216 | | INTEL_PTE_WRITE; | |
b0d623f7 A |
217 | } |
218 | } | |
219 | ||
316670eb A |
220 | IdlePML4[KERNEL_PHYSMAP_PML4_INDEX] = |
221 | ((uintptr_t)ID_MAP_VTOP(physmapL3)) | |
222 | | INTEL_PTE_VALID | |
223 | | INTEL_PTE_NX | |
224 | | INTEL_PTE_WRITE; | |
225 | ||
226 | physmap_base = KVADDR(KERNEL_PHYSMAP_PML4_INDEX, phys_random_L3, 0, 0); | |
227 | physmap_max = physmap_base + NPHYSMAP * GB; | |
228 | DBG("Physical address map base: 0x%qx\n", physmap_base); | |
229 | DBG("Physical map idlepml4[%d]: 0x%llx\n", | |
230 | KERNEL_PHYSMAP_PML4_INDEX, IdlePML4[KERNEL_PHYSMAP_PML4_INDEX]); | |
231 | } | |
6d2010ae | 232 | |
316670eb A |
233 | static void |
234 | descriptor_alias_init() | |
235 | { | |
236 | vm_offset_t master_gdt_phys; | |
237 | vm_offset_t master_gdt_alias_phys; | |
238 | vm_offset_t master_idt_phys; | |
239 | vm_offset_t master_idt_alias_phys; | |
240 | ||
241 | assert(((vm_offset_t)master_gdt & PAGE_MASK) == 0); | |
242 | assert(((vm_offset_t)master_idt64 & PAGE_MASK) == 0); | |
243 | ||
244 | master_gdt_phys = (vm_offset_t) ID_MAP_VTOP(master_gdt); | |
245 | master_idt_phys = (vm_offset_t) ID_MAP_VTOP(master_idt64); | |
246 | master_gdt_alias_phys = (vm_offset_t) ID_MAP_VTOP(MASTER_GDT_ALIAS); | |
247 | master_idt_alias_phys = (vm_offset_t) ID_MAP_VTOP(MASTER_IDT_ALIAS); | |
248 | ||
249 | DBG("master_gdt_phys: %p\n", (void *) master_gdt_phys); | |
250 | DBG("master_idt_phys: %p\n", (void *) master_idt_phys); | |
251 | DBG("master_gdt_alias_phys: %p\n", (void *) master_gdt_alias_phys); | |
252 | DBG("master_idt_alias_phys: %p\n", (void *) master_idt_alias_phys); | |
253 | ||
254 | KPTphys[atop_kernel(master_gdt_alias_phys)] = master_gdt_phys | | |
255 | INTEL_PTE_VALID | INTEL_PTE_NX | INTEL_PTE_WRITE; | |
256 | KPTphys[atop_kernel(master_idt_alias_phys)] = master_idt_phys | | |
257 | INTEL_PTE_VALID | INTEL_PTE_NX; /* read-only */ | |
b0d623f7 | 258 | } |
b0d623f7 A |
259 | |
260 | static void | |
261 | Idle_PTs_init(void) | |
262 | { | |
263 | /* Allocate the "idle" kernel page tables: */ | |
264 | KPTphys = ALLOCPAGES(NKPT); /* level 1 */ | |
265 | IdlePTD = ALLOCPAGES(NPGPTD); /* level 2 */ | |
316670eb A |
266 | IdlePDPT = ALLOCPAGES(1); /* level 3 */ |
267 | IdlePML4 = ALLOCPAGES(1); /* level 4 */ | |
268 | ||
269 | // Fill the lowest level with everything up to physfree | |
270 | fillkpt(KPTphys, | |
271 | INTEL_PTE_WRITE, 0, 0, (int)(((uintptr_t)physfree) >> PAGE_SHIFT)); | |
272 | ||
273 | /* IdlePTD */ | |
274 | fillkpt(IdlePTD, | |
275 | INTEL_PTE_WRITE, (uintptr_t)ID_MAP_VTOP(KPTphys), 0, NKPT); | |
276 | ||
277 | // IdlePDPT entries | |
278 | fillkpt(IdlePDPT, | |
279 | INTEL_PTE_WRITE, (uintptr_t)ID_MAP_VTOP(IdlePTD), 0, NPGPTD); | |
280 | ||
281 | // IdlePML4 single entry for kernel space. | |
282 | fillkpt(IdlePML4 + KERNEL_PML4_INDEX, | |
283 | INTEL_PTE_WRITE, (uintptr_t)ID_MAP_VTOP(IdlePDPT), 0, 1); | |
284 | ||
285 | postcode(VSTART_PHYSMAP_INIT); | |
b0d623f7 | 286 | |
b0d623f7 | 287 | physmap_init(); |
316670eb A |
288 | |
289 | postcode(VSTART_DESC_ALIAS_INIT); | |
290 | ||
291 | descriptor_alias_init(); | |
292 | ||
293 | postcode(VSTART_SET_CR3); | |
294 | ||
295 | // Switch to the page tables.. | |
296 | set_cr3_raw((uintptr_t)ID_MAP_VTOP(IdlePML4)); | |
297 | ||
298 | } | |
299 | ||
b0d623f7 A |
300 | |
301 | /* | |
302 | * vstart() is called in the natural mode (64bit for K64, 32 for K32) | |
303 | * on a set of bootstrap pagetables which use large, 2MB pages to map | |
304 | * all of physical memory in both. See idle_pt.c for details. | |
305 | * | |
306 | * In K64 this identity mapping is mirrored the top and bottom 512GB | |
307 | * slots of PML4. | |
308 | * | |
309 | * The bootstrap processor called with argument boot_args_start pointing to | |
310 | * the boot-args block. The kernel's (4K page) page tables are allocated and | |
311 | * initialized before switching to these. | |
312 | * | |
313 | * Non-bootstrap processors are called with argument boot_args_start NULL. | |
314 | * These processors switch immediately to the existing kernel page tables. | |
315 | */ | |
316 | void | |
317 | vstart(vm_offset_t boot_args_start) | |
318 | { | |
319 | boolean_t is_boot_cpu = !(boot_args_start == 0); | |
320 | int cpu; | |
316670eb | 321 | uint32_t lphysfree; |
b0d623f7 A |
322 | |
323 | postcode(VSTART_ENTRY); | |
324 | ||
325 | if (is_boot_cpu) { | |
326 | /* | |
327 | * Get startup parameters. | |
328 | */ | |
329 | kernelBootArgs = (boot_args *)boot_args_start; | |
330 | lphysfree = kernelBootArgs->kaddr + kernelBootArgs->ksize; | |
331 | physfree = (void *)(uintptr_t)((lphysfree + PAGE_SIZE - 1) &~ (PAGE_SIZE - 1)); | |
332 | #if DEBUG | |
6d2010ae | 333 | pal_serial_init(); |
b0d623f7 A |
334 | #endif |
335 | DBG("revision 0x%x\n", kernelBootArgs->Revision); | |
336 | DBG("version 0x%x\n", kernelBootArgs->Version); | |
337 | DBG("command line %s\n", kernelBootArgs->CommandLine); | |
338 | DBG("memory map 0x%x\n", kernelBootArgs->MemoryMap); | |
339 | DBG("memory map sz 0x%x\n", kernelBootArgs->MemoryMapSize); | |
340 | DBG("kaddr 0x%x\n", kernelBootArgs->kaddr); | |
341 | DBG("ksize 0x%x\n", kernelBootArgs->ksize); | |
342 | DBG("physfree %p\n", physfree); | |
343 | DBG("bootargs: %p, &ksize: %p &kaddr: %p\n", | |
344 | kernelBootArgs, | |
345 | &kernelBootArgs->ksize, | |
346 | &kernelBootArgs->kaddr); | |
316670eb A |
347 | |
348 | postcode(VSTART_IDLE_PTS_INIT); | |
b0d623f7 A |
349 | |
350 | Idle_PTs_init(); | |
351 | ||
352 | first_avail = (vm_offset_t)ID_MAP_VTOP(physfree); | |
353 | ||
354 | cpu = 0; | |
6d2010ae | 355 | cpu_data_alloc(TRUE); |
7ddcb079 A |
356 | |
357 | ||
358 | /* | |
359 | * Setup boot args given the physical start address. | |
360 | */ | |
361 | kernelBootArgs = (boot_args *) | |
362 | ml_static_ptovirt(boot_args_start); | |
363 | DBG("i386_init(0x%lx) kernelBootArgs=%p\n", | |
364 | (unsigned long)boot_args_start, kernelBootArgs); | |
365 | ||
366 | PE_init_platform(FALSE, kernelBootArgs); | |
367 | postcode(PE_INIT_PLATFORM_D); | |
b0d623f7 | 368 | } else { |
316670eb A |
369 | /* Switch to kernel's page tables (from the Boot PTs) */ |
370 | set_cr3_raw((uintptr_t)ID_MAP_VTOP(IdlePML4)); | |
b0d623f7 A |
371 | /* Find our logical cpu number */ |
372 | cpu = lapic_to_cpu[(LAPIC_READ(ID)>>LAPIC_ID_SHIFT) & LAPIC_ID_MASK]; | |
7ddcb079 | 373 | DBG("CPU: %d, GSBASE initial value: 0x%llx\n", cpu, rdmsr64(MSR_IA32_GS_BASE)); |
b0d623f7 | 374 | } |
8ad349bb | 375 | |
316670eb | 376 | postcode(VSTART_CPU_DESC_INIT); |
b0d623f7 A |
377 | if(is_boot_cpu) |
378 | cpu_desc_init64(cpu_datap(cpu)); | |
379 | cpu_desc_load64(cpu_datap(cpu)); | |
316670eb | 380 | postcode(VSTART_CPU_MODE_INIT); |
6d2010ae A |
381 | if (is_boot_cpu) |
382 | cpu_mode_init(current_cpu_datap()); /* cpu_mode_init() will be | |
383 | * invoked on the APs | |
384 | * via i386_init_slave() | |
385 | */ | |
b0d623f7 | 386 | postcode(VSTART_EXIT); |
316670eb A |
387 | x86_init_wrapper(is_boot_cpu ? (uintptr_t) i386_init |
388 | : (uintptr_t) i386_init_slave, | |
389 | cpu_datap(cpu)->cpu_int_stack_top); | |
b0d623f7 | 390 | } |
21362eb3 | 391 | |
55e303ae A |
392 | /* |
393 | * Cpu initialization. Running virtual, but without MACH VM | |
b0d623f7 | 394 | * set up. |
55e303ae A |
395 | */ |
396 | void | |
7ddcb079 | 397 | i386_init(void) |
55e303ae A |
398 | { |
399 | unsigned int maxmem; | |
0c530ab8 | 400 | uint64_t maxmemtouse; |
b0d623f7 | 401 | unsigned int cpus = 0; |
935ed37a | 402 | boolean_t fidn; |
b0d623f7 | 403 | boolean_t IA32e = TRUE; |
91447636 A |
404 | |
405 | postcode(I386_INIT_ENTRY); | |
55e303ae | 406 | |
6d2010ae A |
407 | pal_i386_init(); |
408 | ||
b0d623f7 | 409 | #if CONFIG_MCA |
0c530ab8 A |
410 | /* Initialize machine-check handling */ |
411 | mca_cpu_init(); | |
b0d623f7 | 412 | #endif |
4452a7af | 413 | |
0c530ab8 | 414 | master_cpu = 0; |
0c530ab8 | 415 | cpu_init(); |
b0d623f7 | 416 | |
0c530ab8 A |
417 | postcode(CPU_INIT_D); |
418 | ||
55e303ae A |
419 | printf_init(); /* Init this in case we need debugger */ |
420 | panic_init(); /* Init this in case we need debugger */ | |
421 | ||
422 | /* setup debugging output if one has been chosen */ | |
423 | PE_init_kprintf(FALSE); | |
55e303ae | 424 | |
39236c6e A |
425 | kernel_early_bootstrap(); |
426 | ||
593a1d5f | 427 | if (!PE_parse_boot_argn("diag", &dgWork.dgFlags, sizeof (dgWork.dgFlags))) |
0c530ab8 A |
428 | dgWork.dgFlags = 0; |
429 | ||
430 | serialmode = 0; | |
593a1d5f | 431 | if(PE_parse_boot_argn("serial", &serialmode, sizeof (serialmode))) { |
0c530ab8 A |
432 | /* We want a serial keyboard and/or console */ |
433 | kprintf("Serial mode specified: %08X\n", serialmode); | |
434 | } | |
435 | if(serialmode & 1) { | |
436 | (void)switch_to_serial_console(); | |
437 | disableConsoleOutput = FALSE; /* Allow printfs to happen */ | |
438 | } | |
439 | ||
55e303ae A |
440 | /* setup console output */ |
441 | PE_init_printf(FALSE); | |
442 | ||
443 | kprintf("version_variant = %s\n", version_variant); | |
444 | kprintf("version = %s\n", version); | |
2d21ac55 | 445 | |
593a1d5f A |
446 | if (!PE_parse_boot_argn("maxmem", &maxmem, sizeof (maxmem))) |
447 | maxmemtouse = 0; | |
55e303ae | 448 | else |
b0d623f7 | 449 | maxmemtouse = ((uint64_t)maxmem) * MB; |
55e303ae | 450 | |
593a1d5f | 451 | if (PE_parse_boot_argn("cpus", &cpus, sizeof (cpus))) { |
91447636 A |
452 | if ((0 < cpus) && (cpus < max_ncpus)) |
453 | max_ncpus = cpus; | |
454 | } | |
55e303ae | 455 | |
0c530ab8 A |
456 | /* |
457 | * debug support for > 4G systems | |
458 | */ | |
593a1d5f | 459 | if (!PE_parse_boot_argn("himemory_mode", &vm_himemory_mode, sizeof (vm_himemory_mode))) |
0c530ab8 A |
460 | vm_himemory_mode = 0; |
461 | ||
935ed37a | 462 | if (!PE_parse_boot_argn("immediate_NMI", &fidn, sizeof (fidn))) |
2d21ac55 | 463 | force_immediate_debugger_NMI = FALSE; |
935ed37a A |
464 | else |
465 | force_immediate_debugger_NMI = fidn; | |
6d2010ae A |
466 | |
467 | #if DEBUG | |
468 | nanoseconds_to_absolutetime(URGENCY_NOTIFICATION_ASSERT_NS, &urgency_notification_assert_abstime_threshold); | |
469 | #endif | |
470 | PE_parse_boot_argn("urgency_notification_abstime", | |
471 | &urgency_notification_assert_abstime_threshold, | |
472 | sizeof(urgency_notification_assert_abstime_threshold)); | |
473 | ||
0c530ab8 A |
474 | if (!(cpuid_extfeatures() & CPUID_EXTFEATURE_XD)) |
475 | nx_enabled = 0; | |
476 | ||
2d21ac55 A |
477 | /* |
478 | * VM initialization, after this we're using page tables... | |
479 | * The maximum number of cpus must be set beforehand. | |
480 | */ | |
0c530ab8 A |
481 | i386_vm_init(maxmemtouse, IA32e, kernelBootArgs); |
482 | ||
6d2010ae A |
483 | /* create the console for verbose or pretty mode */ |
484 | /* Note: doing this prior to tsc_init() allows for graceful panic! */ | |
485 | PE_init_platform(TRUE, kernelBootArgs); | |
486 | PE_create_console(); | |
0c530ab8 | 487 | |
0b4c1975 A |
488 | tsc_init(); |
489 | power_management_init(); | |
0c530ab8 A |
490 | processor_bootstrap(); |
491 | thread_bootstrap(); | |
492 | ||
55e303ae | 493 | machine_startup(); |
55e303ae | 494 | } |
b0d623f7 A |
495 | |
496 | static void | |
497 | do_init_slave(boolean_t fast_restart) | |
498 | { | |
499 | void *init_param = FULL_SLAVE_INIT; | |
500 | ||
501 | postcode(I386_INIT_SLAVE); | |
502 | ||
503 | if (!fast_restart) { | |
504 | /* Ensure that caching and write-through are enabled */ | |
505 | set_cr0(get_cr0() & ~(CR0_NW|CR0_CD)); | |
506 | ||
507 | DBG("i386_init_slave() CPU%d: phys (%d) active.\n", | |
508 | get_cpu_number(), get_cpu_phys_number()); | |
509 | ||
510 | assert(!ml_get_interrupts_enabled()); | |
511 | ||
512 | cpu_mode_init(current_cpu_datap()); | |
316670eb | 513 | pmap_cpu_init(); |
b0d623f7 A |
514 | |
515 | #if CONFIG_MCA | |
516 | mca_cpu_init(); | |
517 | #endif | |
518 | ||
bd504ef0 | 519 | LAPIC_INIT(); |
b0d623f7 A |
520 | lapic_configure(); |
521 | LAPIC_DUMP(); | |
522 | LAPIC_CPU_MAP_DUMP(); | |
523 | ||
524 | init_fpu(); | |
525 | ||
6d2010ae | 526 | #if CONFIG_MTRR |
b0d623f7 | 527 | mtrr_update_cpu(); |
6d2010ae | 528 | #endif |
bd504ef0 A |
529 | /* update CPU microcode */ |
530 | ucode_update_wake(); | |
b0d623f7 A |
531 | } else |
532 | init_param = FAST_SLAVE_INIT; | |
533 | ||
534 | #if CONFIG_VMX | |
535 | /* resume VT operation */ | |
536 | vmx_resume(); | |
537 | #endif | |
538 | ||
6d2010ae | 539 | #if CONFIG_MTRR |
b0d623f7 A |
540 | if (!fast_restart) |
541 | pat_init(); | |
6d2010ae | 542 | #endif |
b0d623f7 A |
543 | |
544 | cpu_thread_init(); /* not strictly necessary */ | |
545 | ||
39236c6e | 546 | cpu_init(); /* Sets cpu_running which starter cpu waits for */ |
b0d623f7 A |
547 | slave_main(init_param); |
548 | ||
549 | panic("do_init_slave() returned from slave_main()"); | |
550 | } | |
551 | ||
552 | /* | |
553 | * i386_init_slave() is called from pstart. | |
554 | * We're in the cpu's interrupt stack with interrupts disabled. | |
555 | * At this point we are in legacy mode. We need to switch on IA32e | |
556 | * if the mode is set to 64-bits. | |
557 | */ | |
558 | void | |
559 | i386_init_slave(void) | |
560 | { | |
561 | do_init_slave(FALSE); | |
562 | } | |
563 | ||
564 | /* | |
565 | * i386_init_slave_fast() is called from pmCPUHalt. | |
566 | * We're running on the idle thread and need to fix up | |
567 | * some accounting and get it so that the scheduler sees this | |
568 | * CPU again. | |
569 | */ | |
570 | void | |
571 | i386_init_slave_fast(void) | |
572 | { | |
573 | do_init_slave(TRUE); | |
574 | } | |
575 | ||
576 |