kernel - Fix vkernel_trap
authorMatthew Dillon <dillon@apollo.backplane.com>
Mon, 18 Jan 2010 20:05:17 +0000 (12:05 -0800)
committerMatthew Dillon <dillon@apollo.backplane.com>
Mon, 18 Jan 2010 20:05:17 +0000 (12:05 -0800)
* vkernel_trap restores the trapframe for the original vkernel call to
  vmspace_ctl(), but only the syscall trap code was actually setting
  up the frame for a syscall-return.

  The other calls to vkernel_trap() (signal, page-fault, other traps)
  were not properly adjusting the frame for a syscall-return and it
  is only pure luck that it didn't bite us until now.

* Add a per-platform cpu_vkernel_trap() which does the syscall-return
  fixup at the end.

Reported-by: Antonio Huete Jimenez <tuxillo@quantumachine.net>
sys/platform/pc32/i386/trap.c
sys/platform/pc64/x86_64/trap.c
sys/platform/vkernel/i386/trap.c
sys/sys/systm.h
sys/sys/vkernel.h
sys/vm/vm_vmspace.c

index c4ba438..194c627 100644 (file)
@@ -1271,10 +1271,7 @@ syscall2(struct trapframe *frame)
         * call.  The current frame is copied out to the virtual kernel.
         */
        if (lp->lwp_vkernel && lp->lwp_vkernel->ve) {
-               error = vkernel_trap(lp, frame);
-               frame->tf_eax = error;
-               if (error)
-                       frame->tf_eflags |= PSL_C;
+               vkernel_trap(lp, frame);
                error = EJUSTRETURN;
                callp = NULL;
                goto out;
@@ -1523,3 +1520,16 @@ set_vkernel_fp(struct trapframe *frame)
        }
 }
 
+/*
+ * Called from vkernel_trap() to fixup the vkernel's syscall
+ * frame for vmspace_ctl() return.
+ */
+void
+cpu_vkernel_trap(struct trapframe *frame, int error)
+{
+       frame->tf_eax = error;
+       if (error)
+               frame->tf_eflags |= PSL_C;
+       else
+               frame->tf_eflags &= ~PSL_C;
+}
index 3a8c1db..0e02a10 100644 (file)
@@ -750,16 +750,6 @@ trap(struct trapframe *frame)
                goto out2;
        }
 
-       /*
-        * Virtual kernel intercept - if the fault is directly related to a
-        * VM context managed by a virtual kernel then let the virtual kernel
-        * handle it.
-        */
-       if (lp->lwp_vkernel && lp->lwp_vkernel->ve) {
-               vkernel_trap(lp, frame);
-               goto out2;
-       }
-
        /*
         * Virtual kernel intercept - if the fault is directly related to a
         * VM context managed by a virtual kernel then let the virtual kernel
@@ -1101,10 +1091,7 @@ syscall2(struct trapframe *frame)
         * call.  The current frame is copied out to the virtual kernel.
         */
        if (lp->lwp_vkernel && lp->lwp_vkernel->ve) {
-               error = vkernel_trap(lp, frame);
-               frame->tf_rax = error;
-               if (error)
-                       frame->tf_rflags |= PSL_C;
+               vkernel_trap(lp, frame);
                error = EJUSTRETURN;
                goto out;
        }
@@ -1350,3 +1337,17 @@ set_vkernel_fp(struct trapframe *frame)
 {
        /* JGXXX */
 }
+
+/*
+ * Called from vkernel_trap() to fixup the vkernel's syscall
+ * frame for vmspace_ctl() return.
+ */
+void
+cpu_vkernel_trap(struct trapframe *frame, int error)
+{
+       frame->tf_rax = error;
+       if (error)
+               frame->tf_rflags |= PSL_C;
+       else
+               frame->tf_rflags &= ~PSL_C;
+}
index cb54821..377e5a8 100644 (file)
@@ -1188,10 +1188,7 @@ syscall2(struct trapframe *frame)
         * call.  The current frame is copied out to the virtual kernel.
         */
        if (lp->lwp_vkernel && lp->lwp_vkernel->ve) {
-               error = vkernel_trap(lp, frame);
-               frame->tf_eax = error;
-               if (error)
-                       frame->tf_eflags |= PSL_C;
+               vkernel_trap(lp, frame);
                error = EJUSTRETURN;
                goto out;
        }
@@ -1485,7 +1482,7 @@ go_user(struct intrframe *frame)
 #endif
                if (r < 0) {
                        if (errno != EINTR)
-                               panic("vmspace_ctl failed");
+                               panic("vmspace_ctl failed error %d", errno);
                } else {
                        if (tf->tf_trapno) {
                                user_trap(tf);
@@ -1520,3 +1517,16 @@ set_vkernel_fp(struct trapframe *frame)
        }
 }
 
+/*
+ * Called from vkernel_trap() to fixup the vkernel's syscall
+ * frame for vmspace_ctl() return.
+ */
+void
+cpu_vkernel_trap(struct trapframe *frame, int error)
+{
+       frame->tf_eax = error;
+       if (error)
+               frame->tf_eflags |= PSL_C;
+       else
+               frame->tf_eflags &= ~PSL_C;
+}
index a9fddd4..4d3841c 100644 (file)
@@ -165,6 +165,7 @@ void        cpu_boot (int);
 void   cpu_rootconf (void);
 void   cpu_vmspace_alloc(struct vmspace *);
 void   cpu_vmspace_free(struct vmspace *);
+void   cpu_vkernel_trap(struct trapframe *, int);
 void   set_user_TLS(void);
 void   set_vkernel_fp(struct trapframe *);
 int    kvm_access_check(vm_offset_t, vm_offset_t, int);
index 6fa1aee..9443c0d 100644 (file)
@@ -97,7 +97,7 @@ struct vmspace_entry {
 void vkernel_inherit(struct proc *p1, struct proc *p2);
 void vkernel_exit(struct proc *p);
 void vkernel_lwp_exit(struct lwp *lp);
-int vkernel_trap(struct lwp *lp, struct trapframe *frame);
+void vkernel_trap(struct lwp *lp, struct trapframe *frame);
 
 #endif
 
index 49c90d9..b76d00d 100644 (file)
@@ -610,7 +610,7 @@ vkernel_lwp_exit(struct lwp *lp)
  * A VM space under virtual kernel control trapped out or made a system call
  * or otherwise needs to return control to the virtual kernel context.
  */
-int
+void
 vkernel_trap(struct lwp *lp, struct trapframe *frame)
 {
        struct proc *p = lp->lwp_proc;
@@ -647,6 +647,6 @@ vkernel_trap(struct lwp *lp, struct trapframe *frame)
        bcopy(&vklp->save_vextframe.vx_tls, &curthread->td_tls,
              sizeof(vklp->save_vextframe.vx_tls));
        set_user_TLS();
-       return(error);
+       cpu_vkernel_trap(frame, error);
 }