An exception is allowed to be injected even if the vcpu is in an interrupt

shadow, so move the check for pending exception before bailing out due to
an interrupt shadow.

Change return type of 'vmcb_eventinject()' to a void and convert all error
returns into KASSERTs.

Fix VMCB_EXITINTINFO_EC(x) and VMCB_EXITINTINFO_TYPE(x) to do the shift
before masking the result.

Reviewed by:    Anish Gupta (akgupt3@gmail.com)
This commit is contained in:
Neel Natu 2014-08-25 00:58:20 +00:00
parent 4e98fc9011
commit 48e8c2137a
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/projects/bhyve_svm/; revision=270511
3 changed files with 49 additions and 59 deletions

View File

@ -702,6 +702,9 @@ svm_vmexit(struct svm_softc *svm_sc, int vcpu, struct vm_exit *vmexit)
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 @@ svm_inject_nmi(struct svm_softc *svm_sc, int vcpu)
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 @@ svm_inj_interrupts(struct svm_softc *svm_sc, int vcpu, struct vlapic *vlapic)
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 @@ svm_inj_interrupts(struct svm_softc *svm_sc, int vcpu, struct vlapic *vlapic)
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 @@ svm_inj_interrupts(struct svm_softc *svm_sc, int vcpu, struct vlapic *vlapic)
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 @@ svm_handle_exitintinfo(struct svm_softc *svm_sc, int vcpu)
*/
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_vmrun(void *arg, int vcpu, register_t rip, pmap_t pmap,
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();

View File

@ -371,27 +371,32 @@ vmcb_seg(struct vmcb *vmcb, int type)
/*
* 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));
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);
}
if (intr_type == VMCB_EVENTINJ_TYPE_EXCEPTION && vector == IDT_NMI) {
ERR("NMI with Exception type is not possible.\n");
return (EINVAL);
ctrl->eventinj = vector | (intr_type << 8) | VMCB_EVENTINJ_VALID;
if (ec_valid) {
ctrl->eventinj |= VMCB_EVENTINJ_EC_VALID;
ctrl->eventinj |= (uint64_t)error << 32;
}
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);
}

View File

@ -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 svm_set_vmcb(struct vmcb *vmcb, uint8_t asid);
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_ */