patch-2.4.19 linux-2.4.19/arch/s390/kernel/traps.c

Next file: linux-2.4.19/arch/s390/lib/Makefile
Previous file: linux-2.4.19/arch/s390/kernel/time.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.18/arch/s390/kernel/traps.c linux-2.4.19/arch/s390/kernel/traps.c
@@ -50,7 +50,9 @@
 #endif
 #endif
 
-extern pgm_check_handler_t do_page_fault;
+extern pgm_check_handler_t do_protection_exception;
+extern pgm_check_handler_t do_segment_exception;
+extern pgm_check_handler_t do_page_exception;
 extern pgm_check_handler_t do_pseudo_page_fault;
 #ifdef CONFIG_PFAULT
 extern int pfault_init(void);
@@ -269,23 +271,6 @@
         do_exit(SIGSEGV);
 }
 
-#define DO_ERROR(signr, str, name) \
-asmlinkage void name(struct pt_regs * regs, long interruption_code) \
-{ \
-	do_trap(interruption_code, signr, str, regs, NULL); \
-}
-
-#define DO_ERROR_INFO(signr, str, name, sicode, siaddr) \
-asmlinkage void name(struct pt_regs * regs, long interruption_code) \
-{ \
-        siginfo_t info; \
-        info.si_signo = signr; \
-        info.si_errno = 0; \
-        info.si_code = sicode; \
-        info.si_addr = (void *)siaddr; \
-        do_trap(interruption_code, signr, str, regs, &info); \
-}
-
 static void inline do_trap(long interruption_code, int signr, char *str,
                            struct pt_regs *regs, siginfo_t *info)
 {
@@ -299,7 +284,7 @@
         if (regs->psw.mask & PSW_PROBLEM_STATE) {
                 struct task_struct *tsk = current;
 
-                tsk->thread.trap_no = interruption_code;
+                tsk->thread.trap_no = interruption_code & 0xffff;
 		if (info)
 			force_sig_info(signr, info, tsk);
 		else
@@ -326,6 +311,11 @@
         }
 }
 
+static inline void *get_check_address(struct pt_regs *regs)
+{
+	return (void *) ADDR_BITS_REMOVE(regs->psw.addr-S390_lowcore.pgm_ilc);
+}
+
 int do_debugger_trap(struct pt_regs *regs,int signal)
 {
 	if(regs->psw.mask&PSW_PROBLEM_STATE)
@@ -349,14 +339,68 @@
 	return 0;
 }
 
+#define DO_ERROR(signr, str, name) \
+asmlinkage void name(struct pt_regs * regs, long interruption_code) \
+{ \
+	do_trap(interruption_code, signr, str, regs, NULL); \
+}
+
+#define DO_ERROR_INFO(signr, str, name, sicode, siaddr) \
+asmlinkage void name(struct pt_regs * regs, long interruption_code) \
+{ \
+        siginfo_t info; \
+        info.si_signo = signr; \
+        info.si_errno = 0; \
+        info.si_code = sicode; \
+        info.si_addr = (void *)siaddr; \
+        do_trap(interruption_code, signr, str, regs, &info); \
+}
+
 DO_ERROR(SIGSEGV, "Unknown program exception", default_trap_handler)
-DO_ERROR(SIGILL,  "privileged operation", privileged_op)
-DO_ERROR(SIGILL,  "execute exception", execute_exception)
-DO_ERROR(SIGSEGV, "addressing exception", addressing_exception)
-DO_ERROR(SIGFPE,  "fixpoint divide exception", divide_exception)
-DO_ERROR(SIGILL,  "translation exception", translation_exception)
-DO_ERROR(SIGILL,  "special operand exception", special_op_exception)
-DO_ERROR(SIGILL,  "operand exception", operand_exception)
+
+DO_ERROR_INFO(SIGBUS, "addressing exception", addressing_exception,
+	      BUS_ADRERR, get_check_address(regs))
+DO_ERROR_INFO(SIGILL,  "execute exception", execute_exception,
+	      ILL_ILLOPN, get_check_address(regs))
+DO_ERROR_INFO(SIGFPE,  "fixpoint divide exception", divide_exception,
+	      FPE_INTDIV, get_check_address(regs))
+DO_ERROR_INFO(SIGILL,  "operand exception", operand_exception,
+	      ILL_ILLOPN, get_check_address(regs))
+DO_ERROR_INFO(SIGILL,  "privileged operation", privileged_op,
+	      ILL_PRVOPC, get_check_address(regs))
+DO_ERROR_INFO(SIGILL,  "special operation exception", special_op_exception,
+	      ILL_ILLOPN, get_check_address(regs))
+DO_ERROR_INFO(SIGILL,  "translation exception", translation_exception,
+	      ILL_ILLOPN, get_check_address(regs))
+
+static inline void
+do_fp_trap(struct pt_regs *regs, void *location,
+           int fpc, long interruption_code)
+{
+	siginfo_t si;
+
+	si.si_signo = SIGFPE;
+	si.si_errno = 0;
+	si.si_addr = location;
+	si.si_code = 0;
+	/* FPC[2] is Data Exception Code */
+	if ((fpc & 0x00000300) == 0) {
+		/* bits 6 and 7 of DXC are 0 iff IEEE exception */
+		if (fpc & 0x8000) /* invalid fp operation */
+			si.si_code = FPE_FLTINV;
+		else if (fpc & 0x4000) /* div by 0 */
+			si.si_code = FPE_FLTDIV;
+		else if (fpc & 0x2000) /* overflow */
+			si.si_code = FPE_FLTOVF;
+		else if (fpc & 0x1000) /* underflow */
+			si.si_code = FPE_FLTUND;
+		else if (fpc & 0x0800) /* inexact */
+			si.si_code = FPE_FLTRES;
+	}
+	current->thread.ieee_instruction_pointer = (addr_t) location;
+	do_trap(interruption_code, SIGFPE,
+		"floating point exception", regs, &si);
+}
 
 asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code)
 {
@@ -407,11 +451,10 @@
 #endif 
 	else
 		signal = SIGILL;
-        if (signal == SIGFPE) {
-		current->thread.ieee_instruction_pointer = (addr_t) location;
-		do_trap(interruption_code, signal,
-			"floating point exception", regs, NULL);
-        } else if (signal)
+        if (signal == SIGFPE)
+		do_fp_trap(regs, location,
+                           current->thread.fp_regs.fpc, interruption_code);
+        else if (signal)
 		do_trap(interruption_code, signal,
 			"illegal operation", regs, NULL);
 }
