X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/316670eb35587141e969394ae8537d66b9211e80..b226f5e54a60dc81db17b1260381d7dbfea3cdf1:/osfmk/i386/lapic_native.c diff --git a/osfmk/i386/lapic_native.c b/osfmk/i386/lapic_native.c index 3e6991974..73e5e1c13 100644 --- a/osfmk/i386/lapic_native.c +++ b/osfmk/i386/lapic_native.c @@ -56,10 +56,6 @@ #include #endif -#if CONFIG_COUNTERS -#include -#endif - #include #if MP_DEBUG @@ -112,37 +108,52 @@ static void legacy_init(void) { int result; + kern_return_t kr; vm_map_entry_t entry; vm_map_offset_t lapic_vbase64; /* Establish a map to the local apic */ - lapic_vbase64 = (vm_offset_t)vm_map_min(kernel_map); - result = vm_map_find_space(kernel_map, - &lapic_vbase64, - round_page(LAPIC_SIZE), 0, - VM_MAKE_TAG(VM_MEMORY_IOKIT), &entry); - /* Convert 64-bit vm_map_offset_t to "pointer sized" vm_offset_t - */ - lapic_vbase = (vm_offset_t) lapic_vbase64; - if (result != KERN_SUCCESS) { - panic("legacy_init: vm_map_find_entry FAILED (err=%d)", result); + if (lapic_vbase == 0) { + lapic_vbase64 = (vm_offset_t)vm_map_min(kernel_map); + result = vm_map_find_space(kernel_map, + &lapic_vbase64, + round_page(LAPIC_SIZE), 0, + 0, + VM_MAP_KERNEL_FLAGS_NONE, + VM_KERN_MEMORY_IOKIT, + &entry); + /* Convert 64-bit vm_map_offset_t to "pointer sized" vm_offset_t + */ + lapic_vbase = (vm_offset_t) lapic_vbase64; + if (result != KERN_SUCCESS) { + panic("legacy_init: vm_map_find_entry FAILED (err=%d)", result); + } + vm_map_unlock(kernel_map); + + /* + * Map in the local APIC non-cacheable, as recommended by Intel + * in section 8.4.1 of the "System Programming Guide". + * In fact, this is redundant because EFI will have assigned an + * MTRR physical range containing the local APIC's MMIO space as + * UC and this will override the default PAT setting. + */ + kr = pmap_enter(pmap_kernel(), + lapic_vbase, + (ppnum_t) i386_btop(lapic_pbase), + VM_PROT_READ|VM_PROT_WRITE, + VM_PROT_NONE, + VM_WIMG_IO, + TRUE); + + assert(kr == KERN_SUCCESS); } - vm_map_unlock(kernel_map); /* - * Map in the local APIC non-cacheable, as recommended by Intel - * in section 8.4.1 of the "System Programming Guide". - * In fact, this is redundant because EFI will have assigned an - * MTRR physical range containing the local APIC's MMIO space as - * UC and this will override the default PAT setting. + * Set flat delivery model, logical processor id + * This should already be the default set. */ - pmap_enter(pmap_kernel(), - lapic_vbase, - (ppnum_t) i386_btop(lapic_pbase), - VM_PROT_READ|VM_PROT_WRITE, - VM_PROT_NONE, - VM_WIMG_IO, - TRUE); + LAPIC_WRITE(DFR, LAPIC_DFR_FLAT); + LAPIC_WRITE(LDR, (get_cpu_number()) << LAPIC_LDR_SHIFT); } @@ -158,15 +169,41 @@ legacy_write(lapic_register_t reg, uint32_t value) *LAPIC_MMIO(reg) = value; } +static uint64_t +legacy_read_icr(void) +{ + return (((uint64_t)*LAPIC_MMIO(ICRD)) << 32) | ((uint64_t)*LAPIC_MMIO(ICR)); +} + +static void +legacy_write_icr(uint32_t dst, uint32_t cmd) +{ + *LAPIC_MMIO(ICRD) = dst << LAPIC_ICRD_DEST_SHIFT; + *LAPIC_MMIO(ICR) = cmd; +} + static lapic_ops_table_t legacy_ops = { legacy_init, legacy_read, - legacy_write + legacy_write, + legacy_read_icr, + legacy_write_icr }; +static boolean_t is_x2apic = FALSE; + static void x2apic_init(void) { + uint32_t lo; + uint32_t hi; + + rdmsr(MSR_IA32_APIC_BASE, lo, hi); + if ((lo & MSR_IA32_APIC_BASE_EXTENDED) == 0) { + lo |= MSR_IA32_APIC_BASE_EXTENDED; + wrmsr(MSR_IA32_APIC_BASE, lo, hi); + kprintf("x2APIC mode enabled\n"); + } } static uint32_t @@ -185,13 +222,26 @@ x2apic_write(lapic_register_t reg, uint32_t value) wrmsr(LAPIC_MSR(reg), value, 0); } +static uint64_t +x2apic_read_icr(void) +{ + return rdmsr64(LAPIC_MSR(ICR));; +} + +static void +x2apic_write_icr(uint32_t dst, uint32_t cmd) +{ + wrmsr(LAPIC_MSR(ICR), cmd, dst); +} + static lapic_ops_table_t x2apic_ops = { x2apic_init, x2apic_read, - x2apic_write + x2apic_write, + x2apic_read_icr, + x2apic_write_icr }; - void lapic_init(void) { @@ -199,7 +249,6 @@ lapic_init(void) uint32_t hi; boolean_t is_boot_processor; boolean_t is_lapic_enabled; - boolean_t is_x2apic; /* Examine the local APIC state */ rdmsr(MSR_IA32_APIC_BASE, lo, hi); @@ -214,10 +263,21 @@ lapic_init(void) if (!is_boot_processor || !is_lapic_enabled) panic("Unexpected local APIC state\n"); + /* + * If x2APIC is available and not already enabled, enable it. + * Unless overriden by boot-arg. + */ + if (!is_x2apic && (cpuid_features() & CPUID_FEATURE_x2APIC)) { + PE_parse_boot_argn("-x2apic", &is_x2apic, sizeof(is_x2apic)); + kprintf("x2APIC supported %s be enabled\n", + is_x2apic ? "and will" : "but will not"); + } + lapic_ops = is_x2apic ? &x2apic_ops : &legacy_ops; - lapic_ops->init(); + LAPIC_INIT(); + kprintf("ID: 0x%x LDR: 0x%x\n", LAPIC_READ(ID), LAPIC_READ(LDR)); if ((LAPIC_READ(VERSION)&LAPIC_VERSION_MASK) < 0x14) { panic("Local APIC version 0x%x, 0x14 or more expected\n", (LAPIC_READ(VERSION)&LAPIC_VERSION_MASK)); @@ -226,6 +286,7 @@ lapic_init(void) /* Set up the lapic_id <-> cpu_number map and add this boot processor */ lapic_cpu_map_init(); lapic_cpu_map((LAPIC_READ(ID)>>LAPIC_ID_SHIFT)&LAPIC_ID_MASK, 0); + current_cpu_datap()->cpu_phys_number = cpu_to_lapic[0]; kprintf("Boot cpu local APIC id 0x%x\n", cpu_to_lapic[0]); } @@ -290,7 +351,7 @@ lapic_dump(void) LAPIC_READ(APR)&LAPIC_APR_MASK, LAPIC_READ(PPR)&LAPIC_PPR_MASK); kprintf("Destination Format 0x%x Logical Destination 0x%x\n", - LAPIC_READ(DFR)>>LAPIC_DFR_SHIFT, + is_x2apic ? 0 : LAPIC_READ(DFR)>>LAPIC_DFR_SHIFT, LAPIC_READ(LDR)>>LAPIC_LDR_SHIFT); kprintf("%cEnabled %cFocusChecking SV 0x%x\n", BOOL(LAPIC_READ(SVR)&LAPIC_SVR_ENABLE), @@ -385,6 +446,10 @@ lapic_probe(void) * Re-initialize cpu features info and re-check. */ cpuid_set_info(); + /* We expect this codepath will never be traversed + * due to EFI enabling the APIC. Reducing the APIC + * interrupt base dynamically is not supported. + */ if (cpuid_features() & CPUID_FEATURE_APIC) { printf("Local APIC discovered and enabled\n"); lapic_os_enabled = TRUE; @@ -449,10 +514,6 @@ lapic_configure(void) } } - /* Set flat delivery model, logical processor id */ - LAPIC_WRITE(DFR, LAPIC_DFR_FLAT); - LAPIC_WRITE(LDR, (get_cpu_number()) << LAPIC_LDR_SHIFT); - /* Accept all */ LAPIC_WRITE(TPR, 0); @@ -741,17 +802,12 @@ lapic_interrupt(int interrupt_num, x86_saved_state_t *state) break; case LAPIC_PMC_SW_INTERRUPT: { -#if CONFIG_COUNTERS - thread_t old, new; - ml_get_csw_threads(&old, &new); - - if (pmc_context_switch(old, new) == TRUE) { - retval = 1; - /* No EOI required for SWI */ - } -#endif /* CONFIG_COUNTERS */ } break; + case LAPIC_KICK_INTERRUPT: + _lapic_end_of_interrupt(); + retval = 1; + break; } return retval; @@ -801,12 +857,11 @@ lapic_send_ipi(int cpu, int vector) state = ml_set_interrupts_enabled(FALSE); /* Wait for pending outgoing send to complete */ - while (LAPIC_READ(ICR) & LAPIC_ICR_DS_PENDING) { + while (LAPIC_READ_ICR() & LAPIC_ICR_DS_PENDING) { cpu_pause(); } - LAPIC_WRITE(ICRD, cpu_to_lapic[cpu] << LAPIC_ICRD_DEST_SHIFT); - LAPIC_WRITE(ICR, vector | LAPIC_ICR_DM_FIXED); + LAPIC_WRITE_ICR(cpu_to_lapic[cpu], vector | LAPIC_ICR_DM_FIXED); (void) ml_set_interrupts_enabled(state); } @@ -896,3 +951,26 @@ lapic_disable_timer(void) } } +/* SPI returning the CMCI vector */ +uint8_t +lapic_get_cmci_vector(void) +{ + uint8_t cmci_vector = 0; +#if CONFIG_MCA + /* CMCI, if available */ + if (mca_is_cmci_present()) + cmci_vector = LAPIC_VECTOR(CMCI); +#endif + return cmci_vector; +} + +#if DEVELOPMENT || DEBUG +extern void lapic_trigger_MC(void); +void +lapic_trigger_MC(void) +{ + /* A 64-bit access to any register will do it. */ + volatile uint64_t dummy = *(volatile uint64_t *) (volatile void *) LAPIC_MMIO(ID); + dummy++; +} +#endif