patch-2.4.0-test9 linux/arch/i386/kernel/traps.c

Next file: linux/arch/i386/kernel/vm86.c
Previous file: linux/arch/i386/kernel/time.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.0-test8/linux/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c
@@ -95,6 +95,7 @@
 asmlinkage void reserved(void);
 asmlinkage void alignment_check(void);
 asmlinkage void spurious_interrupt_bug(void);
+asmlinkage void machine_check(void);
 
 int kstack_depth_to_print = 24;
 
@@ -415,8 +416,8 @@
 	 *  here too!]
 	 */
 
-	static unsigned int last_irq_sums [NR_CPUS] = { 0, },
-				alert_counter [NR_CPUS] = { 0, };
+	static unsigned int last_irq_sums [NR_CPUS],
+				alert_counter [NR_CPUS];
 
 	/*
 	 * Since current-> is always on the stack, and we always switch
@@ -491,17 +492,26 @@
 }
 
 /*
- * Careful - we must not do a lock-kernel until we have checked that the
- * debug fault happened in user mode. Getting debug exceptions while
- * in the kernel has to be handled without locking, to avoid deadlocks..
+ * Our handling of the processor debug registers is non-trivial.
+ * We do not clear them on entry and exit from the kernel. Therefore
+ * it is possible to get a watchpoint trap here from inside the kernel.
+ * However, the code in ./ptrace.c has ensured that the user can
+ * only set watchpoints on userspace addresses. Therefore the in-kernel
+ * watchpoint trap can only occur in code which is reading/writing
+ * from user space. Such code must not hold kernel locks (since it
+ * can equally take a page fault), therefore it is safe to call
+ * force_sig_info even though that claims and releases locks.
+ * 
+ * Code in ./signal.c ensures that the debug control register
+ * is restored before we deliver any signal, and therefore that
+ * user code runs with the correct debug control register even though
+ * we clear it here.
  *
  * Being careful here means that we don't have to be as careful in a
  * lot of more complicated places (task switching can be a bit lazy
  * about restoring all the debug state, and ptrace doesn't have to
  * find every occurrence of the TF bit that could be saved away even
- * by user code - and we don't have to be careful about what values
- * can be written to the debug registers because there are no really
- * bad cases).
+ * by user code)
  */
 asmlinkage void do_debug(struct pt_regs * regs, long error_code)
 {
@@ -520,6 +530,9 @@
 	if (regs->eflags & VM_MASK)
 		goto debug_vm86;
 
+	/* Save debug status register where ptrace can see it */
+	tsk->thread.debugreg[6] = condition;
+
 	/* Mask out spurious TF errors due to lazy TF clearing */
 	if (condition & DR_STEP) {
 		/*
@@ -535,30 +548,33 @@
 			goto clear_TF;
 	}
 
-	/* If this is a kernel mode trap, we need to reset db7 to allow us to continue sanely */
-	if ((regs->xcs & 3) == 0)
-		goto clear_dr7;
-
 	/* Ok, finally something we can handle */
 	tsk->thread.trap_no = 1;
 	tsk->thread.error_code = error_code;
 	info.si_signo = SIGTRAP;
 	info.si_errno = 0;
 	info.si_code = TRAP_BRKPT;
-	info.si_addr = (void *)regs->eip;
+	
+	/* If this is a kernel mode trap, save the user PC on entry to 
+	 * the kernel, that's what the debugger can make sense of.
+	 */
+	info.si_addr = ((regs->xcs & 3) == 0) ? (void *)tsk->thread.eip : 
+	                                        (void *)regs->eip;
 	force_sig_info(SIGTRAP, &info, tsk);
-	return;
-
-debug_vm86:
-	handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1);
-	return;
 
+	/* Disable additional traps. They'll be re-enabled when
+	 * the signal is delivered.
+	 */
 clear_dr7:
 	__asm__("movl %0,%%db7"
 		: /* no output */
 		: "r" (0));
 	return;
 
+debug_vm86:
+	handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1);
+	return;
+
 clear_TF:
 	regs->eflags &= ~TF_MASK;
 	return;
@@ -963,6 +979,7 @@
 	set_trap_gate(15,&spurious_interrupt_bug);
 	set_trap_gate(16,&coprocessor_error);
 	set_trap_gate(17,&alignment_check);
+	set_trap_gate(18,&machine_check);
 	set_trap_gate(19,&simd_coprocessor_error);
 
 	set_system_gate(SYSCALL_VECTOR,&system_call);

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)