[S390] cleanup trap handling
authorMartin Schwidefsky <schwidefsky@de.ibm.com>
Tue, 27 Dec 2011 10:27:18 +0000 (11:27 +0100)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Tue, 27 Dec 2011 10:27:12 +0000 (11:27 +0100)
Move the program interruption code and the translation exception identifier
to the pt_regs structure as 'int_code' and 'int_parm_long' and make the
first level interrupt handler in entry[64].S store the two values. That
makes it possible to drop 'prot_addr' and 'trap_no' from the thread_struct
and to reduce the number of arguments to a lot of functions. Finally
un-inline do_trap. Overall this saves 5812 bytes in the .text section of
the 64 bit kernel.

Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
12 files changed:
arch/s390/include/asm/kdebug.h
arch/s390/include/asm/processor.h
arch/s390/include/asm/ptrace.h
arch/s390/include/asm/syscall.h
arch/s390/kernel/asm-offsets.c
arch/s390/kernel/compat_signal.c
arch/s390/kernel/entry.S
arch/s390/kernel/entry.h
arch/s390/kernel/entry64.S
arch/s390/kernel/signal.c
arch/s390/kernel/traps.c
arch/s390/mm/fault.c

index 40db27cd6e608df9c54285c6e1b52c6d572277f4..5c1abd47612a433fa6a33fbdc7a90b1cde66890d 100644 (file)
@@ -22,6 +22,6 @@ enum die_val {
        DIE_NMI_IPI,
 };
 
-extern void die(const char *, struct pt_regs *, long);
+extern void die(struct pt_regs *, const char *);
 
 #endif
index 5f33d37d032c81a988310f8e539c7986f0ea4c6b..27272f6a14c2fbecf4f9a6f1a29cba7986f3bb92 100644 (file)
@@ -80,8 +80,6 @@ struct thread_struct {
        unsigned int  acrs[NUM_ACRS];
         unsigned long ksp;              /* kernel stack pointer             */
        mm_segment_t mm_segment;
-        unsigned long prot_addr;        /* address of protection-excep.     */
-        unsigned int trap_no;
        unsigned long gmap_addr;        /* address of last gmap fault. */
        struct per_regs per_user;       /* User specified PER registers */
        struct per_event per_event;     /* Cause of the last PER trap */
index a65846340d51d74c453bcc29f089c7932b3bff6d..56da355678f4aa7feed766a016b84282381451ba 100644 (file)
@@ -324,7 +324,8 @@ struct pt_regs
        psw_t psw;
        unsigned long gprs[NUM_GPRS];
        unsigned long orig_gpr2;
-       unsigned int svc_code;
+       unsigned int int_code;
+       unsigned long int_parm_long;
 };
 
 /*
index b239ff53b189fd90c66003d350c183785620ad95..fb214dd9b7e0631606072a00a6b3994de4e8a97b 100644 (file)
@@ -27,7 +27,7 @@ static inline long syscall_get_nr(struct task_struct *task,
                                  struct pt_regs *regs)
 {
        return test_tsk_thread_flag(task, TIF_SYSCALL) ?
-               (regs->svc_code & 0xffff) : -1;
+               (regs->int_code & 0xffff) : -1;
 }
 
 static inline void syscall_rollback(struct task_struct *task,
index c1a56ba5f8486c3393af91d88dde564d74f52c68..6e6a72e66d60d8ed6aabf84a9821af65ddea2282 100644 (file)
@@ -45,7 +45,8 @@ int main(void)
        DEFINE(__PT_PSW, offsetof(struct pt_regs, psw));
        DEFINE(__PT_GPRS, offsetof(struct pt_regs, gprs));
        DEFINE(__PT_ORIG_GPR2, offsetof(struct pt_regs, orig_gpr2));
-       DEFINE(__PT_SVC_CODE, offsetof(struct pt_regs, svc_code));
+       DEFINE(__PT_INT_CODE, offsetof(struct pt_regs, int_code));
+       DEFINE(__PT_INT_PARM_LONG, offsetof(struct pt_regs, int_parm_long));
        DEFINE(__PT_SIZE, sizeof(struct pt_regs));
        BLANK();
        DEFINE(__SF_BACKCHAIN, offsetof(struct stack_frame, back_chain));
index 4f68c81d3ffaafb7ee1db39e7c63375e0d08422b..60c268b16f91a2c29f97d14931bd0362af48ba95 100644 (file)
@@ -501,8 +501,12 @@ static int setup_frame32(int sig, struct k_sigaction *ka,
 
        /* We forgot to include these in the sigcontext.
           To avoid breaking binary compatibility, they are passed as args. */
