Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/arch/amd64/amd64 If we get a fault setting the user %gs, ...
details: https://anonhg.NetBSD.org/src/rev/856b9ff4dfaa
branches: trunk
changeset: 779357:856b9ff4dfaa
user: dsl <dsl%NetBSD.org@localhost>
date: Tue May 22 21:10:26 2012 +0000
description:
If we get a fault setting the user %gs, or on a iret that is returning
to userspace, we must do a 'swapgs' to reload the kernel %gs_base.
Also save the %ds, %es, %fs, %gs selector values in the frame so
they can be restored if we finally return to user (probably after
an application SIGSEGV handler has fixed the error).
Without this any such fault leaves the kernel running with the wrong
%gs offset and it will most likely fault again early in trap().
Repeats until the stack tramples on something important.
iret change works, invalid %gs is a little harder to arrange.
diffstat:
sys/arch/amd64/amd64/vector.S | 86 ++++++++++++++++++++++++++++++-------------
1 files changed, 60 insertions(+), 26 deletions(-)
diffs (109 lines):
diff -r f34048036f18 -r 856b9ff4dfaa sys/arch/amd64/amd64/vector.S
--- a/sys/arch/amd64/amd64/vector.S Tue May 22 19:11:21 2012 +0000
+++ b/sys/arch/amd64/amd64/vector.S Tue May 22 21:10:26 2012 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: vector.S,v 1.40 2012/05/07 21:09:29 dsl Exp $ */
+/* $NetBSD: vector.S,v 1.41 2012/05/22 21:10:26 dsl Exp $ */
/*-
* Copyright (c) 1998, 2007, 2008 The NetBSD Foundation, Inc.
@@ -224,14 +224,53 @@
IDTVEC(trap0a)
TRAP(T_TSSFLT)
-IDTVEC(trap0b)
- TRAP(T_SEGNPFLT)
+#ifdef XEN
+/*
+ * I don't believe XEN generates in-kernel traps for the
+ * equivalent of iret, if it does this code would be needed
+ * in order to copy the user segment registers into the fault frame.
+ */
+#define check_swapgs alltraps
+#endif
+
+IDTVEC(trap0b) /* #NP() Segment not present */
+ TRAP_NJ(T_SEGNPFLT)
+ jmp check_swapgs
+
+IDTVEC(trap0c) /* #SS() Stack exception */
+ TRAP_NJ(T_STKFLT)
+ jmp check_swapgs
-IDTVEC(trap0c)
- TRAP(T_STKFLT)
-
-IDTVEC(trap0d)
- TRAP(T_PROTFLT)
+IDTVEC(trap0d) /* #GP() General protection */
+ TRAP_NJ(T_PROTFLT)
+#ifdef check_swapgs
+ jmp check_swapgs
+#else
+/* We need to worry about traps while the kernel %gs_base isn't loaded.
+ * These are either loads to %gs (only 32bit) or faults on iret during
+ * return to user. */
+check_swapgs:
+ INTRENTRY_L(3f,1:)
+2: sti
+ jmp calltrap
+3:
+ /* Trap in kernel mode. */
+ /* If faulting instruction is 'iret' we may need to do a 'swapgs'. */
+ movq TF_RIP(%rsp),%rax
+ cmpw $0xcf48,(%rax) /* Faulting instruction is iretq ? */
+ jne 5f /* Jump if not */
+ movq TF_RSP(%rsp),%rax /* Must read %rsp, may be a pad word */
+ testb $SEL_UPL,8(%rax) /* Check %cs of outer iret frame */
+ je 2b /* jump if iret was to kernel */
+ jmp 1b /* to user - must restore %gs */
+5:
+ /* Not 'iret', all moves to %gs also need a swapgs */
+ movw (%rax),%ax
+ andb $070,%ah /* mask mod/rm from mod/reg/rm */
+ cmpw $0x8e+050*256,%ax /* Any move to %gs (reg 5) */
+ jne 2b /* No - normal kernel fault */
+ jmp 1b /* Yes - restore %gs */
+#endif
IDTVEC(trap0e)
TRAP(T_PAGEFLT)
@@ -305,25 +344,20 @@
.quad _C_LABEL(Xtrap1e), _C_LABEL(Xtrap1f)
/*
- * 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.
- *
- * XXXfvdl currently unused, as pop %ds and pop %es are illegal in long
- * mode. However, if the x86-64 port is going to support USER_LDT, we
- * may need something like this after all.
+ * trap() calls here when it detects a fault in INTRFASTEXIT (loading the
+ * segment registers or during the iret itself).
+ * The address of the (possibly reconstructed) user trap frame is
+ * passed as an argument.
+ * Typically the code will have raised a SIGSEGV which will be actioned
+ * by the code below.
*/
-NENTRY(resume_iret)
- ZTRAP(T_PROTFLT)
-#if 0
-NENTRY(resume_pop_ds)
- movl $GSEL(GDATA_SEL, SEL_KPL),%eax
- movl %eax,%es
-NENTRY(resume_pop_es)
- movl $T_PROTFLT,TF_TRAPNO(%rsp)
- jmp calltrap
-#endif
+_C_LABEL(trap_return_fault_return): .globl trap_return_fault_return
+ mov %rdi,%rsp /* frame for user return */
+#ifdef DIAGNOSTIC
+ /* We can't recover the saved %rbx, so suppress warning */
+ movl CPUVAR(ILEVEL),%ebx
+#endif /* DIAGNOSTIC */
+ jmp .Lalltraps_checkusr
/*
* All traps go through here. Call the generic trap handler, and
Home |
Main Index |
Thread Index |
Old Index