void lapic_init(void) { int result; vm_map_entry_t entry; uint32_t lo; uint32_t hi; boolean_t is_boot_processor; boolean_t is_lapic_enabled; vm_offset_t lapic_base; /* Examine the local APIC state */ rdmsr(MSR_IA32_APIC_BASE, lo, hi); is_boot_processor = (lo & MSR_IA32_APIC_BASE_BSP) != 0; is_lapic_enabled = (lo & MSR_IA32_APIC_BASE_ENABLE) != 0; lapic_base = (lo & MSR_IA32_APIC_BASE_BASE); kprintf("MSR_IA32_APIC_BASE %p %s %s\n", (void *) lapic_base, is_lapic_enabled ? "enabled" : "disabled", is_boot_processor ? "BSP" : "AP"); if (!is_boot_processor || !is_lapic_enabled) panic("Unexpected local APIC state\n"); /* Establish a map to the local apic */ lapic_start = (vm_offset_t)vm_map_min(kernel_map); result = vm_map_find_space(kernel_map, (vm_map_address_t *) &lapic_start, round_page(LAPIC_SIZE), 0, VM_MAKE_TAG(VM_MEMORY_IOKIT), &entry); if (result != KERN_SUCCESS) { panic("smp_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". */ pmap_enter(pmap_kernel(), lapic_start, (ppnum_t) i386_btop(lapic_base), VM_PROT_READ|VM_PROT_WRITE, VM_WIMG_IO, TRUE); lapic_id = (unsigned long)(lapic_start + LAPIC_ID); 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)); } /* 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); kprintf("Boot cpu local APIC id 0x%x\n", cpu_to_lapic[0]); }
static int lapic_esr_read(void) { /* write-read register */ LAPIC_WRITE(ERROR_STATUS, 0); return LAPIC_READ(ERROR_STATUS); }
static uint64_t rtc_lapic_set_timer(uint64_t deadline, uint64_t now) { uint64_t count; uint64_t set = 0; if (deadline > 0) { /* * Convert delta to bus ticks * - time now is not relevant */ count = deadline_to_decrementer(deadline, now); set = now + count; lapic_set_timer_fast((uint32_t) tmrCvt(count, busFCvtn2t)); } else { lapic_set_timer(FALSE, one_shot, divide_by_1, 0); } KERNEL_DEBUG_CONSTANT( DECR_SET_APIC_DEADLINE | DBG_FUNC_NONE, now, deadline, set, LAPIC_READ(TIMER_CURRENT_COUNT), 0); return set; }
int x86_cpu_send_ipi(unsigned char dest_shorthand, unsigned int dst, unsigned int v) { assert((v & LAPIC_ICR_DM_INIT) || (v & LAPIC_ICR_LEVELASSERT)); /* if we've initialized SMP, but we've disabled it, don't send any IPIs */ if(!(kernel_state_flags & KSF_SMP_ENABLE)) return 1; int to, send_status; int old = cpu_interrupt_set(0); spinlock_acquire(&ipi_lock); /* Writing to the lower ICR register causes the interrupt * to get sent off (Intel 3A 10.6.1), so do the higher reg first */ LAPIC_WRITE(LAPIC_ICR+0x10, (dst << 24)); unsigned lower = v | (dest_shorthand << 18); /* gotta have assert for all except init */ LAPIC_WRITE(LAPIC_ICR, lower); /* Wait for send to finish */ to = 0; do { asm("pause"); send_status = LAPIC_READ(LAPIC_ICR) & LAPIC_ICR_STATUS_PEND; } while (send_status && (to++ < 1000)); spinlock_release(&ipi_lock); cpu_interrupt_set(old); return (to < 1000); }
void lapic_shutdown(void) { uint32_t lo; uint32_t hi; uint32_t value; /* Shutdown if local APIC was enabled by OS */ if (lapic_os_enabled == FALSE) return; mp_disable_preemption(); /* ExtINT: masked */ if (get_cpu_number() == master_cpu) { value = LAPIC_READ(LVT_LINT0); value |= LAPIC_LVT_MASKED; LAPIC_WRITE(LVT_LINT0, value); } /* Error: masked */ LAPIC_WRITE(LVT_ERROR, LAPIC_READ(LVT_ERROR) | LAPIC_LVT_MASKED); /* Timer: masked */ LAPIC_WRITE(LVT_TIMER, LAPIC_READ(LVT_TIMER) | LAPIC_LVT_MASKED); /* Perfmon: masked */ LAPIC_WRITE(LVT_PERFCNT, LAPIC_READ(LVT_PERFCNT) | LAPIC_LVT_MASKED); /* APIC software disabled */ LAPIC_WRITE(SVR, LAPIC_READ(SVR) & ~LAPIC_SVR_ENABLE); /* Bypass the APIC completely and update cpu features */ rdmsr(MSR_IA32_APIC_BASE, lo, hi); lo &= ~MSR_IA32_APIC_BASE_ENABLE; wrmsr(MSR_IA32_APIC_BASE, lo, hi); cpuid_set_info(); mp_enable_preemption(); }
void lapic_init(void) { uint32_t lo; 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); is_boot_processor = (lo & MSR_IA32_APIC_BASE_BSP) != 0; is_lapic_enabled = (lo & MSR_IA32_APIC_BASE_ENABLE) != 0; is_x2apic = (lo & MSR_IA32_APIC_BASE_EXTENDED) != 0; lapic_pbase = (lo & MSR_IA32_APIC_BASE_BASE); kprintf("MSR_IA32_APIC_BASE 0x%llx %s %s mode %s\n", lapic_pbase, is_lapic_enabled ? "enabled" : "disabled", is_x2apic ? "extended" : "legacy", is_boot_processor ? "BSP" : "AP"); if (!is_boot_processor || !is_lapic_enabled) panic("Unexpected local APIC state\n"); lapic_ops = is_x2apic ? &x2apic_ops : &legacy_ops; lapic_ops->init(); 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)); } /* 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); kprintf("Boot cpu local APIC id 0x%x\n", cpu_to_lapic[0]); }
void lapic_dump(void) { int i; #define BOOL(a) ((a)?' ':'!') #define VEC(lvt) \ LAPIC_READ(lvt)&LAPIC_LVT_VECTOR_MASK #define DS(lvt) \ (LAPIC_READ(lvt)&LAPIC_LVT_DS_PENDING)?" SendPending" : "Idle" #define DM(lvt) \ DM_str[(LAPIC_READ(lvt)>>LAPIC_LVT_DM_SHIFT)&LAPIC_LVT_DM_MASK] #define MASK(lvt) \ BOOL(LAPIC_READ(lvt)&LAPIC_LVT_MASKED) #define TM(lvt) \ (LAPIC_READ(lvt)&LAPIC_LVT_TM_LEVEL)? "Level" : "Edge" #define IP(lvt) \ (LAPIC_READ(lvt)&LAPIC_LVT_IP_PLRITY_LOW)? "Low " : "High" kprintf("LAPIC %d at %p version 0x%x\n", (LAPIC_READ(ID)>>LAPIC_ID_SHIFT)&LAPIC_ID_MASK, (void *) lapic_start, LAPIC_READ(VERSION)&LAPIC_VERSION_MASK); kprintf("Priorities: Task 0x%x Arbitration 0x%x Processor 0x%x\n", LAPIC_READ(TPR)&LAPIC_TPR_MASK, 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, LAPIC_READ(LDR)>>LAPIC_LDR_SHIFT); kprintf("%cEnabled %cFocusChecking SV 0x%x\n", BOOL(LAPIC_READ(SVR)&LAPIC_SVR_ENABLE), BOOL(!(LAPIC_READ(SVR)&LAPIC_SVR_FOCUS_OFF)), LAPIC_READ(SVR) & LAPIC_SVR_MASK); #if CONFIG_MCA if (mca_is_cmci_present()) kprintf("LVT_CMCI: Vector 0x%02x [%s] %s %cmasked\n", VEC(LVT_CMCI), DM(LVT_CMCI), DS(LVT_CMCI), MASK(LVT_CMCI)); #endif kprintf("LVT_TIMER: Vector 0x%02x %s %cmasked %s\n", VEC(LVT_TIMER), DS(LVT_TIMER), MASK(LVT_TIMER), (LAPIC_READ(LVT_TIMER)&LAPIC_LVT_PERIODIC)?"Periodic":"OneShot"); kprintf(" Initial Count: 0x%08x \n", LAPIC_READ(TIMER_INITIAL_COUNT)); kprintf(" Current Count: 0x%08x \n", LAPIC_READ(TIMER_CURRENT_COUNT)); kprintf(" Divide Config: 0x%08x \n", LAPIC_READ(TIMER_DIVIDE_CONFIG)); kprintf("LVT_PERFCNT: Vector 0x%02x [%s] %s %cmasked\n", VEC(LVT_PERFCNT), DM(LVT_PERFCNT), DS(LVT_PERFCNT), MASK(LVT_PERFCNT)); kprintf("LVT_THERMAL: Vector 0x%02x [%s] %s %cmasked\n", VEC(LVT_THERMAL), DM(LVT_THERMAL), DS(LVT_THERMAL), MASK(LVT_THERMAL)); kprintf("LVT_LINT0: Vector 0x%02x [%s][%s][%s] %s %cmasked\n", VEC(LVT_LINT0), DM(LVT_LINT0), TM(LVT_LINT0), IP(LVT_LINT0), DS(LVT_LINT0), MASK(LVT_LINT0)); kprintf("LVT_LINT1: Vector 0x%02x [%s][%s][%s] %s %cmasked\n", VEC(LVT_LINT1), DM(LVT_LINT1), TM(LVT_LINT1), IP(LVT_LINT1), DS(LVT_LINT1), MASK(LVT_LINT1)); kprintf("LVT_ERROR: Vector 0x%02x %s %cmasked\n", VEC(LVT_ERROR), DS(LVT_ERROR), MASK(LVT_ERROR)); kprintf("ESR: %08x \n", lapic_esr_read()); kprintf(" "); for(i=0xf; i>=0; i--) kprintf("%x%x%x%x",i,i,i,i); kprintf("\n"); kprintf("TMR: 0x"); for(i=7; i>=0; i--) kprintf("%08x",LAPIC_READ_OFFSET(TMR_BASE, i*0x10)); kprintf("\n"); kprintf("IRR: 0x"); for(i=7; i>=0; i--) kprintf("%08x",LAPIC_READ_OFFSET(IRR_BASE, i*0x10)); kprintf("\n"); kprintf("ISR: 0x"); for(i=7; i >= 0; i--) kprintf("%08x",LAPIC_READ_OFFSET(ISR_BASE, i*0x10)); kprintf("\n"); }