]>
Commit | Line | Data |
---|---|---|
1c79356b | 1 | /* |
39236c6e | 2 | * Copyright (c) 2000-2012 Apple Inc. All rights reserved. |
1c79356b | 3 | * |
2d21ac55 | 4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
1c79356b | 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@ |
1c79356b | 27 | */ |
2d21ac55 | 28 | |
1c79356b A |
29 | #include <i386/machine_routines.h> |
30 | #include <i386/io_map_entries.h> | |
55e303ae A |
31 | #include <i386/cpuid.h> |
32 | #include <i386/fpu.h> | |
2d21ac55 | 33 | #include <mach/processor.h> |
55e303ae | 34 | #include <kern/processor.h> |
91447636 | 35 | #include <kern/machine.h> |
39037602 | 36 | |
91447636 A |
37 | #include <kern/cpu_number.h> |
38 | #include <kern/thread.h> | |
39236c6e | 39 | #include <kern/thread_call.h> |
39037602 A |
40 | #include <kern/policy_internal.h> |
41 | ||
fe8ab488 | 42 | #include <prng/random.h> |
55e303ae | 43 | #include <i386/machine_cpu.h> |
593a1d5f | 44 | #include <i386/lapic.h> |
fe8ab488 | 45 | #include <i386/bit_routines.h> |
55e303ae | 46 | #include <i386/mp_events.h> |
0c530ab8 | 47 | #include <i386/pmCPU.h> |
6d2010ae | 48 | #include <i386/trap.h> |
2d21ac55 A |
49 | #include <i386/tsc.h> |
50 | #include <i386/cpu_threads.h> | |
b0d623f7 | 51 | #include <i386/proc_reg.h> |
91447636 | 52 | #include <mach/vm_param.h> |
b0d623f7 | 53 | #include <i386/pmap.h> |
316670eb | 54 | #include <i386/pmap_internal.h> |
b0d623f7 | 55 | #include <i386/misc_protos.h> |
39236c6e A |
56 | #include <kern/timer_queue.h> |
57 | #if KPC | |
58 | #include <kern/kpc.h> | |
59 | #endif | |
fe8ab488 | 60 | #include <architecture/i386/pio.h> |
39037602 | 61 | #include <i386/cpu_data.h> |
0c530ab8 A |
62 | #if DEBUG |
63 | #define DBG(x...) kprintf("DBG: " x) | |
64 | #else | |
65 | #define DBG(x...) | |
66 | #endif | |
67 | ||
5ba3f43e A |
68 | #if MONOTONIC |
69 | #include <kern/monotonic.h> | |
70 | #endif /* MONOTONIC */ | |
71 | ||
91447636 | 72 | extern void wakeup(void *); |
55e303ae A |
73 | |
74 | static int max_cpus_initialized = 0; | |
75 | ||
39037602 A |
76 | uint64_t LockTimeOut; |
77 | uint64_t TLBTimeOut; | |
78 | uint64_t LockTimeOutTSC; | |
79 | uint32_t LockTimeOutUsec; | |
80 | uint64_t MutexSpin; | |
b0d623f7 | 81 | uint64_t LastDebuggerEntryAllowance; |
316670eb | 82 | uint64_t delay_spin_threshold; |
0c530ab8 | 83 | |
6d2010ae A |
84 | extern uint64_t panic_restart_timeout; |
85 | ||
86 | boolean_t virtualized = FALSE; | |
87 | ||
39236c6e A |
88 | decl_simple_lock_data(static, ml_timer_evaluation_slock); |
89 | uint32_t ml_timer_eager_evaluations; | |
90 | uint64_t ml_timer_eager_evaluation_max; | |
91 | static boolean_t ml_timer_evaluation_in_progress = FALSE; | |
92 | ||
93 | ||
55e303ae A |
94 | #define MAX_CPUS_SET 0x1 |
95 | #define MAX_CPUS_WAIT 0x2 | |
1c79356b A |
96 | |
97 | /* IO memory map services */ | |
98 | ||
99 | /* Map memory map IO space */ | |
100 | vm_offset_t ml_io_map( | |
101 | vm_offset_t phys_addr, | |
102 | vm_size_t size) | |
103 | { | |
0c530ab8 | 104 | return(io_map(phys_addr,size,VM_WIMG_IO)); |
1c79356b A |
105 | } |
106 | ||
107 | /* boot memory allocation */ | |
108 | vm_offset_t ml_static_malloc( | |
91447636 | 109 | __unused vm_size_t size) |
1c79356b A |
110 | { |
111 | return((vm_offset_t)NULL); | |
112 | } | |
113 | ||
0c530ab8 A |
114 | |
115 | void ml_get_bouncepool_info(vm_offset_t *phys_addr, vm_size_t *size) | |
116 | { | |
0b4c1975 A |
117 | *phys_addr = 0; |
118 | *size = 0; | |
0c530ab8 A |
119 | } |
120 | ||
121 | ||
1c79356b A |
122 | vm_offset_t |
123 | ml_static_ptovirt( | |
124 | vm_offset_t paddr) | |
125 | { | |
b0d623f7 A |
126 | #if defined(__x86_64__) |
127 | return (vm_offset_t)(((unsigned long) paddr) | VM_MIN_KERNEL_ADDRESS); | |
128 | #else | |
129 | return (vm_offset_t)((paddr) | LINEAR_KERNEL_ADDRESS); | |
130 | #endif | |
1c79356b A |
131 | } |
132 | ||
91447636 A |
133 | |
134 | /* | |
135 | * Routine: ml_static_mfree | |
136 | * Function: | |
137 | */ | |
1c79356b A |
138 | void |
139 | ml_static_mfree( | |
91447636 A |
140 | vm_offset_t vaddr, |
141 | vm_size_t size) | |
1c79356b | 142 | { |
b0d623f7 | 143 | addr64_t vaddr_cur; |
91447636 | 144 | ppnum_t ppn; |
316670eb | 145 | uint32_t freed_pages = 0; |
b0d623f7 | 146 | assert(vaddr >= VM_MIN_KERNEL_ADDRESS); |
91447636 A |
147 | |
148 | assert((vaddr & (PAGE_SIZE-1)) == 0); /* must be page aligned */ | |
149 | ||
150 | for (vaddr_cur = vaddr; | |
316670eb | 151 | vaddr_cur < round_page_64(vaddr+size); |
91447636 | 152 | vaddr_cur += PAGE_SIZE) { |
b0d623f7 | 153 | ppn = pmap_find_phys(kernel_pmap, vaddr_cur); |
91447636 | 154 | if (ppn != (vm_offset_t)NULL) { |
2d21ac55 A |
155 | kernel_pmap->stats.resident_count++; |
156 | if (kernel_pmap->stats.resident_count > | |
157 | kernel_pmap->stats.resident_max) { | |
158 | kernel_pmap->stats.resident_max = | |
159 | kernel_pmap->stats.resident_count; | |
160 | } | |
b0d623f7 | 161 | pmap_remove(kernel_pmap, vaddr_cur, vaddr_cur+PAGE_SIZE); |
316670eb | 162 | assert(pmap_valid_page(ppn)); |
316670eb A |
163 | if (IS_MANAGED_PAGE(ppn)) { |
164 | vm_page_create(ppn,(ppn+1)); | |
316670eb A |
165 | freed_pages++; |
166 | } | |
91447636 A |
167 | } |
168 | } | |
3e170ce0 A |
169 | vm_page_lockspin_queues(); |
170 | vm_page_wire_count -= freed_pages; | |
171 | vm_page_wire_count_initial -= freed_pages; | |
172 | vm_page_unlock_queues(); | |
173 | ||
316670eb A |
174 | #if DEBUG |
175 | kprintf("ml_static_mfree: Released 0x%x pages at VA %p, size:0x%llx, last ppn: 0x%x\n", freed_pages, (void *)vaddr, (uint64_t)size, ppn); | |
176 | #endif | |
1c79356b A |
177 | } |
178 | ||
0c530ab8 | 179 | |
1c79356b A |
180 | /* virtual to physical on wired pages */ |
181 | vm_offset_t ml_vtophys( | |
182 | vm_offset_t vaddr) | |
183 | { | |
b0d623f7 | 184 | return (vm_offset_t)kvtophys(vaddr); |
1c79356b A |
185 | } |
186 | ||
2d21ac55 A |
187 | /* |
188 | * Routine: ml_nofault_copy | |
189 | * Function: Perform a physical mode copy if the source and | |
190 | * destination have valid translations in the kernel pmap. | |
191 | * If translations are present, they are assumed to | |
192 | * be wired; i.e. no attempt is made to guarantee that the | |
193 | * translations obtained remained valid for | |
194 | * the duration of the copy process. | |
195 | */ | |
196 | ||
197 | vm_size_t ml_nofault_copy( | |
198 | vm_offset_t virtsrc, vm_offset_t virtdst, vm_size_t size) | |
199 | { | |
200 | addr64_t cur_phys_dst, cur_phys_src; | |
201 | uint32_t count, nbytes = 0; | |
202 | ||
203 | while (size > 0) { | |
204 | if (!(cur_phys_src = kvtophys(virtsrc))) | |
205 | break; | |
206 | if (!(cur_phys_dst = kvtophys(virtdst))) | |
207 | break; | |
208 | if (!pmap_valid_page(i386_btop(cur_phys_dst)) || !pmap_valid_page(i386_btop(cur_phys_src))) | |
209 | break; | |
b0d623f7 | 210 | count = (uint32_t)(PAGE_SIZE - (cur_phys_src & PAGE_MASK)); |
2d21ac55 | 211 | if (count > (PAGE_SIZE - (cur_phys_dst & PAGE_MASK))) |
b0d623f7 | 212 | count = (uint32_t)(PAGE_SIZE - (cur_phys_dst & PAGE_MASK)); |
2d21ac55 | 213 | if (count > size) |
b0d623f7 | 214 | count = (uint32_t)size; |
2d21ac55 A |
215 | |
216 | bcopy_phys(cur_phys_src, cur_phys_dst, count); | |
217 | ||
218 | nbytes += count; | |
219 | virtsrc += count; | |
220 | virtdst += count; | |
221 | size -= count; | |
222 | } | |
223 | ||
224 | return nbytes; | |
225 | } | |
226 | ||
39236c6e A |
227 | /* |
228 | * Routine: ml_validate_nofault | |
229 | * Function: Validate that ths address range has a valid translations | |
230 | * in the kernel pmap. If translations are present, they are | |
231 | * assumed to be wired; i.e. no attempt is made to guarantee | |
232 | * that the translation persist after the check. | |
233 | * Returns: TRUE if the range is mapped and will not cause a fault, | |
234 | * FALSE otherwise. | |
235 | */ | |
236 | ||
237 | boolean_t ml_validate_nofault( | |
238 | vm_offset_t virtsrc, vm_size_t size) | |
239 | { | |
240 | addr64_t cur_phys_src; | |
241 | uint32_t count; | |
242 | ||
243 | while (size > 0) { | |
244 | if (!(cur_phys_src = kvtophys(virtsrc))) | |
245 | return FALSE; | |
246 | if (!pmap_valid_page(i386_btop(cur_phys_src))) | |
247 | return FALSE; | |
248 | count = (uint32_t)(PAGE_SIZE - (cur_phys_src & PAGE_MASK)); | |
249 | if (count > size) | |
250 | count = (uint32_t)size; | |
251 | ||
252 | virtsrc += count; | |
253 | size -= count; | |
254 | } | |
255 | ||
256 | return TRUE; | |
257 | } | |
258 | ||
1c79356b A |
259 | /* Interrupt handling */ |
260 | ||
55e303ae A |
261 | /* Initialize Interrupts */ |
262 | void ml_init_interrupt(void) | |
263 | { | |
264 | (void) ml_set_interrupts_enabled(TRUE); | |
265 | } | |
266 | ||
b0d623f7 | 267 | |
1c79356b A |
268 | /* Get Interrupts Enabled */ |
269 | boolean_t ml_get_interrupts_enabled(void) | |
270 | { | |
271 | unsigned long flags; | |
272 | ||
b0d623f7 | 273 | __asm__ volatile("pushf; pop %0" : "=r" (flags)); |
1c79356b A |
274 | return (flags & EFL_IF) != 0; |
275 | } | |
276 | ||
277 | /* Set Interrupts Enabled */ | |
278 | boolean_t ml_set_interrupts_enabled(boolean_t enable) | |
279 | { | |
6d2010ae A |
280 | unsigned long flags; |
281 | boolean_t istate; | |
282 | ||
283 | __asm__ volatile("pushf; pop %0" : "=r" (flags)); | |
1c79356b | 284 | |
39236c6e A |
285 | assert(get_interrupt_level() ? (enable == FALSE) : TRUE); |
286 | ||
6d2010ae | 287 | istate = ((flags & EFL_IF) != 0); |
0c530ab8 | 288 | |
6d2010ae A |
289 | if (enable) { |
290 | __asm__ volatile("sti;nop"); | |
0c530ab8 | 291 | |
6d2010ae | 292 | if ((get_preemption_level() == 0) && (*ast_pending() & AST_URGENT)) |
fe8ab488 | 293 | __asm__ volatile ("int %0" :: "N" (T_PREEMPT)); |
6d2010ae A |
294 | } |
295 | else { | |
296 | if (istate) | |
297 | __asm__ volatile("cli"); | |
0c530ab8 | 298 | } |
1c79356b | 299 | |
6d2010ae | 300 | return istate; |
1c79356b A |
301 | } |
302 | ||
303 | /* Check if running at interrupt context */ | |
304 | boolean_t ml_at_interrupt_context(void) | |
305 | { | |
306 | return get_interrupt_level() != 0; | |
307 | } | |
308 | ||
4b17d6b6 A |
309 | void ml_get_power_state(boolean_t *icp, boolean_t *pidlep) { |
310 | *icp = (get_interrupt_level() != 0); | |
311 | /* These will be technically inaccurate for interrupts that occur | |
312 | * successively within a single "idle exit" event, but shouldn't | |
313 | * matter statistically. | |
314 | */ | |
315 | *pidlep = (current_cpu_datap()->lcpu.package->num_idle == topoParms.nLThreadsPerPackage); | |
316 | } | |
317 | ||
1c79356b A |
318 | /* Generate a fake interrupt */ |
319 | void ml_cause_interrupt(void) | |
320 | { | |
321 | panic("ml_cause_interrupt not defined yet on Intel"); | |
322 | } | |
323 | ||
fe8ab488 A |
324 | /* |
325 | * TODO: transition users of this to kernel_thread_start_priority | |
326 | * ml_thread_policy is an unsupported KPI | |
327 | */ | |
d52fe63f A |
328 | void ml_thread_policy( |
329 | thread_t thread, | |
2d21ac55 | 330 | __unused unsigned policy_id, |
d52fe63f A |
331 | unsigned policy_info) |
332 | { | |
55e303ae | 333 | if (policy_info & MACHINE_NETWORK_WORKLOOP) { |
fe8ab488 A |
334 | thread_precedence_policy_data_t info; |
335 | __assert_only kern_return_t kret; | |
55e303ae | 336 | |
fe8ab488 | 337 | info.importance = 1; |
55e303ae | 338 | |
fe8ab488 A |
339 | kret = thread_policy_set_internal(thread, THREAD_PRECEDENCE_POLICY, |
340 | (thread_policy_t)&info, | |
341 | THREAD_PRECEDENCE_POLICY_COUNT); | |
342 | assert(kret == KERN_SUCCESS); | |
55e303ae | 343 | } |
d52fe63f A |
344 | } |
345 | ||
1c79356b A |
346 | /* Initialize Interrupts */ |
347 | void ml_install_interrupt_handler( | |
348 | void *nub, | |
349 | int source, | |
350 | void *target, | |
351 | IOInterruptHandler handler, | |
352 | void *refCon) | |
353 | { | |
354 | boolean_t current_state; | |
355 | ||
5ba3f43e | 356 | current_state = ml_set_interrupts_enabled(FALSE); |
1c79356b A |
357 | |
358 | PE_install_interrupt_handler(nub, source, target, | |
359 | (IOInterruptHandler) handler, refCon); | |
360 | ||
361 | (void) ml_set_interrupts_enabled(current_state); | |
55e303ae | 362 | |
2d21ac55 | 363 | initialize_screen(NULL, kPEAcquireScreen); |
55e303ae A |
364 | } |
365 | ||
91447636 | 366 | |
1c79356b A |
367 | void |
368 | machine_signal_idle( | |
369 | processor_t processor) | |
370 | { | |
b0d623f7 | 371 | cpu_interrupt(processor->cpu_id); |
55e303ae A |
372 | } |
373 | ||
3e170ce0 A |
374 | void |
375 | machine_signal_idle_deferred( | |
376 | __unused processor_t processor) | |
377 | { | |
378 | panic("Unimplemented"); | |
379 | } | |
380 | ||
381 | void | |
382 | machine_signal_idle_cancel( | |
383 | __unused processor_t processor) | |
384 | { | |
385 | panic("Unimplemented"); | |
386 | } | |
387 | ||
b0d623f7 A |
388 | static kern_return_t |
389 | register_cpu( | |
390 | uint32_t lapic_id, | |
391 | processor_t *processor_out, | |
392 | boolean_t boot_cpu ) | |
55e303ae | 393 | { |
55e303ae | 394 | int target_cpu; |
91447636 | 395 | cpu_data_t *this_cpu_datap; |
55e303ae | 396 | |
91447636 A |
397 | this_cpu_datap = cpu_data_alloc(boot_cpu); |
398 | if (this_cpu_datap == NULL) { | |
55e303ae | 399 | return KERN_FAILURE; |
91447636 A |
400 | } |
401 | target_cpu = this_cpu_datap->cpu_number; | |
55e303ae A |
402 | assert((boot_cpu && (target_cpu == 0)) || |
403 | (!boot_cpu && (target_cpu != 0))); | |
404 | ||
405 | lapic_cpu_map(lapic_id, target_cpu); | |
91447636 | 406 | |
b0d623f7 A |
407 | /* The cpu_id is not known at registration phase. Just do |
408 | * lapic_id for now | |
409 | */ | |
91447636 A |
410 | this_cpu_datap->cpu_phys_number = lapic_id; |
411 | ||
412 | this_cpu_datap->cpu_console_buf = console_cpu_alloc(boot_cpu); | |
413 | if (this_cpu_datap->cpu_console_buf == NULL) | |
414 | goto failed; | |
415 | ||
0c530ab8 A |
416 | this_cpu_datap->cpu_chud = chudxnu_cpu_alloc(boot_cpu); |
417 | if (this_cpu_datap->cpu_chud == NULL) | |
418 | goto failed; | |
419 | ||
39236c6e | 420 | #if KPC |
3e170ce0 | 421 | if (kpc_register_cpu(this_cpu_datap) != TRUE) |
39236c6e A |
422 | goto failed; |
423 | #endif | |
424 | ||
91447636 | 425 | if (!boot_cpu) { |
593a1d5f | 426 | cpu_thread_alloc(this_cpu_datap->cpu_number); |
2d21ac55 A |
427 | if (this_cpu_datap->lcpu.core == NULL) |
428 | goto failed; | |
429 | ||
b0d623f7 | 430 | #if NCOPY_WINDOWS > 0 |
91447636 A |
431 | this_cpu_datap->cpu_pmap = pmap_cpu_alloc(boot_cpu); |
432 | if (this_cpu_datap->cpu_pmap == NULL) | |
433 | goto failed; | |
b0d623f7 | 434 | #endif |
91447636 A |
435 | |
436 | this_cpu_datap->cpu_processor = cpu_processor_alloc(boot_cpu); | |
437 | if (this_cpu_datap->cpu_processor == NULL) | |
438 | goto failed; | |
2d21ac55 A |
439 | /* |
440 | * processor_init() deferred to topology start | |
441 | * because "slot numbers" a.k.a. logical processor numbers | |
442 | * are not yet finalized. | |
443 | */ | |
91447636 A |
444 | } |
445 | ||
446 | *processor_out = this_cpu_datap->cpu_processor; | |
2d21ac55 | 447 | |
55e303ae | 448 | return KERN_SUCCESS; |
91447636 A |
449 | |
450 | failed: | |
451 | cpu_processor_free(this_cpu_datap->cpu_processor); | |
b0d623f7 | 452 | #if NCOPY_WINDOWS > 0 |
91447636 | 453 | pmap_cpu_free(this_cpu_datap->cpu_pmap); |
b0d623f7 | 454 | #endif |
0c530ab8 | 455 | chudxnu_cpu_free(this_cpu_datap->cpu_chud); |
91447636 | 456 | console_cpu_free(this_cpu_datap->cpu_console_buf); |
39236c6e | 457 | #if KPC |
39037602 | 458 | kpc_unregister_cpu(this_cpu_datap); |
39236c6e A |
459 | #endif |
460 | ||
91447636 | 461 | return KERN_FAILURE; |
1c79356b A |
462 | } |
463 | ||
b0d623f7 A |
464 | |
465 | kern_return_t | |
466 | ml_processor_register( | |
467 | cpu_id_t cpu_id, | |
468 | uint32_t lapic_id, | |
469 | processor_t *processor_out, | |
470 | boolean_t boot_cpu, | |
471 | boolean_t start ) | |
472 | { | |
473 | static boolean_t done_topo_sort = FALSE; | |
474 | static uint32_t num_registered = 0; | |
475 | ||
476 | /* Register all CPUs first, and track max */ | |
477 | if( start == FALSE ) | |
478 | { | |
479 | num_registered++; | |
480 | ||
481 | DBG( "registering CPU lapic id %d\n", lapic_id ); | |
482 | ||
483 | return register_cpu( lapic_id, processor_out, boot_cpu ); | |
484 | } | |
485 | ||
486 | /* Sort by topology before we start anything */ | |
487 | if( !done_topo_sort ) | |
488 | { | |
489 | DBG( "about to start CPUs. %d registered\n", num_registered ); | |
490 | ||
491 | cpu_topology_sort( num_registered ); | |
492 | done_topo_sort = TRUE; | |
493 | } | |
494 | ||
495 | /* Assign the cpu ID */ | |
496 | uint32_t cpunum = -1; | |
497 | cpu_data_t *this_cpu_datap = NULL; | |
498 | ||
499 | /* find cpu num and pointer */ | |
500 | cpunum = ml_get_cpuid( lapic_id ); | |
501 | ||
502 | if( cpunum == 0xFFFFFFFF ) /* never heard of it? */ | |
503 | panic( "trying to start invalid/unregistered CPU %d\n", lapic_id ); | |
504 | ||
505 | this_cpu_datap = cpu_datap(cpunum); | |
506 | ||
507 | /* fix the CPU id */ | |
508 | this_cpu_datap->cpu_id = cpu_id; | |
509 | ||
fe8ab488 A |
510 | /* allocate and initialize other per-cpu structures */ |
511 | if (!boot_cpu) { | |
512 | mp_cpus_call_cpu_init(cpunum); | |
513 | prng_cpu_init(cpunum); | |
514 | } | |
515 | ||
b0d623f7 A |
516 | /* output arg */ |
517 | *processor_out = this_cpu_datap->cpu_processor; | |
518 | ||
519 | /* OK, try and start this CPU */ | |
520 | return cpu_topology_start_cpu( cpunum ); | |
521 | } | |
522 | ||
523 | ||
43866e37 | 524 | void |
91447636 | 525 | ml_cpu_get_info(ml_cpu_info_t *cpu_infop) |
43866e37 | 526 | { |
55e303ae A |
527 | boolean_t os_supports_sse; |
528 | i386_cpu_info_t *cpuid_infop; | |
529 | ||
91447636 | 530 | if (cpu_infop == NULL) |
55e303ae A |
531 | return; |
532 | ||
533 | /* | |
0c530ab8 | 534 | * Are we supporting MMX/SSE/SSE2/SSE3? |
55e303ae A |
535 | * As distinct from whether the cpu has these capabilities. |
536 | */ | |
060df5ea | 537 | os_supports_sse = !!(get_cr4() & CR4_OSXMM); |
6d2010ae A |
538 | |
539 | if (ml_fpu_avx_enabled()) | |
540 | cpu_infop->vector_unit = 9; | |
541 | else if ((cpuid_features() & CPUID_FEATURE_SSE4_2) && os_supports_sse) | |
2d21ac55 A |
542 | cpu_infop->vector_unit = 8; |
543 | else if ((cpuid_features() & CPUID_FEATURE_SSE4_1) && os_supports_sse) | |
544 | cpu_infop->vector_unit = 7; | |
545 | else if ((cpuid_features() & CPUID_FEATURE_SSSE3) && os_supports_sse) | |
0c530ab8 A |
546 | cpu_infop->vector_unit = 6; |
547 | else if ((cpuid_features() & CPUID_FEATURE_SSE3) && os_supports_sse) | |
548 | cpu_infop->vector_unit = 5; | |
549 | else if ((cpuid_features() & CPUID_FEATURE_SSE2) && os_supports_sse) | |
91447636 | 550 | cpu_infop->vector_unit = 4; |
55e303ae | 551 | else if ((cpuid_features() & CPUID_FEATURE_SSE) && os_supports_sse) |
91447636 | 552 | cpu_infop->vector_unit = 3; |
55e303ae | 553 | else if (cpuid_features() & CPUID_FEATURE_MMX) |
91447636 | 554 | cpu_infop->vector_unit = 2; |
55e303ae | 555 | else |
91447636 | 556 | cpu_infop->vector_unit = 0; |
55e303ae A |
557 | |
558 | cpuid_infop = cpuid_info(); | |
559 | ||
91447636 | 560 | cpu_infop->cache_line_size = cpuid_infop->cache_linesize; |
55e303ae | 561 | |
91447636 A |
562 | cpu_infop->l1_icache_size = cpuid_infop->cache_size[L1I]; |
563 | cpu_infop->l1_dcache_size = cpuid_infop->cache_size[L1D]; | |
55e303ae | 564 | |
91447636 A |
565 | if (cpuid_infop->cache_size[L2U] > 0) { |
566 | cpu_infop->l2_settings = 1; | |
567 | cpu_infop->l2_cache_size = cpuid_infop->cache_size[L2U]; | |
568 | } else { | |
569 | cpu_infop->l2_settings = 0; | |
570 | cpu_infop->l2_cache_size = 0xFFFFFFFF; | |
571 | } | |
55e303ae | 572 | |
91447636 | 573 | if (cpuid_infop->cache_size[L3U] > 0) { |
0c530ab8 A |
574 | cpu_infop->l3_settings = 1; |
575 | cpu_infop->l3_cache_size = cpuid_infop->cache_size[L3U]; | |
91447636 A |
576 | } else { |
577 | cpu_infop->l3_settings = 0; | |
578 | cpu_infop->l3_cache_size = 0xFFFFFFFF; | |
579 | } | |
43866e37 A |
580 | } |
581 | ||
582 | void | |
583 | ml_init_max_cpus(unsigned long max_cpus) | |
584 | { | |
55e303ae A |
585 | boolean_t current_state; |
586 | ||
587 | current_state = ml_set_interrupts_enabled(FALSE); | |
588 | if (max_cpus_initialized != MAX_CPUS_SET) { | |
91447636 A |
589 | if (max_cpus > 0 && max_cpus <= MAX_CPUS) { |
590 | /* | |
2d21ac55 | 591 | * Note: max_cpus is the number of enabled processors |
91447636 A |
592 | * that ACPI found; max_ncpus is the maximum number |
593 | * that the kernel supports or that the "cpus=" | |
594 | * boot-arg has set. Here we take int minimum. | |
595 | */ | |
b0d623f7 | 596 | machine_info.max_cpus = (integer_t)MIN(max_cpus, max_ncpus); |
91447636 | 597 | } |
55e303ae A |
598 | if (max_cpus_initialized == MAX_CPUS_WAIT) |
599 | wakeup((event_t)&max_cpus_initialized); | |
600 | max_cpus_initialized = MAX_CPUS_SET; | |
601 | } | |
602 | (void) ml_set_interrupts_enabled(current_state); | |
43866e37 A |
603 | } |
604 | ||
605 | int | |
606 | ml_get_max_cpus(void) | |
607 | { | |
55e303ae | 608 | boolean_t current_state; |
43866e37 | 609 | |
55e303ae A |
610 | current_state = ml_set_interrupts_enabled(FALSE); |
611 | if (max_cpus_initialized != MAX_CPUS_SET) { | |
612 | max_cpus_initialized = MAX_CPUS_WAIT; | |
613 | assert_wait((event_t)&max_cpus_initialized, THREAD_UNINT); | |
614 | (void)thread_block(THREAD_CONTINUE_NULL); | |
615 | } | |
616 | (void) ml_set_interrupts_enabled(current_state); | |
617 | return(machine_info.max_cpus); | |
43866e37 | 618 | } |
5ba3f43e A |
619 | |
620 | boolean_t | |
621 | ml_wants_panic_trap_to_debugger(void) | |
622 | { | |
623 | return FALSE; | |
624 | } | |
625 | ||
626 | void | |
627 | ml_panic_trap_to_debugger(__unused const char *panic_format_str, | |
628 | __unused va_list *panic_args, | |
629 | __unused unsigned int reason, | |
630 | __unused void *ctx, | |
631 | __unused uint64_t panic_options_mask, | |
632 | __unused unsigned long panic_caller) | |
633 | { | |
634 | return; | |
635 | } | |
636 | ||
0c530ab8 A |
637 | /* |
638 | * Routine: ml_init_lock_timeout | |
639 | * Function: | |
640 | */ | |
641 | void | |
642 | ml_init_lock_timeout(void) | |
643 | { | |
644 | uint64_t abstime; | |
b0d623f7 | 645 | uint32_t mtxspin; |
143464d5 | 646 | #if DEVELOPMENT || DEBUG |
b0d623f7 | 647 | uint64_t default_timeout_ns = NSEC_PER_SEC>>2; |
143464d5 A |
648 | #else |
649 | uint64_t default_timeout_ns = NSEC_PER_SEC>>1; | |
650 | #endif | |
b0d623f7 | 651 | uint32_t slto; |
6d2010ae A |
652 | uint32_t prt; |
653 | ||
b0d623f7 A |
654 | if (PE_parse_boot_argn("slto_us", &slto, sizeof (slto))) |
655 | default_timeout_ns = slto * NSEC_PER_USEC; | |
0c530ab8 | 656 | |
39037602 A |
657 | /* |
658 | * LockTimeOut is absolutetime, LockTimeOutTSC is in TSC ticks, | |
659 | * and LockTimeOutUsec is in microseconds and it's 32-bits. | |
660 | */ | |
661 | LockTimeOutUsec = (uint32_t) (default_timeout_ns / NSEC_PER_USEC); | |
b0d623f7 | 662 | nanoseconds_to_absolutetime(default_timeout_ns, &abstime); |
39037602 A |
663 | LockTimeOut = abstime; |
664 | LockTimeOutTSC = tmrCvt(abstime, tscFCvtn2t); | |
0c530ab8 | 665 | |
fe8ab488 A |
666 | /* |
667 | * TLBTimeOut dictates the TLB flush timeout period. It defaults to | |
668 | * LockTimeOut but can be overriden separately. In particular, a | |
669 | * zero value inhibits the timeout-panic and cuts a trace evnt instead | |
670 | * - see pmap_flush_tlbs(). | |
671 | */ | |
672 | if (PE_parse_boot_argn("tlbto_us", &slto, sizeof (slto))) { | |
673 | default_timeout_ns = slto * NSEC_PER_USEC; | |
674 | nanoseconds_to_absolutetime(default_timeout_ns, &abstime); | |
675 | TLBTimeOut = (uint32_t) abstime; | |
676 | } else { | |
677 | TLBTimeOut = LockTimeOut; | |
678 | } | |
679 | ||
813fb2f6 | 680 | #if DEVELOPMENT || DEBUG |
5ba3f43e | 681 | reportphyreaddelayabs = LockTimeOut >> 1; |
813fb2f6 | 682 | #endif |
3e170ce0 A |
683 | if (PE_parse_boot_argn("phyreadmaxus", &slto, sizeof (slto))) { |
684 | default_timeout_ns = slto * NSEC_PER_USEC; | |
685 | nanoseconds_to_absolutetime(default_timeout_ns, &abstime); | |
686 | reportphyreaddelayabs = abstime; | |
687 | } | |
688 | ||
593a1d5f | 689 | if (PE_parse_boot_argn("mtxspin", &mtxspin, sizeof (mtxspin))) { |
0c530ab8 A |
690 | if (mtxspin > USEC_PER_SEC>>4) |
691 | mtxspin = USEC_PER_SEC>>4; | |
692 | nanoseconds_to_absolutetime(mtxspin*NSEC_PER_USEC, &abstime); | |
693 | } else { | |
694 | nanoseconds_to_absolutetime(10*NSEC_PER_USEC, &abstime); | |
695 | } | |
696 | MutexSpin = (unsigned int)abstime; | |
b0d623f7 | 697 | |
060df5ea | 698 | nanoseconds_to_absolutetime(4ULL * NSEC_PER_SEC, &LastDebuggerEntryAllowance); |
6d2010ae A |
699 | if (PE_parse_boot_argn("panic_restart_timeout", &prt, sizeof (prt))) |
700 | nanoseconds_to_absolutetime(prt * NSEC_PER_SEC, &panic_restart_timeout); | |
39037602 | 701 | |
6d2010ae | 702 | virtualized = ((cpuid_features() & CPUID_FEATURE_VMM) != 0); |
39037602 A |
703 | if (virtualized) { |
704 | int vti; | |
705 | ||
706 | if (!PE_parse_boot_argn("vti", &vti, sizeof (vti))) | |
707 | vti = 6; | |
708 | printf("Timeouts adjusted for virtualization (<<%d)\n", vti); | |
709 | kprintf("Timeouts adjusted for virtualization (<<%d):\n", vti); | |
710 | #define VIRTUAL_TIMEOUT_INFLATE64(_timeout) \ | |
711 | MACRO_BEGIN \ | |
712 | kprintf("%24s: 0x%016llx ", #_timeout, _timeout); \ | |
713 | _timeout <<= vti; \ | |
714 | kprintf("-> 0x%016llx\n", _timeout); \ | |
715 | MACRO_END | |
716 | #define VIRTUAL_TIMEOUT_INFLATE32(_timeout) \ | |
717 | MACRO_BEGIN \ | |
718 | kprintf("%24s: 0x%08x ", #_timeout, _timeout); \ | |
719 | if ((_timeout <<vti) >> vti == _timeout) \ | |
720 | _timeout <<= vti; \ | |
721 | else \ | |
722 | _timeout = ~0; /* cap rather than overflow */ \ | |
723 | kprintf("-> 0x%08x\n", _timeout); \ | |
724 | MACRO_END | |
725 | VIRTUAL_TIMEOUT_INFLATE32(LockTimeOutUsec); | |
726 | VIRTUAL_TIMEOUT_INFLATE64(LockTimeOut); | |
727 | VIRTUAL_TIMEOUT_INFLATE64(LockTimeOutTSC); | |
728 | VIRTUAL_TIMEOUT_INFLATE64(TLBTimeOut); | |
729 | VIRTUAL_TIMEOUT_INFLATE64(MutexSpin); | |
813fb2f6 | 730 | VIRTUAL_TIMEOUT_INFLATE64(reportphyreaddelayabs); |
39037602 A |
731 | } |
732 | ||
060df5ea | 733 | interrupt_latency_tracker_setup(); |
39236c6e | 734 | simple_lock_init(&ml_timer_evaluation_slock, 0); |
0c530ab8 A |
735 | } |
736 | ||
316670eb A |
737 | /* |
738 | * Threshold above which we should attempt to block | |
739 | * instead of spinning for clock_delay_until(). | |
740 | */ | |
39236c6e | 741 | |
316670eb | 742 | void |
bd504ef0 | 743 | ml_init_delay_spin_threshold(int threshold_us) |
316670eb | 744 | { |
bd504ef0 | 745 | nanoseconds_to_absolutetime(threshold_us * NSEC_PER_USEC, &delay_spin_threshold); |
316670eb A |
746 | } |
747 | ||
748 | boolean_t | |
749 | ml_delay_should_spin(uint64_t interval) | |
750 | { | |
751 | return (interval < delay_spin_threshold) ? TRUE : FALSE; | |
752 | } | |
753 | ||
91447636 | 754 | /* |
bd504ef0 | 755 | * This is called from the machine-independent layer |
91447636 A |
756 | * to perform machine-dependent info updates. Defer to cpu_thread_init(). |
757 | */ | |
758 | void | |
759 | ml_cpu_up(void) | |
760 | { | |
761 | return; | |
762 | } | |
763 | ||
764 | /* | |
bd504ef0 | 765 | * This is called from the machine-independent layer |
91447636 A |
766 | * to perform machine-dependent info updates. |
767 | */ | |
768 | void | |
769 | ml_cpu_down(void) | |
770 | { | |
bd504ef0 A |
771 | i386_deactivate_cpu(); |
772 | ||
91447636 A |
773 | return; |
774 | } | |
775 | ||
91447636 A |
776 | /* |
777 | * The following are required for parts of the kernel | |
778 | * that cannot resolve these functions as inlines: | |
779 | */ | |
780 | extern thread_t current_act(void); | |
781 | thread_t | |
9bccf70c | 782 | current_act(void) |
91447636 A |
783 | { |
784 | return(current_thread_fast()); | |
785 | } | |
55e303ae A |
786 | |
787 | #undef current_thread | |
91447636 | 788 | extern thread_t current_thread(void); |
55e303ae A |
789 | thread_t |
790 | current_thread(void) | |
791 | { | |
91447636 | 792 | return(current_thread_fast()); |
55e303ae | 793 | } |
0c530ab8 | 794 | |
0c530ab8 A |
795 | |
796 | boolean_t ml_is64bit(void) { | |
797 | ||
798 | return (cpu_mode_is64bit()); | |
799 | } | |
800 | ||
801 | ||
802 | boolean_t ml_thread_is64bit(thread_t thread) { | |
803 | ||
804 | return (thread_is_64bit(thread)); | |
805 | } | |
806 | ||
807 | ||
808 | boolean_t ml_state_is64bit(void *saved_state) { | |
809 | ||
810 | return is_saved_state64(saved_state); | |
811 | } | |
812 | ||
813 | void ml_cpu_set_ldt(int selector) | |
814 | { | |
815 | /* | |
816 | * Avoid loading the LDT | |
817 | * if we're setting the KERNEL LDT and it's already set. | |
818 | */ | |
819 | if (selector == KERNEL_LDT && | |
820 | current_cpu_datap()->cpu_ldt == KERNEL_LDT) | |
821 | return; | |
822 | ||
b0d623f7 | 823 | lldt(selector); |
b0d623f7 | 824 | current_cpu_datap()->cpu_ldt = selector; |
0c530ab8 A |
825 | } |
826 | ||
827 | void ml_fp_setvalid(boolean_t value) | |
828 | { | |
829 | fp_setvalid(value); | |
830 | } | |
831 | ||
2d21ac55 A |
832 | uint64_t ml_cpu_int_event_time(void) |
833 | { | |
834 | return current_cpu_datap()->cpu_int_event_time; | |
835 | } | |
836 | ||
b0d623f7 A |
837 | vm_offset_t ml_stack_remaining(void) |
838 | { | |
839 | uintptr_t local = (uintptr_t) &local; | |
840 | ||
841 | if (ml_at_interrupt_context() != 0) { | |
842 | return (local - (current_cpu_datap()->cpu_int_stack_top - INTSTACK_SIZE)); | |
843 | } else { | |
844 | return (local - current_thread()->kernel_stack); | |
845 | } | |
846 | } | |
2d21ac55 | 847 | |
5ba3f43e A |
848 | #if KASAN |
849 | vm_offset_t ml_stack_base(void); | |
850 | vm_size_t ml_stack_size(void); | |
851 | ||
852 | vm_offset_t | |
853 | ml_stack_base(void) | |
854 | { | |
855 | if (ml_at_interrupt_context()) { | |
856 | return current_cpu_datap()->cpu_int_stack_top - INTSTACK_SIZE; | |
857 | } else { | |
858 | return current_thread()->kernel_stack; | |
859 | } | |
860 | } | |
861 | ||
862 | vm_size_t | |
863 | ml_stack_size(void) | |
864 | { | |
865 | if (ml_at_interrupt_context()) { | |
866 | return INTSTACK_SIZE; | |
867 | } else { | |
868 | return kernel_stack_size; | |
869 | } | |
870 | } | |
871 | #endif | |
872 | ||
6d2010ae A |
873 | void |
874 | kernel_preempt_check(void) | |
875 | { | |
876 | boolean_t intr; | |
877 | unsigned long flags; | |
878 | ||
879 | assert(get_preemption_level() == 0); | |
880 | ||
881 | __asm__ volatile("pushf; pop %0" : "=r" (flags)); | |
882 | ||
883 | intr = ((flags & EFL_IF) != 0); | |
884 | ||
885 | if ((*ast_pending() & AST_URGENT) && intr == TRUE) { | |
886 | /* | |
887 | * can handle interrupts and preemptions | |
888 | * at this point | |
889 | */ | |
890 | ||
891 | /* | |
892 | * now cause the PRE-EMPTION trap | |
893 | */ | |
894 | __asm__ volatile ("int %0" :: "N" (T_PREEMPT)); | |
895 | } | |
896 | } | |
897 | ||
060df5ea | 898 | boolean_t machine_timeout_suspended(void) { |
39037602 | 899 | return (pmap_tlb_flush_timeout || spinlock_timed_out || panic_active() || mp_recent_debugger_activity() || ml_recent_wake()); |
060df5ea | 900 | } |
39236c6e A |
901 | |
902 | /* Eagerly evaluate all pending timer and thread callouts | |
903 | */ | |
904 | void ml_timer_evaluate(void) { | |
905 | KERNEL_DEBUG_CONSTANT(DECR_TIMER_RESCAN|DBG_FUNC_START, 0, 0, 0, 0, 0); | |
906 | ||
907 | uint64_t te_end, te_start = mach_absolute_time(); | |
908 | simple_lock(&ml_timer_evaluation_slock); | |
909 | ml_timer_evaluation_in_progress = TRUE; | |
910 | thread_call_delayed_timer_rescan_all(); | |
911 | mp_cpus_call(CPUMASK_ALL, ASYNC, timer_queue_expire_rescan, NULL); | |
912 | ml_timer_evaluation_in_progress = FALSE; | |
913 | ml_timer_eager_evaluations++; | |
914 | te_end = mach_absolute_time(); | |
915 | ml_timer_eager_evaluation_max = MAX(ml_timer_eager_evaluation_max, (te_end - te_start)); | |
916 | simple_unlock(&ml_timer_evaluation_slock); | |
917 | ||
918 | KERNEL_DEBUG_CONSTANT(DECR_TIMER_RESCAN|DBG_FUNC_END, 0, 0, 0, 0, 0); | |
919 | } | |
920 | ||
921 | boolean_t | |
922 | ml_timer_forced_evaluation(void) { | |
923 | return ml_timer_evaluation_in_progress; | |
924 | } | |
fe8ab488 A |
925 | |
926 | /* 32-bit right-rotate n bits */ | |
927 | static inline uint32_t ror32(uint32_t val, const unsigned int n) | |
928 | { | |
929 | __asm__ volatile("rorl %%cl,%0" : "=r" (val) : "0" (val), "c" (n)); | |
930 | return val; | |
931 | } | |
932 | ||
933 | void | |
934 | ml_entropy_collect(void) | |
935 | { | |
936 | uint32_t tsc_lo, tsc_hi; | |
937 | uint32_t *ep; | |
938 | ||
939 | assert(cpu_number() == master_cpu); | |
940 | ||
941 | /* update buffer pointer cyclically */ | |
942 | if (EntropyData.index_ptr - EntropyData.buffer == ENTROPY_BUFFER_SIZE) | |
943 | ep = EntropyData.index_ptr = EntropyData.buffer; | |
944 | else | |
945 | ep = EntropyData.index_ptr++; | |
946 | ||
947 | rdtsc_nofence(tsc_lo, tsc_hi); | |
948 | *ep = ror32(*ep, 9) ^ tsc_lo; | |
949 | } | |
950 | ||
39037602 A |
951 | uint64_t |
952 | ml_energy_stat(__unused thread_t t) { | |
953 | return 0; | |
954 | } | |
955 | ||
fe8ab488 A |
956 | void |
957 | ml_gpu_stat_update(uint64_t gpu_ns_delta) { | |
958 | current_thread()->machine.thread_gpu_ns += gpu_ns_delta; | |
959 | } | |
960 | ||
961 | uint64_t | |
962 | ml_gpu_stat(thread_t t) { | |
963 | return t->machine.thread_gpu_ns; | |
964 | } | |
39037602 A |
965 | |
966 | int plctrace_enabled = 0; | |
967 | ||
968 | void _disable_preemption(void) { | |
969 | disable_preemption_internal(); | |
970 | } | |
971 | ||
972 | void _enable_preemption(void) { | |
973 | enable_preemption_internal(); | |
974 | } | |
975 | ||
976 | void plctrace_disable(void) { | |
977 | plctrace_enabled = 0; | |
978 | } | |
5ba3f43e A |
979 | |
980 | static boolean_t ml_quiescing; | |
981 | ||
982 | void ml_set_is_quiescing(boolean_t quiescing) | |
983 | { | |
984 | assert(FALSE == ml_get_interrupts_enabled()); | |
985 | ml_quiescing = quiescing; | |
986 | } | |
987 | ||
988 | boolean_t ml_is_quiescing(void) | |
989 | { | |
990 | assert(FALSE == ml_get_interrupts_enabled()); | |
991 | return (ml_quiescing); | |
992 | } | |
993 | ||
994 | uint64_t ml_get_booter_memory_size(void) | |
995 | { | |
996 | return (0); | |
997 | } |