-       regs->gprs[4] = current->thread.trap_no;
-       regs->gprs[5] = current->thread.prot_addr;
+       if (sig == SIGSEGV || sig == SIGBUS || sig == SIGILL ||
+           sig == SIGTRAP || sig == SIGFPE) {
+               /* set extra registers only for synchronous signals */
+               regs->gprs[4] = regs->int_code & 127;
+               regs->gprs[5] = regs->int_parm_long;
+       }
 
        /* Place signal number on stack to allow backtrace from handler.  */
        if (__put_user(regs->gprs[2], (int __force __user *) &frame->signo))
index c2773cff89c3041e42c1cf08607e286e1e08b48b..3705700ed37451ace0685532f6da7d8f12eb8100 100644 (file)
@@ -184,16 +184,16 @@ sysc_vtime:
        stm     %r0,%r7,__PT_R0(%r11)
        mvc     __PT_R8(32,%r11),__LC_SAVE_AREA_SYNC
        mvc     __PT_PSW(8,%r11),__LC_SVC_OLD_PSW
-       mvc     __PT_SVC_CODE(4,%r11),__LC_SVC_ILC
+       mvc     __PT_INT_CODE(4,%r11),__LC_SVC_ILC
 sysc_do_svc:
        oi      __TI_flags+3(%r12),_TIF_SYSCALL
-       lh      %r8,__PT_SVC_CODE+2(%r11)
+       lh      %r8,__PT_INT_CODE+2(%r11)
        sla     %r8,2                           # shift and test for svc0
        jnz     sysc_nr_ok
        # svc 0: system call number in %r1
        cl      %r1,BASED(.Lnr_syscalls)
        jnl     sysc_nr_ok
-       sth     %r1,__PT_SVC_CODE+2(%r11)
+       sth     %r1,__PT_INT_CODE+2(%r11)
        lr      %r8,%r1
        sla     %r8,2
 sysc_nr_ok:
@@ -266,9 +266,9 @@ sysc_sigpending:
        jno     sysc_return
        lm      %r2,%r7,__PT_R2(%r11)   # load svc arguments
        xr      %r8,%r8                 # svc 0 returns -ENOSYS
-       clc     __PT_SVC_CODE+2(2,%r11),BASED(.Lnr_syscalls+2)
+       clc     __PT_INT_CODE+2(2,%r11),BASED(.Lnr_syscalls+2)
        jnl     sysc_nr_ok              # invalid svc number -> do svc 0
-       lh      %r8,__PT_SVC_CODE+2(%r11)       # load new svc number
+       lh      %r8,__PT_INT_CODE+2(%r11)       # load new svc number
        sla     %r8,2
        j       sysc_nr_ok              # restart svc
 
@@ -300,7 +300,7 @@ sysc_tracesys:
        lr      %r2,%r11                # pass pointer to pt_regs
        la      %r3,0
        xr      %r0,%r0
-       icm     %r0,3,__PT_SVC_CODE+2(%r11)
+       icm     %r0,3,__PT_INT_CODE+2(%r11)
        st      %r0,__PT_R2(%r11)
        basr    %r14,%r1                # call do_syscall_trace_enter
        cl      %r2,BASED(.Lnr_syscalls)
@@ -396,6 +396,8 @@ ENTRY(pgm_check_handler)
        stm     %r0,%r7,__PT_R0(%r11)
        mvc     __PT_R8(32,%r11),__LC_SAVE_AREA_SYNC
        stm     %r8,%r9,__PT_PSW(%r11)
+       mvc     __PT_INT_CODE(4,%r11),__LC_PGM_ILC
+       mvc     __PT_INT_PARM_LONG(4,%r11),__LC_TRANS_EXC_CODE
        tm      __LC_PGM_ILC+3,0x80     # check for per exception
        jz      0f
        l       %r1,__TI_task(%r12)
@@ -405,13 +407,11 @@ ENTRY(pgm_check_handler)
        mvc     __THREAD_per_address(4,%r1),__LC_PER_ADDRESS
        mvc     __THREAD_per_cause(2,%r1),__LC_PER_CAUSE
        mvc     __THREAD_per_paid(1,%r1),__LC_PER_PAID
