Author: neel
Date: Sun Oct 26 03:03:41 2014
New Revision: 273666
URL: https://svnweb.freebsd.org/changeset/base/273666

Log:
  Don't pass the 'error' return from an I/O port handler directly to vm_run().
  
  Most I/O port handlers return -1 to signal an error. If this value is returned
  without modification to vm_run() then it leads to incorrect behavior because
  '-1' is interpreted as ERESTART at the system call level.
  
  Fix this by always returning EIO to signal an error from an I/O port handler.
  
  MFC after:    1 week

Modified:
  head/sys/amd64/vmm/vmm_ioport.c

Modified: head/sys/amd64/vmm/vmm_ioport.c
==============================================================================
--- head/sys/amd64/vmm/vmm_ioport.c     Sun Oct 26 02:53:23 2014        
(r273665)
+++ head/sys/amd64/vmm/vmm_ioport.c     Sun Oct 26 03:03:41 2014        
(r273666)
@@ -106,15 +106,14 @@ emulate_inout_port(struct vm *vm, int vc
        uint32_t mask, val;
        int error;
 
-       error = 0;
-       *retu = true;
-
-       if (vmexit->u.inout.port >= MAX_IOPORTS)
-               goto done;
-
-       handler = ioport_handler[vmexit->u.inout.port];
-       if (handler == NULL)
-               goto done;
+       /*
+        * If there is no handler for the I/O port then punt to userspace.
+        */
+       if (vmexit->u.inout.port >= MAX_IOPORTS ||
+           (handler = ioport_handler[vmexit->u.inout.port]) == NULL) {
+               *retu = true;
+               return (0);
+       }
 
        mask = vie_size2mask(vmexit->u.inout.bytes);
 
@@ -124,20 +123,27 @@ emulate_inout_port(struct vm *vm, int vc
 
        error = (*handler)(vm, vcpuid, vmexit->u.inout.in,
            vmexit->u.inout.port, vmexit->u.inout.bytes, &val);
+       if (error) {
+               /*
+                * The value returned by this function is also the return value
+                * of vm_run(). This needs to be a positive number otherwise it
+                * can be interpreted as a "pseudo-error" like ERESTART.
+                *
+                * Enforce this by mapping all errors to EIO.
+                */
+               return (EIO);
+       }
 
-       if (!error) {
-               *retu = false;
-               if (vmexit->u.inout.in) {
-                       vmexit->u.inout.eax &= ~mask;
-                       vmexit->u.inout.eax |= val & mask;
-                       error = vm_set_register(vm, vcpuid,
-                           VM_REG_GUEST_RAX, vmexit->u.inout.eax);
-                       KASSERT(error == 0, ("emulate_ioport: error %d "
-                           "setting guest rax register", error));
-               }
+       if (vmexit->u.inout.in) {
+               vmexit->u.inout.eax &= ~mask;
+               vmexit->u.inout.eax |= val & mask;
+               error = vm_set_register(vm, vcpuid, VM_REG_GUEST_RAX,
+                   vmexit->u.inout.eax);
+               KASSERT(error == 0, ("emulate_ioport: error %d setting guest "
+                   "rax register", error));
        }
-done:
-       return (error);
+       *retu = false;
+       return (0);
 }
 
 static int
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to