Changeset View
Changeset View
Standalone View
Standalone View
sys/x86/x86/local_apic.c
Show First 20 Lines • Show All 165 Lines • ▼ Show 20 Lines | static inthand_t *ioint_handlers[] = { | ||||
IDTVEC(apic_isr2), /* 64 - 95 */ | IDTVEC(apic_isr2), /* 64 - 95 */ | ||||
IDTVEC(apic_isr3), /* 96 - 127 */ | IDTVEC(apic_isr3), /* 96 - 127 */ | ||||
IDTVEC(apic_isr4), /* 128 - 159 */ | IDTVEC(apic_isr4), /* 128 - 159 */ | ||||
IDTVEC(apic_isr5), /* 160 - 191 */ | IDTVEC(apic_isr5), /* 160 - 191 */ | ||||
IDTVEC(apic_isr6), /* 192 - 223 */ | IDTVEC(apic_isr6), /* 192 - 223 */ | ||||
IDTVEC(apic_isr7), /* 224 - 255 */ | IDTVEC(apic_isr7), /* 224 - 255 */ | ||||
}; | }; | ||||
static inthand_t *ioint_pti_handlers[] = { | |||||
NULL, /* 0 - 31 */ | |||||
IDTVEC(apic_isr1_pti), /* 32 - 63 */ | |||||
IDTVEC(apic_isr2_pti), /* 64 - 95 */ | |||||
IDTVEC(apic_isr3_pti), /* 96 - 127 */ | |||||
IDTVEC(apic_isr4_pti), /* 128 - 159 */ | |||||
IDTVEC(apic_isr5_pti), /* 160 - 191 */ | |||||
IDTVEC(apic_isr6_pti), /* 192 - 223 */ | |||||
IDTVEC(apic_isr7_pti), /* 224 - 255 */ | |||||
}; | |||||
static u_int32_t lapic_timer_divisors[] = { | static u_int32_t lapic_timer_divisors[] = { | ||||
APIC_TDCR_1, APIC_TDCR_2, APIC_TDCR_4, APIC_TDCR_8, APIC_TDCR_16, | APIC_TDCR_1, APIC_TDCR_2, APIC_TDCR_4, APIC_TDCR_8, APIC_TDCR_16, | ||||
APIC_TDCR_32, APIC_TDCR_64, APIC_TDCR_128 | APIC_TDCR_32, APIC_TDCR_64, APIC_TDCR_128 | ||||
}; | }; | ||||
extern inthand_t IDTVEC(rsvd); | extern inthand_t IDTVEC(rsvd_pti), IDTVEC(rsvd); | ||||
volatile char *lapic_map; | volatile char *lapic_map; | ||||
vm_paddr_t lapic_paddr; | vm_paddr_t lapic_paddr; | ||||
int x2apic_mode; | int x2apic_mode; | ||||
int lapic_eoi_suppression; | int lapic_eoi_suppression; | ||||
static int lapic_timer_tsc_deadline; | static int lapic_timer_tsc_deadline; | ||||
static u_long lapic_timer_divisor, count_freq; | static u_long lapic_timer_divisor, count_freq; | ||||
static struct eventtimer lapic_et; | static struct eventtimer lapic_et; | ||||
▲ Show 20 Lines • Show All 302 Lines • ▼ Show 20 Lines | #endif | ||||
/* Perform basic initialization of the BSP's local APIC. */ | /* Perform basic initialization of the BSP's local APIC. */ | ||||
lapic_enable(); | lapic_enable(); | ||||
/* Set BSP's per-CPU local APIC ID. */ | /* Set BSP's per-CPU local APIC ID. */ | ||||
PCPU_SET(apic_id, lapic_id()); | PCPU_SET(apic_id, lapic_id()); | ||||
/* Local APIC timer interrupt. */ | /* Local APIC timer interrupt. */ | ||||
setidt(APIC_TIMER_INT, IDTVEC(timerint), SDT_APIC, SEL_KPL, GSEL_APIC); | setidt(APIC_TIMER_INT, pti ? IDTVEC(timerint_pti) : IDTVEC(timerint), | ||||
SDT_APIC, SEL_KPL, GSEL_APIC); | |||||
/* Local APIC error interrupt. */ | /* Local APIC error interrupt. */ | ||||
setidt(APIC_ERROR_INT, IDTVEC(errorint), SDT_APIC, SEL_KPL, GSEL_APIC); | setidt(APIC_ERROR_INT, pti ? IDTVEC(errorint_pti) : IDTVEC(errorint), | ||||
SDT_APIC, SEL_KPL, GSEL_APIC); | |||||
/* XXX: Thermal interrupt */ | /* XXX: Thermal interrupt */ | ||||
/* Local APIC CMCI. */ | /* Local APIC CMCI. */ | ||||
setidt(APIC_CMC_INT, IDTVEC(cmcint), SDT_APICT, SEL_KPL, GSEL_APIC); | setidt(APIC_CMC_INT, pti ? IDTVEC(cmcint_pti) : IDTVEC(cmcint), | ||||
SDT_APICT, SEL_KPL, GSEL_APIC); | |||||
if ((resource_int_value("apic", 0, "clock", &i) != 0 || i != 0)) { | if ((resource_int_value("apic", 0, "clock", &i) != 0 || i != 0)) { | ||||
arat = 0; | arat = 0; | ||||
/* Intel CPUID 0x06 EAX[2] set if APIC timer runs in C3. */ | /* Intel CPUID 0x06 EAX[2] set if APIC timer runs in C3. */ | ||||
if (cpu_vendor_id == CPU_VENDOR_INTEL && cpu_high >= 6) { | if (cpu_vendor_id == CPU_VENDOR_INTEL && cpu_high >= 6) { | ||||
do_cpuid(0x06, regs); | do_cpuid(0x06, regs); | ||||
if ((regs[0] & CPUTPM1_ARAT) != 0) | if ((regs[0] & CPUTPM1_ARAT) != 0) | ||||
arat = 1; | arat = 1; | ||||
▲ Show 20 Lines • Show All 1,048 Lines • ▼ Show 20 Lines | native_apic_enable_vector(u_int apic_id, u_int vector) | ||||
KASSERT(vector != IDT_SYSCALL, ("Attempt to overwrite syscall entry")); | KASSERT(vector != IDT_SYSCALL, ("Attempt to overwrite syscall entry")); | ||||
KASSERT(ioint_handlers[vector / 32] != NULL, | KASSERT(ioint_handlers[vector / 32] != NULL, | ||||
("No ISR handler for vector %u", vector)); | ("No ISR handler for vector %u", vector)); | ||||
#ifdef KDTRACE_HOOKS | #ifdef KDTRACE_HOOKS | ||||
KASSERT(vector != IDT_DTRACE_RET, | KASSERT(vector != IDT_DTRACE_RET, | ||||
("Attempt to overwrite DTrace entry")); | ("Attempt to overwrite DTrace entry")); | ||||
#endif | #endif | ||||
setidt(vector, ioint_handlers[vector / 32], SDT_APIC, SEL_KPL, | setidt(vector, (pti ? ioint_pti_handlers : ioint_handlers)[vector / 32], | ||||
GSEL_APIC); | SDT_APIC, SEL_KPL, GSEL_APIC); | ||||
} | } | ||||
static void | static void | ||||
native_apic_disable_vector(u_int apic_id, u_int vector) | native_apic_disable_vector(u_int apic_id, u_int vector) | ||||
{ | { | ||||
KASSERT(vector != IDT_SYSCALL, ("Attempt to overwrite syscall entry")); | KASSERT(vector != IDT_SYSCALL, ("Attempt to overwrite syscall entry")); | ||||
#ifdef KDTRACE_HOOKS | #ifdef KDTRACE_HOOKS | ||||
KASSERT(vector != IDT_DTRACE_RET, | KASSERT(vector != IDT_DTRACE_RET, | ||||
("Attempt to overwrite DTrace entry")); | ("Attempt to overwrite DTrace entry")); | ||||
#endif | #endif | ||||
KASSERT(ioint_handlers[vector / 32] != NULL, | KASSERT(ioint_handlers[vector / 32] != NULL, | ||||
("No ISR handler for vector %u", vector)); | ("No ISR handler for vector %u", vector)); | ||||
#ifdef notyet | #ifdef notyet | ||||
/* | /* | ||||
* We can not currently clear the idt entry because other cpus | * We can not currently clear the idt entry because other cpus | ||||
* may have a valid vector at this offset. | * may have a valid vector at this offset. | ||||
*/ | */ | ||||
setidt(vector, &IDTVEC(rsvd), SDT_APICT, SEL_KPL, GSEL_APIC); | setidt(vector, pti ? &IDTVEC(rsvd_pti) : &IDTVEC(rsvd), SDT_APICT, | ||||
SEL_KPL, GSEL_APIC); | |||||
#endif | #endif | ||||
} | } | ||||
/* Release an APIC vector when it's no longer in use. */ | /* Release an APIC vector when it's no longer in use. */ | ||||
static void | static void | ||||
native_apic_free_vector(u_int apic_id, u_int vector, u_int irq) | native_apic_free_vector(u_int apic_id, u_int vector, u_int irq) | ||||
{ | { | ||||
struct thread *td; | struct thread *td; | ||||
▲ Show 20 Lines • Show All 481 Lines • ▼ Show 20 Lines | |||||
* Consider the case where an IPI is generated immediately after allocation: | * Consider the case where an IPI is generated immediately after allocation: | ||||
* vector = lapic_ipi_alloc(ipifunc); | * vector = lapic_ipi_alloc(ipifunc); | ||||
* ipi_selected(other_cpus, vector); | * ipi_selected(other_cpus, vector); | ||||
* | * | ||||
* In xAPIC mode a write to ICR_LO has serializing semantics because the | * In xAPIC mode a write to ICR_LO has serializing semantics because the | ||||
* APIC page is mapped as an uncached region. In x2APIC mode there is an | * APIC page is mapped as an uncached region. In x2APIC mode there is an | ||||
* explicit 'mfence' before the ICR MSR is written. Therefore in both cases | * explicit 'mfence' before the ICR MSR is written. Therefore in both cases | ||||
* the IDT slot update is globally visible before the IPI is delivered. | * the IDT slot update is globally visible before the IPI is delivered. | ||||
* XXX pti | |||||
*/ | */ | ||||
static int | static int | ||||
native_lapic_ipi_alloc(inthand_t *ipifunc) | native_lapic_ipi_alloc(inthand_t *ipifunc) | ||||
{ | { | ||||
struct gate_descriptor *ip; | struct gate_descriptor *ip; | ||||
long func; | long func; | ||||
int idx, vector; | int idx, vector; | ||||
KASSERT(ipifunc != &IDTVEC(rsvd), ("invalid ipifunc %p", ipifunc)); | KASSERT(ipifunc != &IDTVEC(rsvd) && ipifunc != &IDTVEC(rsvd_pti), | ||||
("invalid ipifunc %p", ipifunc)); | |||||
vector = -1; | vector = -1; | ||||
mtx_lock_spin(&icu_lock); | mtx_lock_spin(&icu_lock); | ||||
for (idx = IPI_DYN_FIRST; idx <= IPI_DYN_LAST; idx++) { | for (idx = IPI_DYN_FIRST; idx <= IPI_DYN_LAST; idx++) { | ||||
ip = &idt[idx]; | ip = &idt[idx]; | ||||
func = (ip->gd_hioffset << 16) | ip->gd_looffset; | func = (ip->gd_hioffset << 16) | ip->gd_looffset; | ||||
if (func == (uintptr_t)&IDTVEC(rsvd)) { | if (func == (uintptr_t)&IDTVEC(rsvd)) { | ||||
vector = idx; | vector = idx; | ||||
Show All 12 Lines | native_lapic_ipi_free(int vector) | ||||
long func; | long func; | ||||
KASSERT(vector >= IPI_DYN_FIRST && vector <= IPI_DYN_LAST, | KASSERT(vector >= IPI_DYN_FIRST && vector <= IPI_DYN_LAST, | ||||
("%s: invalid vector %d", __func__, vector)); | ("%s: invalid vector %d", __func__, vector)); | ||||
mtx_lock_spin(&icu_lock); | mtx_lock_spin(&icu_lock); | ||||
ip = &idt[vector]; | ip = &idt[vector]; | ||||
func = (ip->gd_hioffset << 16) | ip->gd_looffset; | func = (ip->gd_hioffset << 16) | ip->gd_looffset; | ||||
KASSERT(func != (uintptr_t)&IDTVEC(rsvd), | KASSERT(func != (uintptr_t)&IDTVEC(rsvd) && | ||||
func != (uintptr_t)&IDTVEC(rsvd_pti), | |||||
("invalid idtfunc %#lx", func)); | ("invalid idtfunc %#lx", func)); | ||||
setidt(vector, &IDTVEC(rsvd), SDT_APICT, SEL_KPL, GSEL_APIC); | setidt(vector, pti ? &IDTVEC(rsvd_pti) : &IDTVEC(rsvd), SDT_APICT, | ||||
SEL_KPL, GSEL_APIC); | |||||
mtx_unlock_spin(&icu_lock); | mtx_unlock_spin(&icu_lock); | ||||
} | } |