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 */ 72unsigned long lapic_id_initdata = 0; 73unsigned long lapic_id = (unsigned long)&lapic_id_initdata; 74vm_offset_t lapic_start; 75 76static 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 */ 79static boolean_t lapic_os_enabled = FALSE; 80 81static boolean_t lapic_errors_masked = FALSE; 82static uint64_t lapic_last_master_error = 0; 83static uint64_t lapic_error_time_threshold = 0; 84static unsigned lapic_master_error_count = 0; 85static unsigned lapic_error_count_threshold = 5; 86static boolean_t lapic_dont_panic = FALSE; 87 88extern int debug_boot_arg; 89 90/* Base vector for local APIC interrupt sources */ 91int lapic_interrupt_base = LAPIC_DEFAULT_INTERRUPT_BASE; 92 93int lapic_to_cpu[MAX_CPUS]; 94int cpu_to_lapic[MAX_CPUS]; 95 96static void 97lapic_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 107void 108lapic_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 121uint32_t 122ml_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 133static void 134lapic_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 153void 154lapic_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 208static int 209lapic_esr_read(void) 210{ 211 /* write-read register */ 212 LAPIC_WRITE(ERROR_STATUS, 0); 213 return LAPIC_READ(ERROR_STATUS); 214} 215 216static void 217lapic_esr_clear(void) 218{ 219 LAPIC_WRITE(ERROR_STATUS, 0); 220 LAPIC_WRITE(ERROR_STATUS, 0); 221} 222 223static const char *DM_str[8] = { 224 "Fixed", 225 "Lowest Priority", 226 "Invalid", 227 "Invalid", 228 "NMI", 229 "Reset", 230 "Invalid", 231 "ExtINT"}; 232 233void 234lapic_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 */ 334void 335db_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 348boolean_t 349lapic_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 384void 385lapic_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 425void 426lapic_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 474void 475lapic_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 495void 496lapic_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 517static inline void 518_lapic_end_of_interrupt(void) 519{ 520 LAPIC_WRITE(EOI, 0); 521} 522 523void 524lapic_end_of_interrupt(void) 525{ 526 _lapic_end_of_interrupt(); 527} 528 529void 530lapic_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 550int 551lapic_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 642void 643lapic_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 675