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); }
static int lapic_esr_read(void) { /* write-read register */ LAPIC_WRITE(ERROR_STATUS, 0); return LAPIC_READ(ERROR_STATUS); }
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(); }
static void lapic_esr_clear(void) { LAPIC_WRITE(ERROR_STATUS, 0); LAPIC_WRITE(ERROR_STATUS, 0); }