Author: neel
Date: Tue Jan 13 22:00:47 2015
New Revision: 277149
URL: https://svnweb.freebsd.org/changeset/base/277149

Log:
  'struct vm_exception' was intended to be used only as the collateral for the
  VM_INJECT_EXCEPTION ioctl. However it morphed into other uses like keeping
  track pending exceptions for a vcpu. This in turn causes confusion because
  some fields in 'struct vm_exception' like 'vcpuid' make sense only in the
  ioctl context. It also makes it harder to add or remove structure fields.
  
  Fix this by using 'struct vm_exception' only to communicate information
  from userspace to vmm.ko when injecting an exception.
  
  Also, add a field 'restart_instruction' to 'struct vm_exception'. This
  field is set to '1' for exceptions where the faulting instruction is
  restarted after the exception is handled.
  
  MFC after:      1 week

Modified:
  head/sys/amd64/include/vmm.h
  head/sys/amd64/include/vmm_dev.h
  head/sys/amd64/vmm/amd/svm.c
  head/sys/amd64/vmm/intel/vmx.c
  head/sys/amd64/vmm/vmm.c
  head/sys/amd64/vmm/vmm_dev.c

Modified: head/sys/amd64/include/vmm.h
==============================================================================
--- head/sys/amd64/include/vmm.h        Tue Jan 13 21:29:24 2015        
(r277148)
+++ head/sys/amd64/include/vmm.h        Tue Jan 13 22:00:47 2015        
(r277149)
@@ -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 e
 
 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_ */

Modified: head/sys/amd64/include/vmm_dev.h
==============================================================================
--- head/sys/amd64/include/vmm_dev.h    Tue Jan 13 21:29:24 2015        
(r277148)
+++ head/sys/amd64/include/vmm_dev.h    Tue Jan 13 22:00:47 2015        
(r277149)
@@ -63,6 +63,7 @@ struct vm_exception {
        int             vector;
        uint32_t        error_code;
        int             error_code_valid;
+       int             restart_instruction;
 };
 
 struct vm_lapic_msi {

Modified: head/sys/amd64/vmm/amd/svm.c
==============================================================================
--- head/sys/amd64/vmm/amd/svm.c        Tue Jan 13 21:29:24 2015        
(r277148)
+++ head/sys/amd64/vmm/amd/svm.c        Tue Jan 13 22:00:47 2015        
(r277149)
@@ -1201,7 +1201,6 @@ svm_vmexit(struct svm_softc *svm_sc, int
        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
                        /* 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
 
                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));
                }

Modified: head/sys/amd64/vmm/intel/vmx.c
==============================================================================
--- head/sys/amd64/vmm/intel/vmx.c      Tue Jan 13 21:29:24 2015        
(r277148)
+++ head/sys/amd64/vmm/intel/vmx.c      Tue Jan 13 22:00:47 2015        
(r277149)
@@ -1784,7 +1784,7 @@ vmexit_inst_emul(struct vm_exit *vmexit,
 {
        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 vcpui
 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 vc
        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 vc
                        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);

Modified: head/sys/amd64/vmm/vmm.c
==============================================================================
--- head/sys/amd64/vmm/vmm.c    Tue Jan 13 21:29:24 2015        (r277148)
+++ head/sys/amd64/vmm/vmm.c    Tue Jan 13 22:00:47 2015        (r277149)
@@ -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 vcpu
                return (EFAULT);
 done:
        /* restart execution at the faulting instruction */
-       vme->inst_length = 0;
+       vm_restart_instruction(vm, vcpuid);
 
        return (0);
 }
@@ -1526,6 +1528,20 @@ restart:
 }
 
 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)
 {
        struct vcpu *vcpu;
@@ -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 vcpu
                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
 }
 
 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 v
        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 v
         * 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 v
        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

Modified: head/sys/amd64/vmm/vmm_dev.c
==============================================================================
--- head/sys/amd64/vmm/vmm_dev.c        Tue Jan 13 21:29:24 2015        
(r277148)
+++ head/sys/amd64/vmm/vmm_dev.c        Tue Jan 13 22:00:47 2015        
(r277149)
@@ -310,7 +310,9 @@ vmmdev_ioctl(struct cdev *cdev, u_long c
                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;
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to