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

Next file: linux/arch/i386/mm/fault.c
Previous file: linux/arch/i386/kernel/smpboot.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.99-pre9/linux/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c
@@ -2,6 +2,7 @@
  *  linux/arch/i386/traps.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
+ *  FXSAVE/FXRSTOR support by Ingo Molnar, OS exception support by Goutham Rao
  */
 
 /*
@@ -82,6 +83,20 @@
 	force_sig(signr, tsk); \
 }
 
+#define DO_ERROR_INFO(trapnr, signr, str, name, tsk, sicode, siaddr) \
+asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
+{ \
+	siginfo_t info; \
+	tsk->thread.error_code = error_code; \
+	tsk->thread.trap_no = trapnr; \
+	die_if_no_fixup(str,regs,error_code); \
+	info.si_signo = signr; \
+	info.si_errno = 0; \
+	info.si_code = sicode; \
+	info.si_addr = (void *)siaddr; \
+	force_sig_info(signr, &info, tsk); \
+}
+
 #define DO_VM86_ERROR(trapnr, signr, str, name, tsk) \
 asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
 { \
@@ -99,6 +114,28 @@
 	unlock_kernel(); \
 }
 
+#define DO_VM86_ERROR_INFO(trapnr, signr, str, name, tsk, sicode, siaddr) \
+asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
+{ \
+	siginfo_t info; \
+	lock_kernel(); \
+	if (regs->eflags & VM_MASK) { \
+		if (!handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, trapnr)) \
+			goto out; \
+		/* else fall through */ \
+	} \
+	tsk->thread.error_code = error_code; \
+	tsk->thread.trap_no = trapnr; \
+	info.si_signo = signr; \
+	info.si_errno = 0; \
+	info.si_code = sicode; \
+	info.si_addr = (void *)siaddr; \
+	force_sig_info(signr, &info, tsk); \
+	die_if_kernel(str,regs,error_code); \
+out: \
+	unlock_kernel(); \
+}
+
 void page_exception(void);
 
 asmlinkage void divide_error(void);
@@ -120,6 +157,7 @@
 asmlinkage void reserved(void);
 asmlinkage void alignment_check(void);
 asmlinkage void spurious_interrupt_bug(void);
+asmlinkage void xmm_fault(void);
 
 int kstack_depth_to_print = 24;
 
@@ -260,34 +298,29 @@
 	}
 }
 
-DO_VM86_ERROR( 0, SIGFPE,  "divide error", divide_error, current)
+static inline unsigned long get_cr2(void)
+{
+	unsigned long address;
+
+	/* get the address */
+	__asm__("movl %%cr2,%0":"=r" (address));
+	return address;
+}
+
+DO_VM86_ERROR_INFO( 0, SIGFPE,  "divide error", divide_error, current, FPE_INTDIV, regs->eip)
 DO_VM86_ERROR( 3, SIGTRAP, "int3", int3, current)
 DO_VM86_ERROR( 4, SIGSEGV, "overflow", overflow, current)
 DO_VM86_ERROR( 5, SIGSEGV, "bounds", bounds, current)
-DO_ERROR( 6, SIGILL,  "invalid operand", invalid_op, current)
+DO_ERROR_INFO( 6, SIGILL,  "invalid operand", invalid_op, current, ILL_ILLOPN, regs->eip)
 DO_VM86_ERROR( 7, SIGSEGV, "device not available", device_not_available, current)
 DO_ERROR( 8, SIGSEGV, "double fault", double_fault, current)
 DO_ERROR( 9, SIGFPE,  "coprocessor segment overrun", coprocessor_segment_overrun, current)
 DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS, current)
 DO_ERROR(11, SIGBUS,  "segment not present", segment_not_present, current)
 DO_ERROR(12, SIGBUS,  "stack segment", stack_segment, current)
-DO_ERROR(17, SIGSEGV, "alignment check", alignment_check, current)
+DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, current, BUS_ADRALN, get_cr2())
 DO_ERROR(18, SIGSEGV, "reserved", reserved, current)