-0:     l       %r3,__LC_PGM_ILC        # load program interruption code
-       l       %r4,__LC_TRANS_EXC_CODE
-       REENABLE_IRQS
+0:     REENABLE_IRQS
        xc      __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15)
        l       %r1,BASED(.Ljump_table)
        la      %r10,0x7f
-       nr      %r10,%r3
+       n       %r10,__PT_INT_CODE(%r11)
        je      sysc_return
        sll     %r10,2
        l       %r1,0(%r10,%r1)         # load address of handler routine
@@ -858,7 +858,7 @@ cleanup_system_call:
        mvc     __PT_R8(32,%r15),__LC_SAVE_AREA_SYNC
        stm     %r0,%r7,__PT_R0(%r15)
        mvc     __PT_PSW(8,%r15),__LC_SVC_OLD_PSW
-       mvc     __PT_SVC_CODE(4,%r15),__LC_SVC_ILC
+       mvc     __PT_INT_CODE(4,%r15),__LC_SVC_ILC
        # setup saved register 15
        ahi     %r15,-STACK_FRAME_OVERHEAD
        st      %r15,28(%r11)           # r15 stack pointer
index ef8fb1d6e8d72ed51ebac3906456c9eef95e5166..bf538aaf407d8ceb433f094e7d8b6cb22f2c65d5 100644 (file)
@@ -6,15 +6,15 @@
 #include <asm/ptrace.h>
 
 
-extern void (*pgm_check_table[128])(struct pt_regs *, long, unsigned long);
+extern void (*pgm_check_table[128])(struct pt_regs *);
 extern void *restart_stack;
 
 asmlinkage long do_syscall_trace_enter(struct pt_regs *regs);
 asmlinkage void do_syscall_trace_exit(struct pt_regs *regs);
 
-void do_protection_exception(struct pt_regs *, long, unsigned long);
-void do_dat_exception(struct pt_regs *, long, unsigned long);
-void do_asce_exception(struct pt_regs *, long, unsigned long);
+void do_protection_exception(struct pt_regs *regs);
+void do_dat_exception(struct pt_regs *regs);
+void do_asce_exception(struct pt_regs *regs);
 
 void do_per_trap(struct pt_regs *regs);
 void syscall_trace(struct pt_regs *regs, int entryexit);
@@ -28,7 +28,7 @@ void do_extint(struct pt_regs *regs, unsigned int, unsigned int, unsigned long);
 void do_restart(void);
 int __cpuinit start_secondary(void *cpuvoid);
 void __init startup_init(void);
-void die(const char * str, struct pt_regs * regs, long err);
+void die(struct pt_regs *regs, const char *str);
 
 void __init time_init(void);
 
index 73845a9e587cba618750164d03333afc892c49d9..412a7b8783d7b99c47f5b3715a328d4fdf0ea1ed 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  *  arch/s390/kernel/entry64.S
  *    S390 low-level entry points.
@@ -200,17 +199,17 @@ sysc_vtime:
        stmg    %r0,%r7,__PT_R0(%r11)
        mvc     __PT_R8(64,%r11),__LC_SAVE_AREA_SYNC
        mvc     __PT_PSW(16,%r11),__LC_SVC_OLD_PSW
-       mvc     __PT_SVC_CODE(4,%r11),__LC_SVC_ILC
+       mvc     __PT_INT_CODE(4,%r11),__LC_SVC_ILC
 sysc_do_svc:
        oi      __TI_flags+7(%r12),_TIF_SYSCALL
-       llgh    %r8,__PT_SVC_CODE+2(%r11)
+       llgh    %r8,__PT_INT_CODE+2(%r11)
        slag    %r8,%r8,2                       # shift and test for svc 0
        jnz     sysc_nr_ok
        # svc 0: system call number in %r1
        llgfr   %r1,%r1                         # clear high word in r1
        cghi    %r1,NR_syscalls
        jnl     sysc_nr_ok
-       sth     %r1,__PT_SVC_CODE+2(%r11)
+       sth     %r1,__PT_INT_CODE+2(%r11)
        slag    %r8,%r1,2
 sysc_nr_ok:
        larl    %r10,sys_call_table             # 64 bit system call table
@@ -288,7 +287,7 @@ sysc_sigpending:
        jno     sysc_return
        lmg     %r2,%r7,__PT_R2(%r11)   # load svc arguments
        lghi    %r8,0                   # svc 0 returns -ENOSYS
