Date: Sat, 15 Mar 2014 23:09:35 +0000 (UTC) From: Tycho Nightingale <tychon@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r263211 - in head/sys/amd64: include vmm vmm/intel vmm/io Message-ID: <201403152309.s2FN9ZWf029583@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: tychon Date: Sat Mar 15 23:09:34 2014 New Revision: 263211 URL: http://svnweb.freebsd.org/changeset/base/263211 Log: Fix a race wherein the source of an interrupt vector is wrongly attributed if an ExtINT arrives during interrupt injection. Also, fix a spurious interrupt if the PIC tries to raise an interrupt before the outstanding one is accepted. Finally, improve the PIC interrupt latency when another interrupt is raised immediately after the outstanding one is accepted by creating a vmexit rather than waiting for one to occur by happenstance. Approved by: neel (co-mentor) Modified: head/sys/amd64/include/vmm.h head/sys/amd64/vmm/intel/vmx.c head/sys/amd64/vmm/io/vatpic.c head/sys/amd64/vmm/io/vatpic.h head/sys/amd64/vmm/io/vlapic.c head/sys/amd64/vmm/io/vlapic_priv.h head/sys/amd64/vmm/vmm.c Modified: head/sys/amd64/include/vmm.h ============================================================================== --- head/sys/amd64/include/vmm.h Sat Mar 15 21:58:07 2014 (r263210) +++ head/sys/amd64/include/vmm.h Sat Mar 15 23:09:34 2014 (r263211) @@ -117,6 +117,9 @@ int vm_run(struct vm *vm, struct vm_run int vm_inject_nmi(struct vm *vm, int vcpu); int vm_nmi_pending(struct vm *vm, int vcpuid); void vm_nmi_clear(struct vm *vm, int vcpuid); +int vm_inject_extint(struct vm *vm, int vcpu); +int vm_extint_pending(struct vm *vm, int vcpuid); +void vm_extint_clear(struct vm *vm, int vcpuid); uint64_t *vm_guest_msrs(struct vm *vm, int cpu); struct vlapic *vm_lapic(struct vm *vm, int cpu); struct vioapic *vm_ioapic(struct vm *vm); Modified: head/sys/amd64/vmm/intel/vmx.c ============================================================================== --- head/sys/amd64/vmm/intel/vmx.c Sat Mar 15 21:58:07 2014 (r263210) +++ head/sys/amd64/vmm/intel/vmx.c Sat Mar 15 23:09:34 2014 (r263211) @@ -57,6 +57,7 @@ __FBSDID("$FreeBSD$"); #include "vmm_msr.h" #include "vmm_ktr.h" #include "vmm_stat.h" +#include "vatpic.h" #include "vlapic.h" #include "vlapic_priv.h" @@ -1144,7 +1145,7 @@ static void vmx_inject_interrupts(struct vmx *vmx, int vcpu, struct vlapic *vlapic) { struct vm_exception exc; - int vector, need_nmi_exiting; + int vector, need_nmi_exiting, extint_pending; uint64_t rflags; uint32_t gi, info; @@ -1196,7 +1197,9 @@ vmx_inject_interrupts(struct vmx *vmx, i vmx_set_nmi_window_exiting(vmx, vcpu); } - if (virtual_interrupt_delivery) { + extint_pending = vm_extint_pending(vmx->vm, vcpu); + + if (!extint_pending && virtual_interrupt_delivery) { vmx_inject_pir(vlapic); return; } @@ -1212,9 +1215,14 @@ vmx_inject_interrupts(struct vmx *vmx, i return; } - /* Ask the local apic for a vector to inject */ - if (!vlapic_pending_intr(vlapic, &vector)) - return; + if (!extint_pending) { + /* Ask the local apic for a vector to inject */ + if (!vlapic_pending_intr(vlapic, &vector)) + return; + } else { + /* Ask the legacy pic for a vector to inject */ + vatpic_pending_intr(vmx->vm, &vector); + } KASSERT(vector >= 32 && vector <= 255, ("invalid vector %d", vector)); @@ -1252,8 +1260,22 @@ vmx_inject_interrupts(struct vmx *vmx, i info |= vector; vmcs_write(VMCS_ENTRY_INTR_INFO, info); - /* Update the Local APIC ISR */ - vlapic_intr_accepted(vlapic, vector); + if (!extint_pending) { + /* Update the Local APIC ISR */ + vlapic_intr_accepted(vlapic, vector); + } else { + vm_extint_clear(vmx->vm, vcpu); + vatpic_intr_accepted(vmx->vm, vector); + + /* + * After we accepted the current ExtINT the PIC may + * have posted another one. If that is the case, set + * the Interrupt Window Exiting execution control so + * we can inject that one too. + */ + if (vm_extint_pending(vmx->vm, vcpu)) + vmx_set_int_window_exiting(vmx, vcpu); + } VCPU_CTR1(vmx->vm, vcpu, "Injecting hwintr at vector %d", vector); Modified: head/sys/amd64/vmm/io/vatpic.c ============================================================================== --- head/sys/amd64/vmm/io/vatpic.c Sat Mar 15 21:58:07 2014 (r263210) +++ head/sys/amd64/vmm/io/vatpic.c Sat Mar 15 23:09:34 2014 (r263211) @@ -82,6 +82,8 @@ struct vatpic { struct mtx mtx; struct atpic atpic[2]; uint8_t elc[2]; + + bool intr_raised; }; #define VATPIC_CTR0(vatpic, fmt) \ @@ -148,6 +150,9 @@ vatpic_notify_intr(struct vatpic *vatpic KASSERT(VATPIC_LOCKED(vatpic), ("vatpic_notify_intr not locked")); + if (vatpic->intr_raised == true) + return; + /* XXX master only */ atpic = &vatpic->atpic[0]; @@ -155,8 +160,32 @@ vatpic_notify_intr(struct vatpic *vatpic VATPIC_CTR4(vatpic, "atpic notify pin = %d " "(imr 0x%x irr 0x%x isr 0x%x)", pin, atpic->mask, atpic->request, atpic->service); + + /* + * PIC interrupts are routed to both the Local APIC + * and the I/O APIC to support operation in 1 of 3 + * modes. + * + * 1. Legacy PIC Mode: the PIC effectively bypasses + * all APIC components. In mode '1' the local APIC is + * disabled and LINT0 is reconfigured as INTR to + * deliver the PIC interrupt directly to the CPU. + * + * 2. Virtual Wire Mode: the APIC is treated as a + * virtual wire which delivers interrupts from the PIC + * to the CPU. In mode '2' LINT0 is programmed as + * ExtINT to indicate that the PIC is the source of + * the interrupt. + * + * 3. Symmetric I/O Mode: PIC interrupts are fielded + * by the I/O APIC and delivered to the appropriate + * CPU. In mode '3' the I/O APIC input 0 is + * programmed as ExtINT to indicate that the PIC is + * the source of the interrupt. + */ lapic_set_local_intr(vatpic->vm, -1, APIC_LVT_LINT0); vioapic_pulse_irq(vatpic->vm, 0); + vatpic->intr_raised = true; } else { VATPIC_CTR3(vatpic, "atpic no eligible interrupts " "(imr 0x%x irr 0x%x isr 0x%x)", @@ -384,7 +413,7 @@ vatpic_pulse_irq(struct vm *vm, int irq) return (vatpic_set_irqstate(vm, irq, IRQSTATE_PULSE)); } -int +void vatpic_pending_intr(struct vm *vm, int *vecptr) { struct vatpic *vatpic; @@ -405,8 +434,6 @@ vatpic_pending_intr(struct vm *vm, int * *vecptr = atpic->irq_base + pin; VATPIC_UNLOCK(vatpic); - - return (1); } void @@ -422,6 +449,8 @@ vatpic_intr_accepted(struct vm *vm, int atpic = &vatpic->atpic[0]; VATPIC_LOCK(vatpic); + vatpic->intr_raised = false; + pin = vector & 0x7; if (atpic->acnt[pin] == 0) Modified: head/sys/amd64/vmm/io/vatpic.h ============================================================================== --- head/sys/amd64/vmm/io/vatpic.h Sat Mar 15 21:58:07 2014 (r263210) +++ head/sys/amd64/vmm/io/vatpic.h Sat Mar 15 23:09:34 2014 (r263211) @@ -47,7 +47,7 @@ int vatpic_assert_irq(struct vm *vm, int int vatpic_deassert_irq(struct vm *vm, int irq); int vatpic_pulse_irq(struct vm *vm, int irq); -int vatpic_pending_intr(struct vm *vm, int *vecptr); +void vatpic_pending_intr(struct vm *vm, int *vecptr); void vatpic_intr_accepted(struct vm *vm, int vector); #endif /* _VATPIC_H_ */ Modified: head/sys/amd64/vmm/io/vlapic.c ============================================================================== --- head/sys/amd64/vmm/io/vlapic.c Sat Mar 15 21:58:07 2014 (r263210) +++ head/sys/amd64/vmm/io/vlapic.c Sat Mar 15 23:09:34 2014 (r263211) @@ -52,7 +52,6 @@ __FBSDID("$FreeBSD$"); #include "vlapic.h" #include "vlapic_priv.h" -#include "vatpic.h" #include "vioapic.h" #define PRIO(x) ((x) >> 4) @@ -300,16 +299,6 @@ vlapic_set_intr_ready(struct vlapic *vla return (1); } -static VMM_STAT(VLAPIC_EXTINT_COUNT, "number of ExtINTs received by vlapic"); - -static void -vlapic_deliver_extint(struct vlapic *vlapic) -{ - vmm_stat_incr(vlapic->vm, vlapic->vcpuid, VLAPIC_EXTINT_COUNT, 1); - vlapic->extint_pending = true; - vcpu_notify_event(vlapic->vm, vlapic->vcpuid, false); -} - static __inline uint32_t * vlapic_get_lvtptr(struct vlapic *vlapic, uint32_t offset) { @@ -460,7 +449,7 @@ vlapic_fire_lvt(struct vlapic *vlapic, u vm_inject_nmi(vlapic->vm, vlapic->vcpuid); break; case APIC_LVT_DM_EXTINT: - vlapic_deliver_extint(vlapic); + vm_inject_extint(vlapic->vm, vlapic->vcpuid); break; default: // Other modes ignored @@ -673,7 +662,7 @@ vlapic_trigger_lvt(struct vlapic *vlapic */ switch (vector) { case APIC_LVT_LINT0: - vlapic_deliver_extint(vlapic); + vm_inject_extint(vlapic->vm, vlapic->vcpuid); break; case APIC_LVT_LINT1: vm_inject_nmi(vlapic->vm, vlapic->vcpuid); @@ -1053,13 +1042,6 @@ vlapic_pending_intr(struct vlapic *vlapi int idx, i, bitpos, vector; uint32_t *irrptr, val; - if (vlapic->extint_pending) { - if (vecptr == NULL) - return (1); - else - return (vatpic_pending_intr(vlapic->vm, vecptr)); - } - if (vlapic->ops.pending_intr) return ((*vlapic->ops.pending_intr)(vlapic, vecptr)); @@ -1094,12 +1076,6 @@ vlapic_intr_accepted(struct vlapic *vlap uint32_t *irrptr, *isrptr; int idx, stk_top; - if (vlapic->extint_pending) { - vlapic->extint_pending = false; - vatpic_intr_accepted(vlapic->vm, vector); - return; - } - if (vlapic->ops.intr_accepted) return ((*vlapic->ops.intr_accepted)(vlapic, vector)); @@ -1539,7 +1515,7 @@ vlapic_deliver_intr(struct vm *vm, bool vcpuid--; CPU_CLR(vcpuid, &dmask); if (delmode == IOART_DELEXINT) { - vlapic_deliver_extint(vm_lapic(vm, vcpuid)); + vm_inject_extint(vm, vcpuid); } else { lapic_set_intr(vm, vcpuid, vec, level); } Modified: head/sys/amd64/vmm/io/vlapic_priv.h ============================================================================== --- head/sys/amd64/vmm/io/vlapic_priv.h Sat Mar 15 21:58:07 2014 (r263210) +++ head/sys/amd64/vmm/io/vlapic_priv.h Sat Mar 15 23:09:34 2014 (r263211) @@ -156,8 +156,6 @@ struct vlapic { uint32_t esr_pending; int esr_firing; - bool extint_pending; - struct callout callout; /* vlapic timer */ struct bintime timer_fire_bt; /* callout expiry time */ struct bintime timer_freq_bt; /* timer frequency */ Modified: head/sys/amd64/vmm/vmm.c ============================================================================== --- head/sys/amd64/vmm/vmm.c Sat Mar 15 21:58:07 2014 (r263210) +++ head/sys/amd64/vmm/vmm.c Sat Mar 15 23:09:34 2014 (r263211) @@ -95,6 +95,7 @@ struct vcpu { struct vm_exit exitinfo; enum x2apic_state x2apic_state; int nmi_pending; + int extint_pending; struct vm_exception exception; int exception_pending; }; @@ -1351,6 +1352,53 @@ vm_nmi_clear(struct vm *vm, int vcpuid) vmm_stat_incr(vm, vcpuid, VCPU_NMI_COUNT, 1); } +static VMM_STAT(VCPU_EXTINT_COUNT, "number of ExtINTs delivered to vcpu"); + +int +vm_inject_extint(struct vm *vm, int vcpuid) +{ + struct vcpu *vcpu; + + if (vcpuid < 0 || vcpuid >= VM_MAXCPU) + return (EINVAL); + + vcpu = &vm->vcpu[vcpuid]; + + vcpu->extint_pending = 1; + vcpu_notify_event(vm, vcpuid, false); + return (0); +} + +int +vm_extint_pending(struct vm *vm, int vcpuid) +{ + struct vcpu *vcpu; + + if (vcpuid < 0 || vcpuid >= VM_MAXCPU) + panic("vm_extint_pending: invalid vcpuid %d", vcpuid); + + vcpu = &vm->vcpu[vcpuid]; + + return (vcpu->extint_pending); +} + +void +vm_extint_clear(struct vm *vm, int vcpuid) +{ + struct vcpu *vcpu; + + if (vcpuid < 0 || vcpuid >= VM_MAXCPU) + panic("vm_extint_pending: invalid vcpuid %d", vcpuid); + + vcpu = &vm->vcpu[vcpuid]; + + if (vcpu->extint_pending == 0) + panic("vm_extint_clear: inconsistent extint_pending state"); + + vcpu->extint_pending = 0; + vmm_stat_incr(vm, vcpuid, VCPU_EXTINT_COUNT, 1); +} + int vm_get_capability(struct vm *vm, int vcpu, int type, int *retval) {
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201403152309.s2FN9ZWf029583>