Index: sys/amd64/vmm/amd/svm.c =================================================================== --- sys/amd64/vmm/amd/svm.c (revision 270437) +++ sys/amd64/vmm/amd/svm.c (working copy) @@ -702,6 +702,9 @@ vmexit->exitcode = VM_EXITCODE_VMX; vmexit->u.vmx.status = 0; + KASSERT((ctrl->eventinj & VMCB_EVENTINJ_VALID) == 0, ("%s: event " + "injection valid bit is set %#lx", __func__, ctrl->eventinj)); + switch (code) { case VMCB_EXIT_MC: /* Machine Check. */ vmm_stat_incr(svm_sc->vm, vcpu, VMEXIT_MTRAP, 1); @@ -930,11 +933,8 @@ if (!vm_nmi_pending(svm_sc->vm, vcpu)) return (0); - /* Inject NMI, vector number is not used.*/ - if (vmcb_eventinject(ctrl, VMCB_EVENTINJ_TYPE_NMI, IDT_NMI, 0, false)) { - VCPU_CTR0(svm_sc->vm, vcpu, "SVM:NMI injection failed.\n"); - return (EIO); - } + /* Inject NMI, vector number is not used.*/ + vmcb_eventinject(ctrl, VMCB_EVENTINJ_TYPE_NMI, IDT_NMI, 0, false); /* Acknowledge the request is accepted.*/ vm_nmi_clear(svm_sc->vm, vcpu); @@ -961,6 +961,13 @@ state = svm_get_vmcb_state(svm_sc, vcpu); ctrl = svm_get_vmcb_ctrl(svm_sc, vcpu); + if (vm_exception_pending(svm_sc->vm, vcpu, &exc)) { + KASSERT(exc.vector >= 0 && exc.vector < 32, + ("Exception vector% invalid", exc.vector)); + vmcb_eventinject(ctrl, VMCB_EVENTINJ_TYPE_EXCEPTION, exc.vector, + exc.error_code, exc.error_code_valid); + } + /* Can't inject multiple events at once. */ if (ctrl->eventinj & VMCB_EVENTINJ_VALID) { VCPU_CTR1(svm_sc->vm, vcpu, @@ -973,18 +980,7 @@ VCPU_CTR0(svm_sc->vm, vcpu, "SVM:Guest in interrupt shadow.\n"); return; } - - if (vm_exception_pending(svm_sc->vm, vcpu, &exc)) { - KASSERT(exc.vector >= 0 && exc.vector < 32, - ("Exception vector% invalid", exc.vector)); - if (vmcb_eventinject(ctrl, VMCB_EVENTINJ_TYPE_EXCEPTION, - exc.vector, exc.error_code, - exc.error_code_valid)) { - VCPU_CTR1(svm_sc->vm, vcpu, "SVM:Exception%d injection" - " failed.\n", exc.vector); - return; - } - } + /* NMI event has priority over interrupts.*/ if (svm_inject_nmi(svm_sc, vcpu)) { return; @@ -1013,11 +1009,7 @@ return; } - if (vmcb_eventinject(ctrl, VMCB_EVENTINJ_TYPE_INTR, vector, 0, false)) { - VCPU_CTR1(svm_sc->vm, vcpu, "SVM:Event injection failed to" - " vector=%d.\n", vector); - return; - } + vmcb_eventinject(ctrl, VMCB_EVENTINJ_TYPE_INTR, vector, 0, false); if (!extint_pending) { /* Update the Local APIC ISR */ @@ -1067,17 +1059,14 @@ */ intinfo = ctrl->exitintinfo; - if (intinfo & VMCB_EXITINTINFO_VALID) { + if (VMCB_EXITINTINFO_VALID(intinfo)) { vmm_stat_incr(svm_sc->vm, vcpu, VCPU_EXITINTINFO, 1); VCPU_CTR1(svm_sc->vm, vcpu, "SVM:EXITINTINFO:0x%lx is valid\n", intinfo); - if (vmcb_eventinject(ctrl, VMCB_EXITINTINFO_TYPE(intinfo), - VMCB_EXITINTINFO_VECTOR(intinfo), - VMCB_EXITINTINFO_EC(intinfo), - VMCB_EXITINTINFO_EC_VALID & intinfo)) { - VCPU_CTR1(svm_sc->vm, vcpu, "SVM:couldn't inject pending" - " interrupt, exitintinfo:0x%lx\n", intinfo); - } + vmcb_eventinject(ctrl, VMCB_EXITINTINFO_TYPE(intinfo), + VMCB_EXITINTINFO_VECTOR(intinfo), + VMCB_EXITINTINFO_EC(intinfo), + VMCB_EXITINTINFO_EC_VALID(intinfo)); } } /* @@ -1198,7 +1187,7 @@ svm_handle_exitintinfo(svm_sc, vcpu); - (void)svm_inj_interrupts(svm_sc, vcpu, vlapic); + svm_inj_interrupts(svm_sc, vcpu, vlapic); /* Change TSS type to available.*/ setup_tss_type(); Index: sys/amd64/vmm/amd/vmcb.c =================================================================== --- sys/amd64/vmm/amd/vmcb.c (revision 270437) +++ sys/amd64/vmm/amd/vmcb.c (working copy) @@ -371,27 +371,32 @@ /* * Inject an event to vcpu as described in section 15.20, "Event injection". */ -int +void vmcb_eventinject(struct vmcb_ctrl *ctrl, int intr_type, int vector, uint32_t error, bool ec_valid) { - if (intr_type < VMCB_EVENTINJ_TYPE_INTR || - intr_type > VMCB_EVENTINJ_TYPE_INTn) { - ERR("Event:%d is not supported by SVM.\n", intr_type); - return (EINVAL); - } + KASSERT((ctrl->eventinj & VMCB_EVENTINJ_VALID) == 0, + ("%s: event already pending %#lx", __func__, ctrl->eventinj)); - if (intr_type == VMCB_EVENTINJ_TYPE_EXCEPTION && vector == IDT_NMI) { - ERR("NMI with Exception type is not possible.\n"); - return (EINVAL); + KASSERT(vector >=0 && vector <= 255, ("%s: invalid vector %d", + __func__, vector)); + + switch (intr_type) { + case VMCB_EVENTINJ_TYPE_INTR: + case VMCB_EVENTINJ_TYPE_NMI: + case VMCB_EVENTINJ_TYPE_INTn: + break; + case VMCB_EVENTINJ_TYPE_EXCEPTION: + if (vector >= 0 && vector <= 31 && vector != 2) + break; + /* FALLTHROUGH */ + default: + panic("%s: invalid intr_type/vector: %d/%d", __func__, + intr_type, vector); } - - ctrl->eventinj = (vector & VMCB_EVENTINJ_VECTOR_MASK) | - (intr_type << VMCB_EVENTINJ_INTR_TYPE_SHIFT) | - (ec_valid ? VMCB_EVENTINJ_EC_VALID : 0) | - VMCB_EVENTINJ_VALID; - - ctrl->eventinj |= (uint64_t)error << VMCB_EVENTINJ_ERRCODE_SHIFT; - - return (0); + ctrl->eventinj = vector | (intr_type << 8) | VMCB_EVENTINJ_VALID; + if (ec_valid) { + ctrl->eventinj |= VMCB_EVENTINJ_EC_VALID; + ctrl->eventinj |= (uint64_t)error << 32; + } } Index: sys/amd64/vmm/amd/vmcb.h =================================================================== --- sys/amd64/vmm/amd/vmcb.h (revision 270437) +++ sys/amd64/vmm/amd/vmcb.h (working copy) @@ -109,10 +109,6 @@ #define VMCB_EVENTINJ_EC_VALID BIT(11) /* Error Code valid */ #define VMCB_EVENTINJ_VALID BIT(31) /* Event valid */ -#define VMCB_EVENTINJ_VECTOR_MASK 0xFF -#define VMCB_EVENTINJ_INTR_TYPE_SHIFT 8 -#define VMCB_EVENTINJ_ERRCODE_SHIFT 32 - /* Event types that can be injected */ #define VMCB_EVENTINJ_TYPE_INTR 0 #define VMCB_EVENTINJ_TYPE_NMI 2 @@ -152,11 +148,11 @@ * EXITINTINFO, Interrupt exit info for all intrecepts. * Section 15.7.2, Intercepts during IDT Interrupt Delivery. */ -#define VMCB_EXITINTINFO_VECTOR(x) (x & 0xFF) -#define VMCB_EXITINTINFO_TYPE(x) ((x & 0x7) >> 8) -#define VMCB_EXITINTINFO_EC_VALID BIT(11) -#define VMCB_EXITINTINFO_VALID BIT(31) -#define VMCB_EXITINTINFO_EC(x) ((x & 0xFFFFFFFF) >> 32) +#define VMCB_EXITINTINFO_VECTOR(x) ((x) & 0xFF) +#define VMCB_EXITINTINFO_TYPE(x) (((x) >> 8) & 0x7) +#define VMCB_EXITINTINFO_EC_VALID(x) (((x) & BIT(11)) ? 1 : 0) +#define VMCB_EXITINTINFO_VALID(x) (((x) & BIT(31)) ? 1 : 0) +#define VMCB_EXITINTINFO_EC(x) (((x) >> 32) & 0xFFFFFFFF) /* VMCB save state area segment format */ struct vmcb_segment { @@ -283,7 +279,7 @@ int vmcb_read(struct vmcb *vmcb, int ident, uint64_t *retval); int vmcb_write(struct vmcb *vmcb, int ident, uint64_t val); struct vmcb_segment *vmcb_seg(struct vmcb *vmcb, int type); -int vmcb_eventinject(struct vmcb_ctrl *ctrl, int type, int vector, +void vmcb_eventinject(struct vmcb_ctrl *ctrl, int type, int vector, uint32_t error, bool ec_valid); #endif /* _VMCB_H_ */