-       lh      %r1,__PT_SVC_CODE+2(%r11)       # load new svc number
+       lh      %r1,__PT_INT_CODE+2(%r11)       # load new svc number
        cghi    %r1,NR_syscalls
        jnl     sysc_nr_ok              # invalid svc number -> do svc 0
        slag    %r8,%r1,2
@@ -318,7 +317,7 @@ sysc_singlestep:
 sysc_tracesys:
        lgr     %r2,%r11                # pass pointer to pt_regs
        la      %r3,0
-       llgh    %r0,__PT_SVC_CODE+2(%r11)
+       llgh    %r0,__PT_INT_CODE+2(%r11)
        stg     %r0,__PT_R2(%r11)
        brasl   %r14,do_syscall_trace_enter
        lghi    %r0,NR_syscalls
@@ -411,6 +410,8 @@ ENTRY(pgm_check_handler)
        stmg    %r0,%r7,__PT_R0(%r11)
        mvc     __PT_R8(64,%r11),__LC_SAVE_AREA_SYNC
        stmg    %r8,%r9,__PT_PSW(%r11)
+       mvc     __PT_INT_CODE(4,%r11),__LC_PGM_ILC
+       mvc     __PT_INT_PARM_LONG(8,%r11),__LC_TRANS_EXC_CODE
        stg     %r10,__PT_ARGS(%r11)
        tm      __LC_PGM_ILC+3,0x80     # check for per exception
        jz      0f
@@ -421,15 +422,13 @@ ENTRY(pgm_check_handler)
        mvc     __THREAD_per_address(8,%r1),__LC_PER_ADDRESS
        mvc     __THREAD_per_cause(2,%r1),__LC_PER_CAUSE
        mvc     __THREAD_per_paid(1,%r1),__LC_PER_PAID
-0:     lgf     %r3,__LC_PGM_ILC        # load program interruption code
-       lg      %r4,__LC_TRANS_EXC_CODE
-       REENABLE_IRQS
+0:     REENABLE_IRQS
        xc      __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
-       lghi    %r10,0x7f
-       ngr     %r10,%r3
-       je      sysc_return
-       sll     %r10,3
        larl    %r1,pgm_check_table
+       llgh    %r10,__PT_INT_CODE+2(%r11)
+       nill    %r10,0x007f
+       sll     %r10,3
+       je      sysc_return
        lg      %r1,0(%r10,%r1)         # load address of handler routine
        lgr     %r2,%r11                # pass pointer to pt_regs
        basr    %r14,%r1                # branch to interrupt-handler
@@ -877,7 +876,7 @@ cleanup_system_call:
        mvc     __PT_R8(64,%r15),__LC_SAVE_AREA_SYNC
        stmg    %r0,%r7,__PT_R0(%r15)
        mvc     __PT_PSW(16,%r15),__LC_SVC_OLD_PSW
-       mvc     __PT_SVC_CODE(4,%r15),__LC_SVC_ILC
+       mvc     __PT_INT_CODE(4,%r15),__LC_SVC_ILC
        # setup saved register r15
        aghi    %r15,-STACK_FRAME_OVERHEAD
        stg     %r15,56(%r11)           # r15 stack pointer
