diff --git a/sys/amd64/include/vmm.h b/sys/amd64/include/vmm.h index eef5efa11feb..253654d43758 100644 --- a/sys/amd64/include/vmm.h +++ b/sys/amd64/include/vmm.h @@ -289,7 +289,7 @@ struct vpmtmr *vm_pmtmr(struct vm *vm); struct vrtc *vm_rtc(struct vm *vm); /* - * Inject exception 'vme' into the guest vcpu. This function returns 0 on + * Inject exception 'vector' into the guest vcpu. This function returns 0 on * success and non-zero on failure. * * Wrapper functions like 'vm_inject_gp()' should be preferred to calling @@ -299,7 +299,8 @@ struct vrtc *vm_rtc(struct vm *vm); * This function should only be called in the context of the thread that is * executing this vcpu. */ -int vm_inject_exception(struct vm *vm, int vcpuid, struct vm_exception *vme); +int vm_inject_exception(struct vm *vm, int vcpuid, int vector, int err_valid, + uint32_t errcode, int restart_instruction); /* * This function is called after a VM-exit that occurred during exception or @@ -628,4 +629,6 @@ vm_inject_ss(void *vm, int vcpuid, int errcode) void vm_inject_pf(void *vm, int vcpuid, int error_code, uint64_t cr2); +int vm_restart_instruction(void *vm, int vcpuid); + #endif /* _VMM_H_ */ diff --git a/sys/amd64/include/vmm_dev.h b/sys/amd64/include/vmm_dev.h index 3097386db581..f3354e341428 100644 --- a/sys/amd64/include/vmm_dev.h +++ b/sys/amd64/include/vmm_dev.h @@ -63,6 +63,7 @@ struct vm_exception { int vector; uint32_t error_code; int error_code_valid; + int restart_instruction; }; struct vm_lapic_msi { diff --git a/sys/amd64/vmm/amd/svm.c b/sys/amd64/vmm/amd/svm.c index 3a96e56998e9..31164d7c58da 100644 --- a/sys/amd64/vmm/amd/svm.c +++ b/sys/amd64/vmm/amd/svm.c @@ -1201,7 +1201,6 @@ svm_vmexit(struct svm_softc *svm_sc, int vcpu, struct vm_exit *vmexit) struct vmcb_state *state; struct vmcb_ctrl *ctrl; struct svm_regctx *ctx; - struct vm_exception exception; uint64_t code, info1, info2, val; uint32_t eax, ecx, edx; int error, errcode_valid, handled, idtvec, reflect; @@ -1315,6 +1314,7 @@ svm_vmexit(struct svm_softc *svm_sc, int vcpu, struct vm_exit *vmexit) /* fallthru */ default: errcode_valid = 0; + info1 = 0; break; } KASSERT(vmexit->inst_length == 0, ("invalid inst_length (%d) " @@ -1323,17 +1323,10 @@ svm_vmexit(struct svm_softc *svm_sc, int vcpu, struct vm_exit *vmexit) if (reflect) { /* Reflect the exception back into the guest */ - bzero(&exception, sizeof(struct vm_exception)); - exception.vector = idtvec; - if (errcode_valid) { - exception.error_code = info1; - exception.error_code_valid = 1; - } VCPU_CTR2(svm_sc->vm, vcpu, "Reflecting exception " - "%d/%#x into the guest", exception.vector, - exception.error_code); - error = vm_inject_exception(svm_sc->vm, vcpu, - &exception); + "%d/%#x into the guest", idtvec, (int)info1); + error = vm_inject_exception(svm_sc->vm, vcpu, idtvec, + errcode_valid, info1, 0); KASSERT(error == 0, ("%s: vm_inject_exception error %d", __func__, error)); } diff --git a/sys/amd64/vmm/intel/vmx.c b/sys/amd64/vmm/intel/vmx.c index a3fc16af5b9b..a10a591d94d5 100644 --- a/sys/amd64/vmm/intel/vmx.c +++ b/sys/amd64/vmm/intel/vmx.c @@ -1784,7 +1784,7 @@ vmexit_inst_emul(struct vm_exit *vmexit, uint64_t gpa, uint64_t gla) { struct vm_guest_paging *paging; uint32_t csar; - + paging = &vmexit->u.inst_emul.paging; vmexit->exitcode = VM_EXITCODE_INST_EMUL; @@ -2073,12 +2073,11 @@ emulate_rdmsr(struct vmx *vmx, int vcpuid, u_int num, bool *retu) static int vmx_exit_process(struct vmx *vmx, int vcpu, struct vm_exit *vmexit) { - int error, handled, in; + int error, errcode, errcode_valid, handled, in; struct vmxctx *vmxctx; struct vlapic *vlapic; struct vm_inout_str *vis; struct vm_task_switch *ts; - struct vm_exception vmexc; uint32_t eax, ecx, edx, idtvec_info, idtvec_err, intr_info, inst_info; uint32_t intr_type, intr_vec, reason; uint64_t exitintinfo, qual, gpa; @@ -2263,6 +2262,7 @@ vmx_exit_process(struct vmx *vmx, int vcpu, struct vm_exit *vmexit) case EXIT_REASON_MTF: vmm_stat_incr(vmx->vm, vcpu, VMEXIT_MTRAP, 1); vmexit->exitcode = VM_EXITCODE_MTRAP; + vmexit->inst_length = 0; break; case EXIT_REASON_PAUSE: vmm_stat_incr(vmx->vm, vcpu, VMEXIT_PAUSE, 1); @@ -2389,15 +2389,15 @@ vmx_exit_process(struct vmx *vmx, int vcpu, struct vm_exit *vmexit) vmcs_write(VMCS_ENTRY_INST_LENGTH, vmexit->inst_length); /* Reflect all other exceptions back into the guest */ - bzero(&vmexc, sizeof(struct vm_exception)); - vmexc.vector = intr_vec; + errcode_valid = errcode = 0; if (intr_info & VMCS_INTR_DEL_ERRCODE) { - vmexc.error_code_valid = 1; - vmexc.error_code = vmcs_read(VMCS_EXIT_INTR_ERRCODE); + errcode_valid = 1; + errcode = vmcs_read(VMCS_EXIT_INTR_ERRCODE); } VCPU_CTR2(vmx->vm, vcpu, "Reflecting exception %d/%#x into " - "the guest", vmexc.vector, vmexc.error_code); - error = vm_inject_exception(vmx->vm, vcpu, &vmexc); + "the guest", intr_vec, errcode); + error = vm_inject_exception(vmx->vm, vcpu, intr_vec, + errcode_valid, errcode, 0); KASSERT(error == 0, ("%s: vm_inject_exception error %d", __func__, error)); return (1); diff --git a/sys/amd64/vmm/vmm.c b/sys/amd64/vmm/vmm.c index 6fd3d46d2a86..ff32b33e5b90 100644 --- a/sys/amd64/vmm/vmm.c +++ b/sys/amd64/vmm/vmm.c @@ -101,8 +101,10 @@ struct vcpu { uint64_t exitintinfo; /* (i) events pending at VM exit */ int nmi_pending; /* (i) NMI pending */ int extint_pending; /* (i) INTR pending */ - struct vm_exception exception; /* (x) exception collateral */ int exception_pending; /* (i) exception pending */ + int exc_vector; /* (x) exception collateral */ + int exc_errcode_valid; + uint32_t exc_errcode; struct savefpu *guestfpu; /* (a,i) guest fpu state */ uint64_t guest_xcr0; /* (i) guest %xcr0 register */ void *stats; /* (a,i) statistics */ @@ -1223,7 +1225,7 @@ vm_handle_paging(struct vm *vm, int vcpuid, bool *retu) return (EFAULT); done: /* restart execution at the faulting instruction */ - vme->inst_length = 0; + vm_restart_instruction(vm, vcpuid); return (0); } @@ -1525,6 +1527,20 @@ vm_run(struct vm *vm, struct vm_run *vmrun) return (error); } +int +vm_restart_instruction(void *arg, int vcpuid) +{ + struct vcpu *vcpu; + struct vm *vm = arg; + + if (vcpuid < 0 || vcpuid >= VM_MAXCPU) + return (EINVAL); + + vcpu = &vm->vcpu[vcpuid]; + vcpu->exitinfo.inst_length = 0; + return (0); +} + int vm_exit_intinfo(struct vm *vm, int vcpuid, uint64_t info) { @@ -1655,11 +1671,11 @@ vcpu_exception_intinfo(struct vcpu *vcpu) uint64_t info = 0; if (vcpu->exception_pending) { - info = vcpu->exception.vector & 0xff; + info = vcpu->exc_vector & 0xff; info |= VM_INTINFO_VALID | VM_INTINFO_HWEXCEPTION; - if (vcpu->exception.error_code_valid) { + if (vcpu->exc_errcode_valid) { info |= VM_INTINFO_DEL_ERRCODE; - info |= (uint64_t)vcpu->exception.error_code << 32; + info |= (uint64_t)vcpu->exc_errcode << 32; } } return (info); @@ -1684,7 +1700,7 @@ vm_entry_intinfo(struct vm *vm, int vcpuid, uint64_t *retinfo) info2 = vcpu_exception_intinfo(vcpu); vcpu->exception_pending = 0; VCPU_CTR2(vm, vcpuid, "Exception %d delivered: %#lx", - vcpu->exception.vector, info2); + vcpu->exc_vector, info2); } if ((info1 & VM_INTINFO_VALID) && (info2 & VM_INTINFO_VALID)) { @@ -1722,7 +1738,8 @@ vm_get_intinfo(struct vm *vm, int vcpuid, uint64_t *info1, uint64_t *info2) } int -vm_inject_exception(struct vm *vm, int vcpuid, struct vm_exception *exception) +vm_inject_exception(struct vm *vm, int vcpuid, int vector, int errcode_valid, + uint32_t errcode, int restart_instruction) { struct vcpu *vcpu; int error; @@ -1730,7 +1747,7 @@ vm_inject_exception(struct vm *vm, int vcpuid, struct vm_exception *exception) if (vcpuid < 0 || vcpuid >= VM_MAXCPU) return (EINVAL); - if (exception->vector < 0 || exception->vector >= 32) + if (vector < 0 || vector >= 32) return (EINVAL); /* @@ -1738,15 +1755,14 @@ vm_inject_exception(struct vm *vm, int vcpuid, struct vm_exception *exception) * the guest. It is a derived exception that results from specific * combinations of nested faults. */ - if (exception->vector == IDT_DF) + if (vector == IDT_DF) return (EINVAL); vcpu = &vm->vcpu[vcpuid]; if (vcpu->exception_pending) { VCPU_CTR2(vm, vcpuid, "Unable to inject exception %d due to " - "pending exception %d", exception->vector, - vcpu->exception.vector); + "pending exception %d", vector, vcpu->exc_vector); return (EBUSY); } @@ -1760,9 +1776,14 @@ vm_inject_exception(struct vm *vm, int vcpuid, struct vm_exception *exception) KASSERT(error == 0, ("%s: error %d clearing interrupt shadow", __func__, error)); + if (restart_instruction) + vm_restart_instruction(vm, vcpuid); + vcpu->exception_pending = 1; - vcpu->exception = *exception; - VCPU_CTR1(vm, vcpuid, "Exception %d pending", exception->vector); + vcpu->exc_vector = vector; + vcpu->exc_errcode = errcode; + vcpu->exc_errcode_valid = errcode_valid; + VCPU_CTR1(vm, vcpuid, "Exception %d pending", vector); return (0); } @@ -1770,28 +1791,15 @@ void vm_inject_fault(void *vmarg, int vcpuid, int vector, int errcode_valid, int errcode) { - struct vm_exception exception; - struct vm_exit *vmexit; struct vm *vm; - int error; + int error, restart_instruction; vm = vmarg; + restart_instruction = 1; - exception.vector = vector; - exception.error_code = errcode; - exception.error_code_valid = errcode_valid; - error = vm_inject_exception(vm, vcpuid, &exception); + error = vm_inject_exception(vm, vcpuid, vector, errcode_valid, + errcode, restart_instruction); KASSERT(error == 0, ("vm_inject_exception error %d", error)); - - /* - * A fault-like exception allows the instruction to be restarted - * after the exception handler returns. - * - * By setting the inst_length to 0 we ensure that the instruction - * pointer remains at the faulting instruction. - */ - vmexit = vm_exitinfo(vm, vcpuid); - vmexit->inst_length = 0; } void diff --git a/sys/amd64/vmm/vmm_dev.c b/sys/amd64/vmm/vmm_dev.c index a6491d65ea8b..9b39f145c71c 100644 --- a/sys/amd64/vmm/vmm_dev.c +++ b/sys/amd64/vmm/vmm_dev.c @@ -310,7 +310,9 @@ vmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag, break; case VM_INJECT_EXCEPTION: vmexc = (struct vm_exception *)data; - error = vm_inject_exception(sc->vm, vmexc->cpuid, vmexc); + error = vm_inject_exception(sc->vm, vmexc->cpuid, + vmexc->vector, vmexc->error_code_valid, vmexc->error_code, + vmexc->restart_instruction); break; case VM_INJECT_NMI: vmnmi = (struct vm_nmi *)data;