]> git.saurik.com Git - apple/xnu.git/blob - osfmk/i386/lapic.c
xnu-1228.12.14.tar.gz
[apple/xnu.git] / osfmk / i386 / lapic.c
1 /*
2 * Copyright (c) 2008 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
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
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /*
29 * @OSF_COPYRIGHT@
30 */
31
32 #include <mach/mach_types.h>
33 #include <mach/kern_return.h>
34
35 #include <kern/kern_types.h>
36 #include <kern/cpu_number.h>
37 #include <kern/cpu_data.h>
38 #include <kern/assert.h>
39 #include <kern/machine.h>
40
41 #include <vm/vm_map.h>
42 #include <vm/vm_kern.h>
43
44 #include <i386/lapic.h>
45 #include <i386/cpuid.h>
46 #include <i386/proc_reg.h>
47 #include <i386/machine_cpu.h>
48 #include <i386/misc_protos.h>
49 #include <i386/mp.h>
50 #include <i386/mtrr.h>
51 #include <i386/postcode.h>
52 #include <i386/cpu_threads.h>
53 #include <i386/trap.h>
54 #include <i386/machine_routines.h>
55 #include <i386/machine_check.h>
56
57 #if MACH_KDB
58 #include <machine/db_machdep.h>
59 #endif
60
61 #include <sys/kdebug.h>
62
63 #if MP_DEBUG
64 #define PAUSE delay(1000000)
65 #define DBG(x...) kprintf(x)
66 #else
67 #define DBG(x...)
68 #define PAUSE
69 #endif /* MP_DEBUG */
70
71 /* Initialize lapic_id so cpu_number() works on non SMP systems */
72 unsigned long lapic_id_initdata = 0;
73 unsigned long lapic_id = (unsigned long)&lapic_id_initdata;
74 vm_offset_t lapic_start;
75
76 static i386_intr_func_t lapic_intr_func[LAPIC_FUNC_TABLE_SIZE];
77
78 /* TRUE if local APIC was enabled by the OS not by the BIOS */
79 static boolean_t lapic_os_enabled = FALSE;
80
81 static boolean_t lapic_errors_masked = FALSE;
82 static uint64_t lapic_last_master_error = 0;
83 static uint64_t lapic_error_time_threshold = 0;
84 static unsigned lapic_master_error_count = 0;
85 static unsigned lapic_error_count_threshold = 5;
86 static boolean_t lapic_dont_panic = FALSE;
87
88 extern int debug_boot_arg;
89
90 /* Base vector for local APIC interrupt sources */
91 int lapic_interrupt_base = LAPIC_DEFAULT_INTERRUPT_BASE;
92
93 int lapic_to_cpu[MAX_CPUS];
94 int cpu_to_lapic[MAX_CPUS];
95
96 static void
97 lapic_cpu_map_init(void)
98 {
99 int i;
100
101 for (i = 0; i < MAX_CPUS; i++) {
102 lapic_to_cpu[i] = -1;
103 cpu_to_lapic[i] = -1;
104 }
105 }
106
107 void
108 lapic_cpu_map(int apic_id, int cpu)
109 {
110 cpu_to_lapic[cpu] = apic_id;
111 lapic_to_cpu[apic_id] = cpu;
112 }
113
114 /*
115 * Retrieve the local apic ID a cpu.
116 *
117 * Returns the local apic ID for the given processor.
118 * If the processor does not exist or apic not configured, returns -1.
119 */
120
121 uint32_t
122 ml_get_apicid(uint32_t cpu)
123 {
124 if(cpu >= (uint32_t)MAX_CPUS)
125 return 0xFFFFFFFF; /* Return -1 if cpu too big */
126
127 /* Return the apic ID (or -1 if not configured) */
128 return (uint32_t)cpu_to_lapic[cpu];
129
130 }
131
132 #ifdef MP_DEBUG
133 static void
134 lapic_cpu_map_dump(void)
135 {
136 int i;
137
138 for (i = 0; i < MAX_CPUS; i++) {
139 if (cpu_to_lapic[i] == -1)
140 continue;
141 kprintf("cpu_to_lapic[%d]: %d\n",
142 i, cpu_to_lapic[i]);
143 }
144 for (i = 0; i < MAX_CPUS; i++) {
145 if (lapic_to_cpu[i] == -1)
146 continue;
147 kprintf("lapic_to_cpu[%d]: %d\n",
148 i, lapic_to_cpu[i]);
149 }
150 }
151 #endif /* MP_DEBUG */
152
153 void
154 lapic_init(void)
155 {
156 int result;
157 vm_map_entry_t entry;
158 uint32_t lo;
159 uint32_t hi;
160 boolean_t is_boot_processor;
161 boolean_t is_lapic_enabled;
162 vm_offset_t lapic_base;
163
164 /* Examine the local APIC state */
165 rdmsr(MSR_IA32_APIC_BASE, lo, hi);
166 is_boot_processor = (lo & MSR_IA32_APIC_BASE_BSP) != 0;
167 is_lapic_enabled = (lo & MSR_IA32_APIC_BASE_ENABLE) != 0;
168 lapic_base = (lo & MSR_IA32_APIC_BASE_BASE);
169 kprintf("MSR_IA32_APIC_BASE 0x%x %s %s\n", lapic_base,
170 is_lapic_enabled ? "enabled" : "disabled",
171 is_boot_processor ? "BSP" : "AP");
172 if (!is_boot_processor || !is_lapic_enabled)
173 panic("Unexpected local APIC state\n");
174
175 /* Establish a map to the local apic */
176 lapic_start = vm_map_min(kernel_map);
177 result = vm_map_find_space(kernel_map,
178 (vm_map_address_t *) &lapic_start,
179 round_page(LAPIC_SIZE), 0,
180 VM_MAKE_TAG(VM_MEMORY_IOKIT), &entry);
181 if (result != KERN_SUCCESS) {
182 panic("smp_init: vm_map_find_entry FAILED (err=%d)", result);
183 }
184 vm_map_unlock(kernel_map);
185 /* Map in the local APIC non-cacheable, as recommended by Intel
186 * in section 8.4.1 of the "System Programming Guide".
187 */
188 pmap_enter(pmap_kernel(),
189 lapic_start,
190 (ppnum_t) i386_btop(lapic_base),
191 VM_PROT_READ|VM_PROT_WRITE,
192 VM_WIMG_IO,
193 TRUE);
194 lapic_id = (unsigned long)(lapic_start + LAPIC_ID);
195
196 if ((LAPIC_READ(VERSION)&LAPIC_VERSION_MASK) < 0x14) {
197 printf("Local APIC version 0x%x, 0x14 or greater expected\n",
198 (LAPIC_READ(VERSION)&LAPIC_VERSION_MASK));
199 }
200
201 /* Set up the lapic_id <-> cpu_number map and add this boot processor */
202 lapic_cpu_map_init();
203 lapic_cpu_map((LAPIC_READ(ID)>>LAPIC_ID_SHIFT)&LAPIC_ID_MASK, 0);
204 kprintf("Boot cpu local APIC id 0x%x\n", cpu_to_lapic[0]);
205 }
206
207
208 static int
209 lapic_esr_read(void)
210 {
211 /* write-read register */
212 LAPIC_WRITE(ERROR_STATUS, 0);
213 return LAPIC_READ(ERROR_STATUS);
214 }
215
216 static void
217 lapic_esr_clear(void)
218 {
219 LAPIC_WRITE(ERROR_STATUS, 0);
220 LAPIC_WRITE(ERROR_STATUS, 0);
221 }
222
223 static const char *DM_str[8] = {
224 "Fixed",
225 "Lowest Priority",
226 "Invalid",
227 "Invalid",
228 "NMI",
229 "Reset",
230 "Invalid",
231 "ExtINT"};
232
233 void
234 lapic_dump(void)
235 {
236 int i;
237
238 #define BOOL(a) ((a)?' ':'!')
239 #define VEC(lvt) \
240 LAPIC_READ(lvt)&LAPIC_LVT_VECTOR_MASK
241 #define DS(lvt) \
242 (LAPIC_READ(lvt)&LAPIC_LVT_DS_PENDING)?" SendPending" : "Idle"
243 #define DM(lvt) \
244 DM_str[(LAPIC_READ(lvt)>>LAPIC_LVT_DM_SHIFT)&LAPIC_LVT_DM_MASK]
245 #define MASK(lvt) \
246 BOOL(LAPIC_READ(lvt)&LAPIC_LVT_MASKED)
247 #define TM(lvt) \
248 (LAPIC_READ(lvt)&LAPIC_LVT_TM_LEVEL)? "Level" : "Edge"
249 #define IP(lvt) \
250 (LAPIC_READ(lvt)&LAPIC_LVT_IP_PLRITY_LOW)? "Low " : "High"
251
252 kprintf("LAPIC %d at 0x%x version 0x%x\n",
253 (LAPIC_READ(ID)>>LAPIC_ID_SHIFT)&LAPIC_ID_MASK,
254 lapic_start,
255 LAPIC_READ(VERSION)&LAPIC_VERSION_MASK);
256 kprintf("Priorities: Task 0x%x Arbitration 0x%x Processor 0x%x\n",
257 LAPIC_READ(TPR)&LAPIC_TPR_MASK,
258 LAPIC_READ(APR)&LAPIC_APR_MASK,
259 LAPIC_READ(PPR)&LAPIC_PPR_MASK);
260 kprintf("Destination Format 0x%x Logical Destination 0x%x\n",
261 LAPIC_READ(DFR)>>LAPIC_DFR_SHIFT,
262 LAPIC_READ(LDR)>>LAPIC_LDR_SHIFT);
263 kprintf("%cEnabled %cFocusChecking SV 0x%x\n",
264 BOOL(LAPIC_READ(SVR)&LAPIC_SVR_ENABLE),
265 BOOL(!(LAPIC_READ(SVR)&LAPIC_SVR_FOCUS_OFF)),
266 LAPIC_READ(SVR) & LAPIC_SVR_MASK);
267 if (mca_is_cmci_present())
268 kprintf("LVT_CMCI: Vector 0x%02x [%s] %s %cmasked\n",
269 VEC(LVT_CMCI),
270 DM(LVT_CMCI),
271 DS(LVT_CMCI),
272 MASK(LVT_CMCI));
273 kprintf("LVT_TIMER: Vector 0x%02x %s %cmasked %s\n",
274 VEC(LVT_TIMER),
275 DS(LVT_TIMER),
276 MASK(LVT_TIMER),
277 (LAPIC_READ(LVT_TIMER)&LAPIC_LVT_PERIODIC)?"Periodic":"OneShot");
278 kprintf(" Initial Count: 0x%08x \n", LAPIC_READ(TIMER_INITIAL_COUNT));
279 kprintf(" Current Count: 0x%08x \n", LAPIC_READ(TIMER_CURRENT_COUNT));
280 kprintf(" Divide Config: 0x%08x \n", LAPIC_READ(TIMER_DIVIDE_CONFIG));
281 kprintf("LVT_PERFCNT: Vector 0x%02x [%s] %s %cmasked\n",
282 VEC(LVT_PERFCNT),
283 DM(LVT_PERFCNT),
284 DS(LVT_PERFCNT),
285 MASK(LVT_PERFCNT));
286 kprintf("LVT_THERMAL: Vector 0x%02x [%s] %s %cmasked\n",
287 VEC(LVT_THERMAL),
288 DM(LVT_THERMAL),
289 DS(LVT_THERMAL),
290 MASK(LVT_THERMAL));
291 kprintf("LVT_LINT0: Vector 0x%02x [%s][%s][%s] %s %cmasked\n",
292 VEC(LVT_LINT0),
293 DM(LVT_LINT0),
294 TM(LVT_LINT0),
295 IP(LVT_LINT0),
296 DS(LVT_LINT0),
297 MASK(LVT_LINT0));
298 kprintf("LVT_LINT1: Vector 0x%02x [%s][%s][%s] %s %cmasked\n",
299 VEC(LVT_LINT1),
300 DM(LVT_LINT1),
301 TM(LVT_LINT1),
302 IP(LVT_LINT1),
303 DS(LVT_LINT1),
304 MASK(LVT_LINT1));
305 kprintf("LVT_ERROR: Vector 0x%02x %s %cmasked\n",
306 VEC(LVT_ERROR),
307 DS(LVT_ERROR),
308 MASK(LVT_ERROR));
309 kprintf("ESR: %08x \n", lapic_esr_read());
310 kprintf(" ");
311 for(i=0xf; i>=0; i--)
312 kprintf("%x%x%x%x",i,i,i,i);
313 kprintf("\n");
314 kprintf("TMR: 0x");
315 for(i=7; i>=0; i--)
316 kprintf("%08x",LAPIC_READ_OFFSET(TMR_BASE, i*0x10));
317 kprintf("\n");
318 kprintf("IRR: 0x");
319 for(i=7; i>=0; i--)
320 kprintf("%08x",LAPIC_READ_OFFSET(IRR_BASE, i*0x10));
321 kprintf("\n");
322 kprintf("ISR: 0x");
323 for(i=7; i >= 0; i--)
324 kprintf("%08x",LAPIC_READ_OFFSET(ISR_BASE, i*0x10));
325 kprintf("\n");
326 }
327
328 #if MACH_KDB
329 /*
330 * Displays apic junk
331 *
332 * da
333 */
334 void
335 db_apic(__unused db_expr_t addr,
336 __unused int have_addr,
337 __unused db_expr_t count,
338 __unused char *modif)
339 {
340
341 lapic_dump();
342
343 return;
344 }
345
346 #endif
347
348 boolean_t
349 lapic_probe(void)
350 {
351 uint32_t lo;
352 uint32_t hi;
353
354 if (cpuid_features() & CPUID_FEATURE_APIC)
355 return TRUE;
356
357 if (cpuid_family() == 6 || cpuid_family() == 15) {
358 /*
359 * Mobile Pentiums:
360 * There may be a local APIC which wasn't enabled by BIOS.
361 * So we try to enable it explicitly.
362 */
363 rdmsr(MSR_IA32_APIC_BASE, lo, hi);
364 lo &= ~MSR_IA32_APIC_BASE_BASE;
365 lo |= MSR_IA32_APIC_BASE_ENABLE | LAPIC_START;
366 lo |= MSR_IA32_APIC_BASE_ENABLE;
367 wrmsr(MSR_IA32_APIC_BASE, lo, hi);
368
369 /*
370 * Re-initialize cpu features info and re-check.
371 */
372 cpuid_set_info();
373 if (cpuid_features() & CPUID_FEATURE_APIC) {
374 printf("Local APIC discovered and enabled\n");
375 lapic_os_enabled = TRUE;
376 lapic_interrupt_base = LAPIC_REDUCED_INTERRUPT_BASE;
377 return TRUE;
378 }
379 }
380
381 return FALSE;
382 }
383
384 void
385 lapic_shutdown(void)
386 {
387 uint32_t lo;
388 uint32_t hi;
389 uint32_t value;
390
391 /* Shutdown if local APIC was enabled by OS */
392 if (lapic_os_enabled == FALSE)
393 return;
394
395 mp_disable_preemption();
396
397 /* ExtINT: masked */
398 if (get_cpu_number() == master_cpu) {
399 value = LAPIC_READ(LVT_LINT0);
400 value |= LAPIC_LVT_MASKED;
401 LAPIC_WRITE(LVT_LINT0, value);
402 }
403
404 /* Error: masked */
405 LAPIC_WRITE(LVT_ERROR, LAPIC_READ(LVT_ERROR) | LAPIC_LVT_MASKED);
406
407 /* Timer: masked */
408 LAPIC_WRITE(LVT_TIMER, LAPIC_READ(LVT_TIMER) | LAPIC_LVT_MASKED);
409
410 /* Perfmon: masked */
411 LAPIC_WRITE(LVT_PERFCNT, LAPIC_READ(LVT_PERFCNT) | LAPIC_LVT_MASKED);
412
413 /* APIC software disabled */
414 LAPIC_WRITE(SVR, LAPIC_READ(SVR) & ~LAPIC_SVR_ENABLE);
415
416 /* Bypass the APIC completely and update cpu features */
417 rdmsr(MSR_IA32_APIC_BASE, lo, hi);
418 lo &= ~MSR_IA32_APIC_BASE_ENABLE;
419 wrmsr(MSR_IA32_APIC_BASE, lo, hi);
420 cpuid_set_info();
421
422 mp_enable_preemption();
423 }
424
425 void
426 lapic_configure(void)
427 {
428 int value;
429
430 if (lapic_error_time_threshold == 0 && cpu_number() == 0) {
431 nanoseconds_to_absolutetime(NSEC_PER_SEC >> 2, &lapic_error_time_threshold);
432 if (!PE_parse_boot_argn("lapic_dont_panic", &lapic_dont_panic, sizeof(lapic_dont_panic))) {
433 lapic_dont_panic = FALSE;
434 }
435 }
436
437 /* Set flat delivery model, logical processor id */
438 LAPIC_WRITE(DFR, LAPIC_DFR_FLAT);
439 LAPIC_WRITE(LDR, (get_cpu_number()) << LAPIC_LDR_SHIFT);
440
441 /* Accept all */
442 LAPIC_WRITE(TPR, 0);
443
444 LAPIC_WRITE(SVR, LAPIC_VECTOR(SPURIOUS) | LAPIC_SVR_ENABLE);
445
446 /* ExtINT */
447 if (get_cpu_number() == master_cpu) {
448 value = LAPIC_READ(LVT_LINT0);
449 value &= ~LAPIC_LVT_MASKED;
450 value |= LAPIC_LVT_DM_EXTINT;
451 LAPIC_WRITE(LVT_LINT0, value);
452 }
453
454 /* Timer: unmasked, one-shot */
455 LAPIC_WRITE(LVT_TIMER, LAPIC_VECTOR(TIMER));
456
457 /* Perfmon: unmasked */
458 LAPIC_WRITE(LVT_PERFCNT, LAPIC_VECTOR(PERFCNT));
459
460 /* Thermal: unmasked */
461 LAPIC_WRITE(LVT_THERMAL, LAPIC_VECTOR(THERMAL));
462
463 /* CMCI, if available */
464 if (mca_is_cmci_present())
465 LAPIC_WRITE(LVT_CMCI, LAPIC_VECTOR(CMCI));
466
467 if (((cpu_number() == master_cpu) && lapic_errors_masked == FALSE) ||
468 (cpu_number() != master_cpu)) {
469 lapic_esr_clear();
470 LAPIC_WRITE(LVT_ERROR, LAPIC_VECTOR(ERROR));
471 }
472 }
473
474 void
475 lapic_set_timer(
476 boolean_t interrupt,
477 lapic_timer_mode_t mode,
478 lapic_timer_divide_t divisor,
479 lapic_timer_count_t initial_count)
480 {
481 boolean_t state;
482 uint32_t timer_vector;
483
484 state = ml_set_interrupts_enabled(FALSE);
485 timer_vector = LAPIC_READ(LVT_TIMER);
486 timer_vector &= ~(LAPIC_LVT_MASKED|LAPIC_LVT_PERIODIC);;
487 timer_vector |= interrupt ? 0 : LAPIC_LVT_MASKED;
488 timer_vector |= (mode == periodic) ? LAPIC_LVT_PERIODIC : 0;
489 LAPIC_WRITE(LVT_TIMER, timer_vector);
490 LAPIC_WRITE(TIMER_DIVIDE_CONFIG, divisor);
491 LAPIC_WRITE(TIMER_INITIAL_COUNT, initial_count);
492 ml_set_interrupts_enabled(state);
493 }
494
495 void
496 lapic_get_timer(
497 lapic_timer_mode_t *mode,
498 lapic_timer_divide_t *divisor,
499 lapic_timer_count_t *initial_count,
500 lapic_timer_count_t *current_count)
501 {
502 boolean_t state;
503
504 state = ml_set_interrupts_enabled(FALSE);
505 if (mode)
506 *mode = (LAPIC_READ(LVT_TIMER) & LAPIC_LVT_PERIODIC) ?
507 periodic : one_shot;
508 if (divisor)
509 *divisor = LAPIC_READ(TIMER_DIVIDE_CONFIG) & LAPIC_TIMER_DIVIDE_MASK;
510 if (initial_count)
511 *initial_count = LAPIC_READ(TIMER_INITIAL_COUNT);
512 if (current_count)
513 *current_count = LAPIC_READ(TIMER_CURRENT_COUNT);
514 ml_set_interrupts_enabled(state);
515 }
516
517 static inline void
518 _lapic_end_of_interrupt(void)
519 {
520 LAPIC_WRITE(EOI, 0);
521 }
522
523 void
524 lapic_end_of_interrupt(void)
525 {
526 _lapic_end_of_interrupt();
527 }
528
529 void
530 lapic_set_intr_func(int vector, i386_intr_func_t func)
531 {
532 if (vector > lapic_interrupt_base)
533 vector -= lapic_interrupt_base;
534
535 switch (vector) {
536 case LAPIC_NMI_INTERRUPT:
537 case LAPIC_INTERPROCESSOR_INTERRUPT:
538 case LAPIC_TIMER_INTERRUPT:
539 case LAPIC_THERMAL_INTERRUPT:
540 case LAPIC_PERFCNT_INTERRUPT:
541 case LAPIC_CMCI_INTERRUPT:
542 lapic_intr_func[vector] = func;
543 break;
544 default:
545 panic("lapic_set_intr_func(%d,%p) invalid vector\n",
546 vector, func);
547 }
548 }
549
550 int
551 lapic_interrupt(int interrupt, x86_saved_state_t *state)
552 {
553 int retval = 0;
554 int esr = -1;
555
556 interrupt -= lapic_interrupt_base;
557 if (interrupt < 0) {
558 if (interrupt == (LAPIC_NMI_INTERRUPT - lapic_interrupt_base) &&
559 lapic_intr_func[LAPIC_NMI_INTERRUPT] != NULL) {
560 retval = (*lapic_intr_func[LAPIC_NMI_INTERRUPT])(state);
561 _lapic_end_of_interrupt();
562 return retval;
563 }
564 else
565 return 0;
566 }
567
568 switch(interrupt) {
569 case LAPIC_TIMER_INTERRUPT:
570 case LAPIC_THERMAL_INTERRUPT:
571 case LAPIC_PERFCNT_INTERRUPT:
572 case LAPIC_INTERPROCESSOR_INTERRUPT:
573 if (lapic_intr_func[interrupt] != NULL)
574 (void) (*lapic_intr_func[interrupt])(state);
575 if (interrupt == LAPIC_PERFCNT_INTERRUPT)
576 /* Clear interrupt masked */
577 LAPIC_WRITE(LVT_PERFCNT, LAPIC_VECTOR(PERFCNT));
578 _lapic_end_of_interrupt();
579 retval = 1;
580 break;
581 case LAPIC_CMCI_INTERRUPT:
582 if (lapic_intr_func[interrupt] != NULL)
583 (void) (*lapic_intr_func[interrupt])(state);
584 /* return 0 for plaform expert to handle */
585 break;
586 case LAPIC_ERROR_INTERRUPT:
587 /* We treat error interrupts on APs as fatal.
588 * The current interrupt steering scheme directs most
589 * external interrupts to the BSP (HPET interrupts being
590 * a notable exception); hence, such an error
591 * on an AP may signify LVT corruption (with "may" being
592 * the operative word). On the BSP, we adopt a more
593 * lenient approach, in the interests of enhancing
594 * debuggability and reducing fragility.
595 * If "lapic_error_count_threshold" error interrupts
596 * occur within "lapic_error_time_threshold" absolute
597 * time units, we mask the error vector and log. The
598 * error interrupts themselves are likely
599 * side effects of issues which are beyond the purview of
600 * the local APIC interrupt handler, however. The Error
601 * Status Register value (the illegal destination
602 * vector code is one observed in practice) indicates
603 * the immediate cause of the error.
604 */
605 esr = lapic_esr_read();
606 lapic_dump();
607
608 if ((debug_boot_arg && (lapic_dont_panic == FALSE)) ||
609 cpu_number() != master_cpu) {
610 panic("Local APIC error, ESR: %d\n", esr);
611 }
612
613 if (cpu_number() == master_cpu) {
614 uint64_t abstime = mach_absolute_time();
615 if ((abstime - lapic_last_master_error) < lapic_error_time_threshold) {
616 if (lapic_master_error_count++ > lapic_error_count_threshold) {
617 lapic_errors_masked = TRUE;
618 LAPIC_WRITE(LVT_ERROR, LAPIC_READ(LVT_ERROR) | LAPIC_LVT_MASKED);
619 printf("Local APIC: errors masked\n");
620 }
621 }
622 else {
623 lapic_last_master_error = abstime;
624 lapic_master_error_count = 0;
625 }
626 printf("Local APIC error on master CPU, ESR: %d, error count this run: %d\n", esr, lapic_master_error_count);
627 }
628
629 _lapic_end_of_interrupt();
630 retval = 1;
631 break;
632 case LAPIC_SPURIOUS_INTERRUPT:
633 kprintf("SPIV\n");
634 /* No EOI required here */
635 retval = 1;
636 break;
637 }
638
639 return retval;
640 }
641
642 void
643 lapic_smm_restore(void)
644 {
645 boolean_t state;
646
647 if (lapic_os_enabled == FALSE)
648 return;
649
650 state = ml_set_interrupts_enabled(FALSE);
651
652 if (LAPIC_ISR_IS_SET(LAPIC_REDUCED_INTERRUPT_BASE, TIMER)) {
653 /*
654 * Bogus SMI handler enables interrupts but does not know about
655 * local APIC interrupt sources. When APIC timer counts down to
656 * zero while in SMM, local APIC will end up waiting for an EOI
657 * but no interrupt was delivered to the OS.
658 */
659 _lapic_end_of_interrupt();
660
661 /*
662 * timer is one-shot, trigger another quick countdown to trigger
663 * another timer interrupt.
664 */
665 if (LAPIC_READ(TIMER_CURRENT_COUNT) == 0) {
666 LAPIC_WRITE(TIMER_INITIAL_COUNT, 1);
667 }
668
669 kprintf("lapic_smm_restore\n");
670 }
671
672 ml_set_interrupts_enabled(state);
673 }
674