From bb47c0722753e42a01efa8ca923901cbad298cb4 Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Mon, 18 Jan 2010 12:05:17 -0800 Subject: [PATCH] kernel - Fix vkernel_trap * 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 --- sys/platform/pc32/i386/trap.c | 18 ++++++++++++++---- sys/platform/pc64/x86_64/trap.c | 29 +++++++++++++++-------------- sys/platform/vkernel/i386/trap.c | 20 +++++++++++++++----- sys/sys/systm.h | 1 + sys/sys/vkernel.h | 2 +- sys/vm/vm_vmspace.c | 4 ++-- 6 files changed, 48 insertions(+), 26 deletions(-) diff --git a/sys/platform/pc32/i386/trap.c b/sys/platform/pc32/i386/trap.c index c4ba438b6e..194c627a73 100644 --- a/sys/platform/pc32/i386/trap.c +++ b/sys/platform/pc32/i386/trap.c @@ -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; +} diff --git a/sys/platform/pc64/x86_64/trap.c b/sys/platform/pc64/x86_64/trap.c index 3a8c1dbf98..0e02a10023 100644 --- a/sys/platform/pc64/x86_64/trap.c +++ b/sys/platform/pc64/x86_64/trap.c @@ -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; +} diff --git a/sys/platform/vkernel/i386/trap.c b/sys/platform/vkernel/i386/trap.c index cb548217c6..377e5a84a8 100644 --- a/sys/platform/vkernel/i386/trap.c +++ b/sys/platform/vkernel/i386/trap.c @@ -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; +} diff --git a/sys/sys/systm.h b/sys/sys/systm.h index a9fddd49fa..4d3841c1df 100644 --- a/sys/sys/systm.h +++ b/sys/sys/systm.h @@ -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); diff --git a/sys/sys/vkernel.h b/sys/sys/vkernel.h index 6fa1aee451..9443c0db91 100644 --- a/sys/sys/vkernel.h +++ b/sys/sys/vkernel.h @@ -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 diff --git a/sys/vm/vm_vmspace.c b/sys/vm/vm_vmspace.c index 49c90d9249..b76d00de7f 100644 --- a/sys/vm/vm_vmspace.c +++ b/sys/vm/vm_vmspace.c @@ -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); } -- 2.41.0