|
@@ -43,7 +43,7 @@
|
|
|
#include <asm/debug.h>
|
|
|
#include "entry.h"
|
|
|
|
|
|
-void (*pgm_check_table[128])(struct pt_regs *, long, unsigned long);
|
|
|
+void (*pgm_check_table[128])(struct pt_regs *regs);
|
|
|
|
|
|
int show_unhandled_signals;
|
|
|
|
|
@@ -234,7 +234,7 @@ void show_regs(struct pt_regs *regs)
|
|
|
|
|
|
static DEFINE_SPINLOCK(die_lock);
|
|
|
|
|
|
-void die(const char * str, struct pt_regs * regs, long err)
|
|
|
+void die(struct pt_regs *regs, const char *str)
|
|
|
{
|
|
|
static int die_counter;
|
|
|
|
|
@@ -243,7 +243,7 @@ void die(const char * str, struct pt_regs * regs, long err)
|
|
|
console_verbose();
|
|
|
spin_lock_irq(&die_lock);
|
|
|
bust_spinlocks(1);
|
|
|
- printk("%s: %04lx [#%d] ", str, err & 0xffff, ++die_counter);
|
|
|
+ printk("%s: %04x [#%d] ", str, regs->int_code & 0xffff, ++die_counter);
|
|
|
#ifdef CONFIG_PREEMPT
|
|
|
printk("PREEMPT ");
|
|
|
#endif
|
|
@@ -254,7 +254,7 @@ void die(const char * str, struct pt_regs * regs, long err)
|
|
|
printk("DEBUG_PAGEALLOC");
|
|
|
#endif
|
|
|
printk("\n");
|
|
|
- notify_die(DIE_OOPS, str, regs, err, current->thread.trap_no, SIGSEGV);
|
|
|
+ notify_die(DIE_OOPS, str, regs, 0, regs->int_code & 0xffff, SIGSEGV);
|
|
|
show_regs(regs);
|
|
|
bust_spinlocks(0);
|
|
|
add_taint(TAINT_DIE);
|
|
@@ -267,8 +267,7 @@ void die(const char * str, struct pt_regs * regs, long err)
|
|
|
do_exit(SIGSEGV);
|
|
|
}
|
|
|
|
|
|
-static void inline report_user_fault(struct pt_regs *regs, long int_code,
|
|
|
- int signr)
|
|
|
+static inline void report_user_fault(struct pt_regs *regs, int signr)
|
|
|
{
|
|
|
if ((task_pid_nr(current) > 1) && !show_unhandled_signals)
|
|
|
return;
|
|
@@ -276,7 +275,7 @@ static void inline report_user_fault(struct pt_regs *regs, long int_code,
|
|
|
return;
|
|
|
if (!printk_ratelimit())
|
|
|
return;
|
|
|
- printk("User process fault: interruption code 0x%lX ", int_code);
|
|
|
+ printk("User process fault: interruption code 0x%X ", regs->int_code);
|
|
|
print_vma_addr("in ", regs->psw.addr & PSW_ADDR_INSN);
|
|
|
printk("\n");
|
|
|
show_regs(regs);
|
|
@@ -287,19 +286,28 @@ int is_valid_bugaddr(unsigned long addr)
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
-static inline void __kprobes do_trap(long pgm_int_code, int signr, char *str,
|
|
|
- struct pt_regs *regs, siginfo_t *info)
|
|
|
+static inline void __user *get_psw_address(struct pt_regs *regs)
|
|
|
{
|
|
|
- if (notify_die(DIE_TRAP, str, regs, pgm_int_code,
|
|
|
- pgm_int_code, signr) == NOTIFY_STOP)
|
|
|
+ return (void __user *)
|
|
|
+ ((regs->psw.addr - (regs->int_code >> 16)) & PSW_ADDR_INSN);
|
|
|
+}
|
|
|
+
|
|
|
+static void __kprobes do_trap(struct pt_regs *regs,
|
|
|
+ int si_signo, int si_code, char *str)
|
|
|
+{
|
|
|
+ siginfo_t info;
|
|
|
+
|
|
|
+ if (notify_die(DIE_TRAP, str, regs, 0,
|
|
|
+ regs->int_code, si_signo) == NOTIFY_STOP)
|
|
|
return;
|
|
|
|
|
|
if (regs->psw.mask & PSW_MASK_PSTATE) {
|
|
|
- struct task_struct *tsk = current;
|
|
|
-
|
|
|
- tsk->thread.trap_no = pgm_int_code & 0xffff;
|
|
|
- force_sig_info(signr, info, tsk);
|
|
|
- report_user_fault(regs, pgm_int_code, signr);
|
|
|
+ info.si_signo = si_signo;
|
|
|
+ info.si_errno = 0;
|
|
|
+ info.si_code = si_code;
|
|
|
+ info.si_addr = get_psw_address(regs);
|
|
|
+ force_sig_info(si_signo, &info, current);
|
|
|
+ report_user_fault(regs, si_signo);
|
|
|
} else {
|
|
|
const struct exception_table_entry *fixup;
|
|
|
fixup = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN);
|
|
@@ -311,18 +319,11 @@ static inline void __kprobes do_trap(long pgm_int_code, int signr, char *str,
|
|
|
btt = report_bug(regs->psw.addr & PSW_ADDR_INSN, regs);
|
|
|
if (btt == BUG_TRAP_TYPE_WARN)
|
|
|
return;
|
|
|
- die(str, regs, pgm_int_code);
|
|
|
+ die(regs, str);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static inline void __user *get_psw_address(struct pt_regs *regs,
|
|
|
- long pgm_int_code)
|
|
|
-{
|
|
|
- return (void __user *)
|
|
|
- ((regs->psw.addr - (pgm_int_code >> 16)) & PSW_ADDR_INSN);
|
|
|
-}
|
|
|
-
|
|
|
void __kprobes do_per_trap(struct pt_regs *regs)
|
|
|
{
|
|
|
siginfo_t info;
|
|
@@ -339,26 +340,19 @@ void __kprobes do_per_trap(struct pt_regs *regs)
|
|
|
force_sig_info(SIGTRAP, &info, current);
|
|
|
}
|
|
|
|
|
|
-static void default_trap_handler(struct pt_regs *regs, long pgm_int_code,
|
|
|
- unsigned long trans_exc_code)
|
|
|
+static void default_trap_handler(struct pt_regs *regs)
|
|
|
{
|
|
|
if (regs->psw.mask & PSW_MASK_PSTATE) {
|
|
|
- report_user_fault(regs, pgm_int_code, SIGSEGV);
|
|
|
+ report_user_fault(regs, SIGSEGV);
|
|
|
do_exit(SIGSEGV);
|
|
|
} else
|
|
|
- die("Unknown program exception", regs, pgm_int_code);
|
|
|
+ die(regs, "Unknown program exception");
|
|
|
}
|
|
|
|
|
|
#define DO_ERROR_INFO(name, signr, sicode, str) \
|
|
|
-static void name(struct pt_regs *regs, long pgm_int_code, \
|
|
|
- unsigned long trans_exc_code) \
|
|
|
+static void name(struct pt_regs *regs) \
|
|
|
{ \
|
|
|
- siginfo_t info; \
|
|
|
- info.si_signo = signr; \
|
|
|
- info.si_errno = 0; \
|
|
|
- info.si_code = sicode; \
|
|
|
- info.si_addr = get_psw_address(regs, pgm_int_code); \
|
|
|
- do_trap(pgm_int_code, signr, str, regs, &info); \
|
|
|
+ do_trap(regs, signr, sicode, str); \
|
|
|
}
|
|
|
|
|
|
DO_ERROR_INFO(addressing_exception, SIGILL, ILL_ILLADR,
|
|
@@ -388,42 +382,34 @@ DO_ERROR_INFO(special_op_exception, SIGILL, ILL_ILLOPN,
|
|
|
DO_ERROR_INFO(translation_exception, SIGILL, ILL_ILLOPN,
|
|
|
"translation exception")
|
|
|
|
|
|
-static inline void do_fp_trap(struct pt_regs *regs, void __user *location,
|
|
|
- int fpc, long pgm_int_code)
|
|
|
+static inline void do_fp_trap(struct pt_regs *regs, int fpc)
|
|
|
{
|
|
|
- siginfo_t si;
|
|
|
-
|
|
|
- si.si_signo = SIGFPE;
|
|
|
- si.si_errno = 0;
|
|
|
- si.si_addr = location;
|
|
|
- si.si_code = 0;
|
|
|
+ int 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;
|
|
|
+ si_code = FPE_FLTINV;
|
|
|
else if (fpc & 0x4000) /* div by 0 */
|
|
|
- si.si_code = FPE_FLTDIV;
|
|
|
+ si_code = FPE_FLTDIV;
|
|
|
else if (fpc & 0x2000) /* overflow */
|
|
|
- si.si_code = FPE_FLTOVF;
|
|
|
+ si_code = FPE_FLTOVF;
|
|
|
else if (fpc & 0x1000) /* underflow */
|
|
|
- si.si_code = FPE_FLTUND;
|
|
|
+ si_code = FPE_FLTUND;
|
|
|
else if (fpc & 0x0800) /* inexact */
|
|
|
- si.si_code = FPE_FLTRES;
|
|
|
+ si_code = FPE_FLTRES;
|
|
|
}
|
|
|
- do_trap(pgm_int_code, SIGFPE,
|
|
|
- "floating point exception", regs, &si);
|
|
|
+ do_trap(regs, SIGFPE, si_code, "floating point exception");
|
|
|
}
|
|
|
|
|
|
-static void __kprobes illegal_op(struct pt_regs *regs, long pgm_int_code,
|
|
|
- unsigned long trans_exc_code)
|
|
|
+static void __kprobes illegal_op(struct pt_regs *regs)
|
|
|
{
|
|
|
siginfo_t info;
|
|
|
__u8 opcode[6];
|
|
|
__u16 __user *location;
|
|
|
int signal = 0;
|
|
|
|
|
|
- location = get_psw_address(regs, pgm_int_code);
|
|
|
+ location = get_psw_address(regs);
|
|
|
|
|
|
if (regs->psw.mask & PSW_MASK_PSTATE) {
|
|
|
if (get_user(*((__u16 *) opcode), (__u16 __user *) location))
|
|
@@ -467,44 +453,31 @@ static void __kprobes illegal_op(struct pt_regs *regs, long pgm_int_code,
|
|
|
* If we get an illegal op in kernel mode, send it through the
|
|
|
* kprobes notifier. If kprobes doesn't pick it up, SIGILL
|
|
|
*/
|
|
|
- if (notify_die(DIE_BPT, "bpt", regs, pgm_int_code,
|
|
|
+ if (notify_die(DIE_BPT, "bpt", regs, 0,
|
|
|
3, SIGTRAP) != NOTIFY_STOP)
|
|
|
signal = SIGILL;
|
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_MATHEMU
|
|
|
if (signal == SIGFPE)
|
|
|
- do_fp_trap(regs, location,
|
|
|
- current->thread.fp_regs.fpc, pgm_int_code);
|
|
|
- else if (signal == SIGSEGV) {
|
|
|
- info.si_signo = signal;
|
|
|
- info.si_errno = 0;
|
|
|
- info.si_code = SEGV_MAPERR;
|
|
|
- info.si_addr = (void __user *) location;
|
|
|
- do_trap(pgm_int_code, signal,
|
|
|
- "user address fault", regs, &info);
|
|
|
- } else
|
|
|
+ do_fp_trap(regs, current->thread.fp_regs.fpc);
|
|
|
+ else if (signal == SIGSEGV)
|
|
|
+ do_trap(regs, signal, SEGV_MAPERR, "user address fault");
|
|
|
+ else
|
|
|
#endif
|
|
|
- if (signal) {
|
|
|
- info.si_signo = signal;
|
|
|
- info.si_errno = 0;
|
|
|
- info.si_code = ILL_ILLOPC;
|
|
|
- info.si_addr = (void __user *) location;
|
|
|
- do_trap(pgm_int_code, signal,
|
|
|
- "illegal operation", regs, &info);
|
|
|
- }
|
|
|
+ if (signal)
|
|
|
+ do_trap(regs, signal, ILL_ILLOPC, "illegal operation");
|
|
|
}
|
|
|
|
|
|
|
|
|
#ifdef CONFIG_MATHEMU
|
|
|
-void specification_exception(struct pt_regs *regs, long pgm_int_code,
|
|
|
- unsigned long trans_exc_code)
|
|
|
+void specification_exception(struct pt_regs *regs)
|
|
|
{
|
|
|
__u8 opcode[6];
|
|
|
__u16 __user *location = NULL;
|
|
|
int signal = 0;
|
|
|
|
|
|
- location = (__u16 __user *) get_psw_address(regs, pgm_int_code);
|
|
|
+ location = (__u16 __user *) get_psw_address(regs);
|
|
|
|
|
|
if (regs->psw.mask & PSW_MASK_PSTATE) {
|
|
|
get_user(*((__u16 *) opcode), location);
|
|
@@ -539,30 +512,21 @@ void specification_exception(struct pt_regs *regs, long pgm_int_code,
|
|
|
signal = SIGILL;
|
|
|
|
|
|
if (signal == SIGFPE)
|
|
|
- do_fp_trap(regs, location,
|
|
|
- current->thread.fp_regs.fpc, pgm_int_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(pgm_int_code, signal,
|
|
|
- "specification exception", regs, &info);
|
|
|
- }
|
|
|
+ do_fp_trap(regs, current->thread.fp_regs.fpc);
|
|
|
+ else if (signal)
|
|
|
+ do_trap(regs, signal, ILL_ILLOPN, "specification exception");
|
|
|
}
|
|
|
#else
|
|
|
DO_ERROR_INFO(specification_exception, SIGILL, ILL_ILLOPN,
|
|
|
"specification exception");
|
|
|
#endif
|
|
|
|
|
|
-static void data_exception(struct pt_regs *regs, long pgm_int_code,
|
|
|
- unsigned long trans_exc_code)
|
|
|
+static void data_exception(struct pt_regs *regs)
|
|
|
{
|
|
|
__u16 __user *location;
|
|
|
int signal = 0;
|
|
|
|
|
|
- location = get_psw_address(regs, pgm_int_code);
|
|
|
+ location = get_psw_address(regs);
|
|
|
|
|
|
if (MACHINE_HAS_IEEE)
|
|
|
asm volatile("stfpc %0" : "=m" (current->thread.fp_regs.fpc));
|
|
@@ -627,32 +591,18 @@ static void data_exception(struct pt_regs *regs, long pgm_int_code,
|
|
|
else
|
|
|
signal = SIGILL;
|
|
|
if (signal == SIGFPE)
|
|
|
- do_fp_trap(regs, location,
|
|
|
- current->thread.fp_regs.fpc, pgm_int_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(pgm_int_code, signal, "data exception", regs, &info);
|
|
|
- }
|
|
|
+ do_fp_trap(regs, current->thread.fp_regs.fpc);
|
|
|
+ else if (signal)
|
|
|
+ do_trap(regs, signal, ILL_ILLOPN, "data exception");
|
|
|
}
|
|
|
|
|
|
-static void space_switch_exception(struct pt_regs *regs, long pgm_int_code,
|
|
|
- unsigned long trans_exc_code)
|
|
|
+static void space_switch_exception(struct pt_regs *regs)
|
|
|
{
|
|
|
- siginfo_t info;
|
|
|
-
|
|
|
/* Set user psw back to home space mode. */
|
|
|
if (regs->psw.mask & PSW_MASK_PSTATE)
|
|
|
regs->psw.mask |= PSW_ASC_HOME;
|
|
|
/* Send SIGILL. */
|
|
|
- info.si_signo = SIGILL;
|
|
|
- info.si_errno = 0;
|
|
|
- info.si_code = ILL_PRVOPC;
|
|
|
- info.si_addr = get_psw_address(regs, pgm_int_code);
|
|
|
- do_trap(pgm_int_code, SIGILL, "space switch event", regs, &info);
|
|
|
+ do_trap(regs, SIGILL, ILL_PRVOPC, "space switch event");
|
|
|
}
|
|
|
|
|
|
void __kprobes kernel_stack_overflow(struct pt_regs * regs)
|