-/* I don't have documents for this but it does seem to cover the cache
-   flush from user space exception some people get. */
-DO_ERROR(19, SIGSEGV, "cache flush denied", cache_flush_denied, current)
-
-asmlinkage void cache_flush_denied(struct pt_regs * regs, long error_code)
-{
-	if (regs->eflags & VM_MASK) {
-		handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code);
-		return;
-	}
-	die_if_kernel("cache flush denied",regs,error_code);
-	current->thread.error_code = error_code;
-	current->thread.trap_no = 19;
-	force_sig(SIGSEGV, current);
-}
+DO_VM86_ERROR(19, SIGFPE, "XMM fault", xmm_fault, current)
 
 asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
 {
@@ -485,6 +518,7 @@
 {
 	unsigned int condition;
 	struct task_struct *tsk = current;
+	siginfo_t info;
 
 	__asm__ __volatile__("movl %%db6,%0" : "=r" (condition));
 
@@ -519,7 +553,11 @@
 	/* Ok, finally something we can handle */
 	tsk->thread.trap_no = 1;
 	tsk->thread.error_code = error_code;
-	force_sig(SIGTRAP, tsk);
+	info.si_signo = SIGTRAP;
+	info.si_errno = 0;
+	info.si_code = TRAP_BRKPT;
+	info.si_addr = (void *)regs->eip;
+	force_sig_info(SIGTRAP, &info, tsk);
 	return;
 
 debug_vm86:
@@ -544,9 +582,10 @@
  * the correct behaviour even in the presence of the asynchronous
  * IRQ13 behaviour
  */
-void math_error(void)
+void math_error(void *eip)
 {
 	struct task_struct * task;
+	siginfo_t info;
 
 	/*
 	 * Save the info for the exception handler
@@ -556,13 +595,52 @@
 	save_fpu(task);
 	task->thread.trap_no = 16;
 	task->thread.error_code = 0;
-	force_sig(SIGFPE, task);
+	info.si_signo = SIGFPE;
+	info.si_errno = 0;
+	info.si_code = __SI_FAULT;
+	info.si_addr = eip;
+	/*
+	 * (~cwd & swd) will mask out exceptions that are not set to unmasked
+	 * status.  0x3f is the exception bits in these regs, 0x200 is the
+	 * C1 reg you need in case of a stack fault, 0x040 is the stack
+	 * fault bit.  We should only be taking one exception at a time,
+	 * so if this combination doesn't produce any single exception,
+	 * then we have a bad program that isn't syncronizing its FPU usage
+	 * and it will suffer the consequences since we won't be able to
+	 * fully reproduce the context of the exception
+	 */
+	switch(((~task->thread.i387.hard.cwd) &
+		task->thread.i387.hard.swd & 0x3f) |
+	       (task->thread.i387.hard.swd & 0x240)) {
+		case 0x000:
+		default:
+			break;
+		case 0x001: /* Invalid Op */
+		case 0x040: /* Stack Fault */
+		case 0x240: /* Stack Fault | Direction */
+			info.si_code = FPE_FLTINV;
+			break;
+		case 0x002: /* Denormalize */
+		case 0x010: /* Underflow */
+			info.si_code = FPE_FLTUND;
+			break;
+		case 0x004: /* Zero Divide */
+			info.si_code = FPE_FLTDIV;
+			break;
+		case 0x008: /* Overflow */
+			info.si_code = FPE_FLTOVF;
+			break;
+		case 0x020: /* Precision */
+			info.si_code = FPE_FLTRES;
+			break;
+	}
+	force_sig_info(SIGFPE, &info, task);
 }
 
 asmlinkage void do_coprocessor_error(struct pt_regs * regs, long error_code)
 {
 	ignore_irq13 = 1;
-	math_error();
+	math_error((void *)regs->eip);
 }
 
 asmlinkage void do_spurious_interrupt_bug(struct pt_regs * regs,
@@ -586,7 +664,7 @@
 	__asm__ __volatile__("clts");		/* Allow maths ops (or we recurse) */
 
 	if(current->used_math)
-		__asm__("frstor %0": :"m" (current->thread.i387));
+		i387_restore_hard(current->thread.i387);
 	else
 	{
 		/*
@@ -829,6 +907,8 @@
 	set_trap_gate(15,&spurious_interrupt_bug);
 	set_trap_gate(16,&coprocessor_error);
 	set_trap_gate(17,&alignment_check);
+	set_trap_gate(19,&xmm_fault);
+
 	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)