Module Name: src
Committed By: msaitoh
Date: Fri Mar 27 17:25:15 UTC 2009
Modified Files:
src/sys/arch/i386/i386 [netbsd-5]: trap.c vector.S
Log Message:
Pull up following revision(s) (requested by mrg in ticket #609):
sys/arch/i386/i386/vector.S: revision 1.44
sys/arch/i386/i386/trap.c: revision 1.244
remove a bunch of special casing to handle improperly set segment
registers. if we faulted trying to set them, just fall into
"we_re_toast", and arrange for a SEGV to be delivered to the
userland process. fixes kernel mode faults.
from andrew doran.
To generate a diff of this commit:
cvs rdiff -u -r1.241 -r1.241.4.1 src/sys/arch/i386/i386/trap.c
cvs rdiff -u -r1.42 -r1.42.6.1 src/sys/arch/i386/i386/vector.S
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/arch/i386/i386/trap.c
diff -u src/sys/arch/i386/i386/trap.c:1.241 src/sys/arch/i386/i386/trap.c:1.241.4.1
--- src/sys/arch/i386/i386/trap.c:1.241 Wed Oct 15 06:51:17 2008
+++ src/sys/arch/i386/i386/trap.c Fri Mar 27 17:25:15 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: trap.c,v 1.241 2008/10/15 06:51:17 wrstuden Exp $ */
+/* $NetBSD: trap.c,v 1.241.4.1 2009/03/27 17:25:15 msaitoh Exp $ */
/*-
* Copyright (c) 1998, 2000, 2005, 2006, 2007, 2008 The NetBSD Foundation, Inc.
@@ -68,7 +68,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.241 2008/10/15 06:51:17 wrstuden Exp $");
+__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.241.4.1 2009/03/27 17:25:15 msaitoh Exp $");
#include "opt_ddb.h"
#include "opt_kgdb.h"
@@ -276,13 +276,9 @@
struct proc *p;
int type = frame->tf_trapno;
struct pcb *pcb;
- extern char fusubail[], kcopy_fault[],
- resume_iret[], resume_pop_ds[], resume_pop_es[],
- resume_pop_fs[], resume_pop_gs[],
- IDTVEC(osyscall)[];
+ extern char fusubail[], kcopy_fault[], trapreturn[], IDTVEC(osyscall)[];
struct trapframe *vframe;
ksiginfo_t ksi;
- int resume;
void *onfault;
int error;
uint32_t cr2;
@@ -397,52 +393,25 @@
/*
* Check for failure during return to user mode.
*
- * We do this by looking at the instruction we faulted on. The
- * specific instructions we recognize only happen when
+ * We do this by looking at the instruction we faulted on.
+ * The specific instructions we recognize only happen when
* returning from a trap, syscall, or interrupt.
*
* At this point, there are (at least) two trap frames on
* the kernel stack; we presume here that we faulted while
* loading our registers out of the outer one.
- *
- * The inner frame does not involve a ring crossing, so it
- * ends right before &frame.tf_esp. The outer frame has
- * been partially consumed by the INTRFASTEXIT; exactly
- * how much depends which register we were popping when we
- * faulted, so we compute the outer frame address based on
- * register-dependant offsets computed from &frame.tf_esp
- * below. To decide whether this was a kernel-mode or
- * user-mode error, we look at this outer frame's tf_cs
- * and tf_eflags, which are (fortunately) not consumed until
- * the final instruction of INTRFASTEXIT.
- *
- * XXX
- * The heuristic used here will currently fail for the case of
- * one of the 2 pop instructions faulting when returning from a
- * a fast interrupt. This should not be possible. It can be
- * fixed by rearranging the trap frame so that the stack format
- * at this point is the same as on exit from a `slow'
- * interrupt.
*/
switch (*(u_char *)frame->tf_eip) {
case 0xcf: /* iret */
vframe = (void *)((int)&frame->tf_esp -
offsetof(struct trapframe, tf_eip));
- resume = (int)resume_iret;
break;
case 0x8e:
switch (*(uint32_t *)frame->tf_eip) {
case 0x0c245c8e: /* movl 0xc(%esp,1),%ds */
- resume = (int)resume_pop_ds;
- break;
case 0x0824448e: /* movl 0x8(%esp,1),%es */
- resume = (int)resume_pop_es;
- break;
case 0x0424648e: /* movl 0x4(%esp,1),%fs */
- resume = (int)resume_pop_fs;
- break;
case 0x00246c8e: /* movl 0x0(%esp,1),%gs */
- resume = (int)resume_pop_gs;
break;
default:
goto we_re_toast;
@@ -455,18 +424,34 @@
if (KERNELMODE(vframe->tf_cs, vframe->tf_eflags))
goto we_re_toast;
- frame->tf_eip = resume;
-
/*
- * clear PSL_NT. it can be set by userland because setting it
- * isn't a privileged operation.
+ * Arrange to signal the thread, which will reset its
+ * registers in the outer frame. This also allows us to
+ * capture the invalid register state in sigcontext,
+ * packaged up with the signal delivery. We restart
+ * on return at 'trapreturn', acting as if nothing
+ * happened, restarting the return to user with our new
+ * set of registers.
+ *
+ * Clear PSL_NT. It can be set by userland because setting
+ * it isn't a privileged operation.
*
- * set PSL_I. otherwise, if SIGSEGV is ignored, we'll
+ * Set PSL_I. Otherwise, if SIGSEGV is ignored, we'll
* continue to generate traps infinitely with
* interrupts disabled.
*/
-
+ frame->tf_ds = GSEL(GDATA_SEL, SEL_KPL);
+ frame->tf_es = GSEL(GDATA_SEL, SEL_KPL);
+ frame->tf_gs = GSEL(GDATA_SEL, SEL_KPL);
+ frame->tf_fs = GSEL(GCPU_SEL, SEL_KPL);
+ frame->tf_eip = (uintptr_t)trapreturn;
frame->tf_eflags = (frame->tf_eflags & ~PSL_NT) | PSL_I;
+ KSI_INIT_TRAP(&ksi);
+ ksi.ksi_signo = SIGSEGV;
+ ksi.ksi_addr = (void *)rcr2();
+ ksi.ksi_code = SEGV_ACCERR;
+ ksi.ksi_trap = type & ~T_USER;
+ (*p->p_emul->e_trapsignal)(l, &ksi);
return;
case T_PROTFLT|T_USER: /* protection fault */
Index: src/sys/arch/i386/i386/vector.S
diff -u src/sys/arch/i386/i386/vector.S:1.42 src/sys/arch/i386/i386/vector.S:1.42.6.1
--- src/sys/arch/i386/i386/vector.S:1.42 Mon Jul 7 13:01:16 2008
+++ src/sys/arch/i386/i386/vector.S Fri Mar 27 17:25:15 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: vector.S,v 1.42 2008/07/07 13:01:16 gmcgarry Exp $ */
+/* $NetBSD: vector.S,v 1.42.6.1 2009/03/27 17:25:15 msaitoh Exp $ */
/*
* Copyright 2002 (c) Wasabi Systems, Inc.
@@ -65,7 +65,7 @@
*/
#include <machine/asm.h>
-__KERNEL_RCSID(0, "$NetBSD: vector.S,v 1.42 2008/07/07 13:01:16 gmcgarry Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vector.S,v 1.42.6.1 2009/03/27 17:25:15 msaitoh Exp $");
#include "opt_ddb.h"
#include "opt_multiprocessor.h"
@@ -863,7 +863,7 @@
addl $4,%esp
testl %eax,%eax
jz calltrap
- jmp .Lalltraps_checkusr
+ jmp _C_LABEL(trapreturn)
#else
#ifndef XEN
sti
@@ -999,7 +999,7 @@
#ifdef DIAGNOSTIC
movl CPUVAR(ILEVEL),%ebx
#endif
- jmp .Lalltraps_checkusr
+ jmp _C_LABEL(trapreturn)
IDTVEC(trap10)
#if NNPX > 0
@@ -1018,7 +1018,7 @@
incl _C_LABEL(uvmexp)+V_TRAP
call _C_LABEL(npxintr)
addl $12,%esp
- jmp .Lalltraps_checkusr
+ jmp _C_LABEL(trapreturn)
#else
sti
ZTRAP(T_ARITHTRAP)
@@ -1092,7 +1092,7 @@
pushl %esp
call _C_LABEL(trap)
addl $4,%esp
-.Lalltraps_checkusr:
+_C_LABEL(trapreturn): .globl trapreturn
testb $CHK_UPL,TF_CS(%esp)
jnz .Lalltraps_checkast
#ifdef VM86
@@ -1136,7 +1136,7 @@
movl CPUVAR(ISOURCES)(,%eax,4),%eax
jmp *IS_RESUME(%eax)
7: movl %ebx, CPUVAR(ILEVEL) #restore cpl
- jmp .Lalltraps_checkusr
+ jmp _C_LABEL(trapreturn)
#endif /* XEN */
#ifndef DIAGNOSTIC
6: INTRFASTEXIT
@@ -1210,36 +1210,6 @@
ret
#endif /* IPKDB */
-
-/*
- * If an error is detected during trap, syscall, or interrupt exit, trap() will
- * change %eip to point to one of these labels. We clean up the stack, if
- * necessary, and resume as if we were handling a general protection fault.
- * This will cause the process to get a SIGBUS.
- */
-/* LINTSTUB: Var: char resume_iret[1]; */
-NENTRY(resume_iret)
- ZTRAP(T_PROTFLT)
-/* LINTSTUB: Var: char resume_pop_ds[1]; */
-NENTRY(resume_pop_ds)
- movw %es,TF_ES(%esp)
- movl $GSEL(GDATA_SEL, SEL_KPL),%eax
- movw %ax,%es
-/* LINTSTUB: Var: char resume_pop_es[1]; */
-NENTRY(resume_pop_es)
- movw %fs,TF_FS(%esp)
- movl $GSEL(GDATA_SEL, SEL_KPL),%eax
- movw %ax,%fs
-/* LINTSTUB: Var: char resume_pop_fs[1]; */
-NENTRY(resume_pop_fs)
- movw %gs,TF_GS(%esp)
- movl $GSEL(GDATA_SEL, SEL_KPL),%eax
- movw %ax,%gs
-/* LINTSTUB: Var: char resume_pop_gs[1]; */
-NENTRY(resume_pop_gs)
- movl $T_PROTFLT,TF_TRAPNO(%esp)
- jmp calltrap
-
#ifdef IPKDB
/* LINTSTUB: Func: int ipkdbfbyte(u_char *c) */
NENTRY(ipkdbfbyte)