@@ -426,7 +469,7 @@
 	__u16 *location = NULL;
 	int signal = 0;
 
-	location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
+	location = (__u16 *) get_check_address(regs);
 
 	/*
 	 * We got all needed information from the lowcore and can
@@ -466,16 +509,22 @@
                 }
         } else
 		signal = SIGILL;
-        if (signal == SIGFPE) {
-		current->thread.ieee_instruction_pointer = (addr_t) location;
-		do_trap(interruption_code, signal,
-			"floating point exception", regs, NULL);
-        } else if (signal)
-                do_trap(interruption_code, signal,
-			"specification exception", regs, NULL);
+        if (signal == SIGFPE)
+		do_fp_trap(regs, location,
+                           current->thread.fp_regs.fpc, interruption_code);
+        else if (signal) {
+		siginfo_t info;
+		info.si_signo = signal;
+		info.si_errno = 0;
+		info.si_code = ILL_ILLOPN;
+		info.si_addr = location;
+		do_trap(interruption_code, signal, 
+			"specification exception", regs, &info);
+	}
 }
 #else
-DO_ERROR(SIGILL, "specification exception", specification_exception)
+DO_ERROR_INFO(SIGILL, "specification exception", specification_exception,
+	      ILL_ILLOPN, get_check_address(regs));
 #endif
 
 asmlinkage void data_exception(struct pt_regs * regs, long interruption_code)
@@ -484,7 +533,7 @@
 	__u16 *location;
 	int signal = 0;
 
-	location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
+	location = (__u16 *) get_check_address(regs);
 
 	/*
 	 * We got all needed information from the lowcore and can
@@ -555,13 +604,18 @@
 		signal = SIGFPE;
 	else
 		signal = SIGILL;
-        if (signal == SIGFPE) {
-		current->thread.ieee_instruction_pointer = (addr_t) location;
-		do_trap(interruption_code, signal,
-			"floating point exception", regs, NULL);
-	} else if (signal) 
-                do_trap(interruption_code, signal,
-			"data exception", regs, NULL);
+        if (signal == SIGFPE)
+		do_fp_trap(regs, location,
+                           current->thread.fp_regs.fpc, interruption_code);
+        else if (signal) {
+		siginfo_t info;
+		info.si_signo = signal;
+		info.si_errno = 0;
+		info.si_code = ILL_ILLOPN;
+		info.si_addr = location;
+		do_trap(interruption_code, signal, 
+			"data exception", regs, &info);
+	}
 }
 
 
@@ -577,13 +631,13 @@
         pgm_check_table[1] = &illegal_op;
         pgm_check_table[2] = &privileged_op;
         pgm_check_table[3] = &execute_exception;
-        pgm_check_table[4] = &do_page_fault;
+        pgm_check_table[4] = &do_protection_exception;
         pgm_check_table[5] = &addressing_exception;
         pgm_check_table[6] = &specification_exception;
         pgm_check_table[7] = &data_exception;
         pgm_check_table[9] = &divide_exception;
-        pgm_check_table[0x10] = &do_page_fault;
-        pgm_check_table[0x11] = &do_page_fault;
+        pgm_check_table[0x10] = &do_segment_exception;
+        pgm_check_table[0x11] = &do_page_exception;
         pgm_check_table[0x12] = &translation_exception;
         pgm_check_table[0x13] = &special_op_exception;
  	pgm_check_table[0x14] = &do_pseudo_page_fault;

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