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
- Lines: 240
- Date:
Fri Aug 2 17:39:43 2002
- Orig file:
linux-2.4.18/arch/s390/kernel/traps.c
- Orig date:
Mon Feb 25 11:37:56 2002
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] = ÷_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)