index 7f6f9f35454518f091e4fb86e3d39e46c8aaf391..a8ba840294ff0524c66262bc1f438a1ac995d7bc 100644 (file)
@@ -302,9 +302,13 @@ static int setup_frame(int sig, struct k_sigaction *ka,
 
        /* We forgot to include these in the sigcontext.
           To avoid breaking binary compatibility, they are passed as args. */
-       regs->gprs[4] = current->thread.trap_no;
-       regs->gprs[5] = current->thread.prot_addr;
-       regs->gprs[6] = task_thread_info(current)->last_break;
+       if (sig == SIGSEGV || sig == SIGBUS || sig == SIGILL ||
+           sig == SIGTRAP || sig == SIGFPE) {
+               /* set extra registers only for synchronous signals */
+               regs->gprs[4] = regs->int_code & 127;
+               regs->gprs[5] = regs->int_parm_long;
+               regs->gprs[6] = task_thread_info(current)->last_break;
+       }
 
        /* Place signal number on stack to allow backtrace from handler.  */
        if (__put_user(regs->gprs[2], (int __user *) &frame->signo))
@@ -434,13 +438,13 @@ void do_signal(struct pt_regs *regs)
         * call information.
         */
        current_thread_info()->system_call =
-               test_thread_flag(TIF_SYSCALL) ? regs->svc_code : 0;
+               test_thread_flag(TIF_SYSCALL) ? regs->int_code : 0;
        signr = get_signal_to_deliver(&info, &ka, regs, NULL);
 
        if (signr > 0) {
                /* Whee!  Actually deliver the signal.  */
                if (current_thread_info()->system_call) {
-                       regs->svc_code = current_thread_info()->system_call;
+                       regs->int_code = current_thread_info()->system_call;
                        /* Check for system call restarting. */
                        switch (regs->gprs[2]) {
                        case -ERESTART_RESTARTBLOCK:
@@ -457,7 +461,7 @@ void do_signal(struct pt_regs *regs)
                                regs->gprs[2] = regs->orig_gpr2;
                                regs->psw.addr =
                                        __rewind_psw(regs->psw,
-                                                    regs->svc_code >> 16);
+                                                    regs->int_code >> 16);
                                break;
                        }
                }
@@ -488,11 +492,11 @@ void do_signal(struct pt_regs *regs)
        /* No handlers present - check for system call restart */
        clear_thread_flag(TIF_SYSCALL);
        if (current_thread_info()->system_call) {
-               regs->svc_code = current_thread_info()->system_call;
+               regs->int_code = current_thread_info()->system_call;
                switch (regs->gprs[2]) {
                case -ERESTART_RESTARTBLOCK:
                        /* Restart with sys_restart_syscall */
-                       regs->svc_code = __NR_restart_syscall;
+                       regs->int_code = __NR_restart_syscall;
                /* fallthrough */
                case -ERESTARTNOHAND:
                case -ERESTARTSYS:
index a9807dd862765a92ae8c2f4a2addc46b67186336..dc6cc1b0ae6659de7166ce6f74c942b956fcb2e4 100644 (file)
@@ -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)
index a9d3583922eca0be654fd42b4bcf644339098f57..354dd39073efec6c1a1bf034ab63c4e82dcc824c 100644 (file)
@@ -125,8 +125,7 @@ static inline int user_space_fault(unsigned long trans_exc_code)
        return trans_exc_code != 3;
 }
 
-static inline void report_user_fault(struct pt_regs *regs, long int_code,
-                                    int signr, unsigned long address)
+static inline void report_user_fault(struct pt_regs *regs, long signr)
 {
        if ((task_pid_nr(current) > 1) && !show_unhandled_signals)
                return;
@@ -134,10 +133,12 @@ static inline void 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(KERN_ALERT "User process fault: interruption code 0x%X ",
+              regs->int_code);
        print_vma_addr(KERN_CONT "in ", regs->psw.addr & PSW_ADDR_INSN);
-       printk("\n");
-       printk("failing address: %lX\n", address);
+       printk(KERN_CONT "\n");
+       printk(KERN_ALERT "failing address: %lX\n",
+              regs->int_parm_long & __FAIL_ADDR_MASK);
        show_regs(regs);
 }
 
@@ -145,24 +146,18 @@ static inline void report_user_fault(struct pt_regs *regs, long int_code,
  * Send SIGSEGV to task.  This is an external routine
  * to keep the stack usage of do_page_fault small.
  */
-static noinline void do_sigsegv(struct pt_regs *regs, long int_code,
-                               int si_code, unsigned long trans_exc_code)
+static noinline void do_sigsegv(struct pt_regs *regs, int si_code)
 {
        struct siginfo si;
-       unsigned long address;
 
-       address = trans_exc_code & __FAIL_ADDR_MASK;
-       current->thread.prot_addr = address;
-       current->thread.trap_no = int_code;
-       report_user_fault(regs, int_code, SIGSEGV, address);
+       report_user_fault(regs, SIGSEGV);
        si.si_signo = SIGSEGV;
        si.si_code = si_code;
-       si.si_addr = (void __user *) address;
+       si.si_addr = (void __user *)(regs->int_parm_long & __FAIL_ADDR_MASK);
        force_sig_info(SIGSEGV, &si, current);
 }
 
-static noinline void do_no_context(struct pt_regs *regs, long int_code,
-                                  unsigned long trans_exc_code)
+static noinline void do_no_context(struct pt_regs *regs)
 {
        const struct exception_table_entry *fixup;
        unsigned long address;
@@ -178,55 +173,48 @@ static noinline void do_no_context(struct pt_regs *regs, long int_code,
         * Oops. The kernel tried to access some bad page. We'll have to
         * terminate things with extreme prejudice.
         */
-       address = trans_exc_code & __FAIL_ADDR_MASK;
-       if (!user_space_fault(trans_exc_code))
+       address = regs->int_parm_long & __FAIL_ADDR_MASK;
+       if (!user_space_fault(regs->int_parm_long))
                printk(KERN_ALERT "Unable to handle kernel pointer dereference"
                       " at virtual kernel address %p\n", (void *)address);
        else
                printk(KERN_ALERT "Unable to handle kernel paging request"
                       " at virtual user address %p\n", (void *)address);
 
-       die("Oops", regs, int_code);
+       die(regs, "Oops");
        do_exit(SIGKILL);
 }
 
-static noinline void do_low_address(struct pt_regs *regs, long int_code,
-                                   unsigned long trans_exc_code)
+static noinline void do_low_address(struct pt_regs *regs)
 {
        /* Low-address protection hit in kernel mode means
           NULL pointer write access in kernel mode.  */
        if (regs->psw.mask & PSW_MASK_PSTATE) {
                /* Low-address protection hit in user mode 'cannot happen'. */
-               die ("Low-address protection", regs, int_code);
+               die (regs, "Low-address protection");
                do_exit(SIGKILL);
        }
 
-       do_no_context(regs, int_code, trans_exc_code);
+       do_no_context(regs);
 }
 
-static noinline void do_sigbus(struct pt_regs *regs, long int_code,
-                              unsigned long trans_exc_code)
+static noinline void do_sigbus(struct pt_regs *regs)
 {
        struct task_struct *tsk = current;
-       unsigned long address;
        struct siginfo si;
 
        /*
         * Send a sigbus, regardless of whether we were in kernel
         * or user mode.
         */
-       address = trans_exc_code & __FAIL_ADDR_MASK;
-       tsk->thread.prot_addr = address;
-       tsk->thread.trap_no = int_code;
        si.si_signo = SIGBUS;
        si.si_errno = 0;
        si.si_code = BUS_ADRERR;
-       si.si_addr = (void __user *) address;
+       si.si_addr = (void __user *)(regs->int_parm_long & __FAIL_ADDR_MASK);
        force_sig_info(SIGBUS, &si, tsk);
 }
 
-static noinline void do_fault_error(struct pt_regs *regs, long int_code,
-                                   unsigned long trans_exc_code, int fault)
+static noinline void do_fault_error(struct pt_regs *regs, int fault)
 {
        int si_code;
 
@@ -238,24 +226,24 @@ static noinline void do_fault_error(struct pt_regs *regs, long int_code,
                        /* User mode accesses just cause a SIGSEGV */
                        si_code = (fault == VM_FAULT_BADMAP) ?
                                SEGV_MAPERR : SEGV_ACCERR;
-                       do_sigsegv(regs, int_code, si_code, trans_exc_code);
+                       do_sigsegv(regs, si_code);
                        return;
                }
        case VM_FAULT_BADCONTEXT:
-               do_no_context(regs, int_code, trans_exc_code);
+               do_no_context(regs);
                break;
        default: /* fault & VM_FAULT_ERROR */
                if (fault & VM_FAULT_OOM) {
                        if (!(regs->psw.mask & PSW_MASK_PSTATE))
-                               do_no_context(regs, int_code, trans_exc_code);
+                               do_no_context(regs);
                        else
                                pagefault_out_of_memory();
                } else if (fault & VM_FAULT_SIGBUS) {
                        /* Kernel mode? Handle exceptions or die */
                        if (!(regs->psw.mask & PSW_MASK_PSTATE))
-                               do_no_context(regs, int_code, trans_exc_code);
+                               do_no_context(regs);
                        else
-                               do_sigbus(regs, int_code, trans_exc_code);
+                               do_sigbus(regs);
                } else
                        BUG();
                break;
@@ -273,12 +261,12 @@ static noinline void do_fault_error(struct pt_regs *regs, long int_code,
  *   11       Page translation     ->  Not present       (nullification)
  *   3b       Region third trans.  ->  Not present       (nullification)
  */
-static inline int do_exception(struct pt_regs *regs, int access,
-                              unsigned long trans_exc_code)
+static inline int do_exception(struct pt_regs *regs, int access)
 {
        struct task_struct *tsk;
        struct mm_struct *mm;
        struct vm_area_struct *vma;
+       unsigned long trans_exc_code;
        unsigned long address;
        unsigned int flags;
        int fault;
@@ -288,6 +276,7 @@ static inline int do_exception(struct pt_regs *regs, int access,
 
        tsk = current;
        mm = tsk->mm;
+       trans_exc_code = regs->int_parm_long;
 
        /*
         * Verify that the fault happened in user space, that
@@ -387,45 +376,46 @@ out:
        return fault;
 }
 
-void __kprobes do_protection_exception(struct pt_regs *regs, long pgm_int_code,
-                                      unsigned long trans_exc_code)
+void __kprobes do_protection_exception(struct pt_regs *regs)
 {
+       unsigned long trans_exc_code;
        int fault;
 
+       trans_exc_code = regs->int_parm_long;
        /* Protection exception is suppressing, decrement psw address. */
-       regs->psw.addr = __rewind_psw(regs->psw, pgm_int_code >> 16);
+       regs->psw.addr = __rewind_psw(regs->psw, regs->int_code >> 16);
        /*
         * Check for low-address protection.  This needs to be treated
         * as a special case because the translation exception code
         * field is not guaranteed to contain valid data in this case.
         */
        if (unlikely(!(trans_exc_code & 4))) {
-               do_low_address(regs, pgm_int_code, trans_exc_code);
+               do_low_address(regs);
                return;
        }
-       fault = do_exception(regs, VM_WRITE, trans_exc_code);
+       fault = do_exception(regs, VM_WRITE);
        if (unlikely(fault))
-               do_fault_error(regs, 4, trans_exc_code, fault);
+               do_fault_error(regs, fault);
 }
 
-void __kprobes do_dat_exception(struct pt_regs *regs, long pgm_int_code,
-                               unsigned long trans_exc_code)
+void __kprobes do_dat_exception(struct pt_regs *regs)
 {
        int access, fault;
 
        access = VM_READ | VM_EXEC | VM_WRITE;
-       fault = do_exception(regs, access, trans_exc_code);
+       fault = do_exception(regs, access);
        if (unlikely(fault))
-               do_fault_error(regs, pgm_int_code & 255, trans_exc_code, fault);
+               do_fault_error(regs, fault);
 }
 
 #ifdef CONFIG_64BIT
-void __kprobes do_asce_exception(struct pt_regs *regs, long pgm_int_code,
-                                unsigned long trans_exc_code)
+void __kprobes do_asce_exception(struct pt_regs *regs)
 {
        struct mm_struct *mm = current->mm;
        struct vm_area_struct *vma;
+       unsigned long trans_exc_code;
 
+       trans_exc_code = regs->int_parm_long;
        if (unlikely(!user_space_fault(trans_exc_code) || in_atomic() || !mm))
                goto no_context;
 
@@ -440,12 +430,12 @@ void __kprobes do_asce_exception(struct pt_regs *regs, long pgm_int_code,
 
        /* User mode accesses just cause a SIGSEGV */
        if (regs->psw.mask & PSW_MASK_PSTATE) {
-               do_sigsegv(regs, pgm_int_code, SEGV_MAPERR, trans_exc_code);
+               do_sigsegv(regs, SEGV_MAPERR);
                return;
        }
 
 no_context:
-       do_no_context(regs, pgm_int_code, trans_exc_code);
+       do_no_context(regs);
 }
 #endif
 
@@ -459,14 +449,15 @@ int __handle_fault(unsigned long uaddr, unsigned long pgm_int_code, int write)
                regs.psw.mask |= PSW_MASK_IO | PSW_MASK_EXT;
        regs.psw.addr = (unsigned long) __builtin_return_address(0);
        regs.psw.addr |= PSW_ADDR_AMODE;
-       uaddr &= PAGE_MASK;
+       regs.int_code = pgm_int_code;
+       regs.int_parm_long = (uaddr & PAGE_MASK) | 2;
        access = write ? VM_WRITE : VM_READ;
-       fault = do_exception(&regs, access, uaddr | 2);
+       fault = do_exception(&regs, access);
        if (unlikely(fault)) {
                if (fault & VM_FAULT_OOM)
                        return -EFAULT;
                else if (fault & VM_FAULT_SIGBUS)
-                       do_sigbus(&regs, pgm_int_code, uaddr);
+                       do_sigbus(&regs);
        }
        return fault ? -EFAULT : 0;
 }
This page took 0.042561 seconds and 5 git commands to generate.