[S390] cleanup lowcore access from program checks
Martin Schwidefsky [Mon, 25 Oct 2010 14:10:37 +0000 (16:10 +0200)]
Read all required fields for program checks from the lowcore in the
first level interrupt handler in entry[64].S. If the context that
caused the fault was enabled for interrupts we can now re-enable the
irqs in entry[64].S.

Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

arch/s390/kernel/asm-offsets.c
arch/s390/kernel/entry.S
arch/s390/kernel/entry.h
arch/s390/kernel/entry64.S
arch/s390/kernel/traps.c
arch/s390/mm/fault.c

index 5232278..76328de 100644 (file)
@@ -84,6 +84,7 @@ int main(void)
        DEFINE(__LC_SVC_INT_CODE, offsetof(struct _lowcore, svc_code));
        DEFINE(__LC_PGM_ILC, offsetof(struct _lowcore, pgm_ilc));
        DEFINE(__LC_PGM_INT_CODE, offsetof(struct _lowcore, pgm_code));
+       DEFINE(__LC_TRANS_EXC_CODE, offsetof(struct _lowcore, trans_exc_code));
        DEFINE(__LC_PER_ATMID, offsetof(struct _lowcore, per_perc_atmid));
        DEFINE(__LC_PER_ADDRESS, offsetof(struct _lowcore, per_address));
        DEFINE(__LC_PER_ACCESS_ID, offsetof(struct _lowcore, per_access_id));
index bea9ee3..adf2524 100644 (file)
@@ -72,25 +72,9 @@ STACK_SIZE  = 1 << STACK_SHIFT
        l       %r1,BASED(.Ltrace_irq_off_caller)
        basr    %r14,%r1
        .endm
-
-       .macro  TRACE_IRQS_CHECK_ON
-       tm      SP_PSW(%r15),0x03       # irqs enabled?
-       bz      BASED(0f)
-       TRACE_IRQS_ON
-0:
-       .endm
-
-       .macro  TRACE_IRQS_CHECK_OFF
-       tm      SP_PSW(%r15),0x03       # irqs enabled?
-       bz      BASED(0f)
-       TRACE_IRQS_OFF
-0:
-       .endm
 #else
 #define TRACE_IRQS_ON
 #define TRACE_IRQS_OFF
-#define TRACE_IRQS_CHECK_ON
-#define TRACE_IRQS_CHECK_OFF
 #endif
 
 #ifdef CONFIG_LOCKDEP
@@ -198,6 +182,12 @@ STACK_SIZE  = 1 << STACK_SHIFT
        lpsw    \psworg                 # back to caller
        .endm
 
+       .macro REENABLE_IRQS
+       mvc     __SF_EMPTY(1,%r15),SP_PSW(%r15)
+       ni      __SF_EMPTY(%r15),0xbf
+       ssm     __SF_EMPTY(%r15)
+       .endm
+
 /*
  * Scheduler resume function, called by switch_to
  *  gpr2 = (task_struct *) prev
@@ -440,13 +430,11 @@ kernel_execve:
        br      %r14
        # execve succeeded.
 0:     stnsm   __SF_EMPTY(%r15),0xfc   # disable interrupts
-       TRACE_IRQS_OFF
        l       %r15,__LC_KERNEL_STACK  # load ksp
        s       %r15,BASED(.Lc_spsize)  # make room for registers & psw
        l       %r9,__LC_THREAD_INFO
        mvc     SP_PTREGS(__PT_SIZE,%r15),0(%r12)       # copy pt_regs
        xc      __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15)
-       TRACE_IRQS_ON
        stosm   __SF_EMPTY(%r15),0x03   # reenable interrupts
        l       %r1,BASED(.Lexecve_tail)
        basr    %r14,%r1
@@ -483,9 +471,10 @@ pgm_check_handler:
        UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
        mvc     __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
 pgm_no_vtime:
-       TRACE_IRQS_CHECK_OFF
        l       %r9,__LC_THREAD_INFO    # load pointer to thread_info struct
        l       %r3,__LC_PGM_ILC        # load program interruption code
+       l       %r4,__LC_TRANS_EXC_CODE
+       REENABLE_IRQS
        la      %r8,0x7f
        nr      %r8,%r3
 pgm_do_call:
@@ -495,7 +484,6 @@ pgm_do_call:
        la      %r2,SP_PTREGS(%r15)     # address of register-save area
        basr    %r14,%r7                # branch to interrupt-handler
 pgm_exit:
-       TRACE_IRQS_CHECK_ON
        b       BASED(sysc_return)
 
 #
@@ -523,7 +511,6 @@ pgm_per_std:
        UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
        mvc     __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
 pgm_no_vtime2:
-       TRACE_IRQS_CHECK_OFF
        l       %r9,__LC_THREAD_INFO    # load pointer to thread_info struct
        l       %r1,__TI_task(%r9)
        tm      SP_PSW+1(%r15),0x01     # kernel per event ?
@@ -533,6 +520,8 @@ pgm_no_vtime2:
        mvc     __THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID
        oi      __TI_flags+3(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
        l       %r3,__LC_PGM_ILC        # load program interruption code
+       l       %r4,__LC_TRANS_EXC_CODE
+       REENABLE_IRQS
        la      %r8,0x7f
        nr      %r8,%r3                 # clear per-event-bit and ilc
        be      BASED(pgm_exit2)        # only per or per+check ?
@@ -542,8 +531,6 @@ pgm_no_vtime2:
        la      %r2,SP_PTREGS(%r15)     # address of register-save area
        basr    %r14,%r7                # branch to interrupt-handler
 pgm_exit2:
-       TRACE_IRQS_ON
-       stosm   __SF_EMPTY(%r15),0x03   # reenable interrupts
        b       BASED(sysc_return)
 
 #
@@ -557,13 +544,11 @@ pgm_svcper:
        mvc     __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
        lh      %r7,0x8a                # get svc number from lowcore
        l       %r9,__LC_THREAD_INFO    # load pointer to thread_info struct
-       TRACE_IRQS_OFF
        l       %r8,__TI_task(%r9)
        mvc     __THREAD_per+__PER_atmid(2,%r8),__LC_PER_ATMID
        mvc     __THREAD_per+__PER_address(4,%r8),__LC_PER_ADDRESS
        mvc     __THREAD_per+__PER_access_id(1,%r8),__LC_PER_ACCESS_ID
        oi      __TI_flags+3(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
-       TRACE_IRQS_ON
        stosm   __SF_EMPTY(%r15),0x03   # reenable interrupts
        lm      %r2,%r6,SP_R2(%r15)     # load svc arguments
        b       BASED(sysc_do_svc)
index ff579b6..714ff2e 100644 (file)
@@ -5,7 +5,7 @@
 #include <linux/signal.h>
 #include <asm/ptrace.h>
 
-typedef void pgm_check_handler_t(struct pt_regs *, long);
+typedef void pgm_check_handler_t(struct pt_regs *, long, unsigned long);
 extern pgm_check_handler_t *pgm_check_table[128];
 pgm_check_handler_t do_protection_exception;
 pgm_check_handler_t do_dat_exception;
index 8bccec1..2d205e4 100644 (file)
@@ -79,25 +79,9 @@ _TIF_SYSCALL = (_TIF_SYSCALL_TRACE>>8 | _TIF_SYSCALL_AUDIT>>8 | \
        basr    %r2,%r0
        brasl   %r14,trace_hardirqs_off_caller
        .endm
-
-       .macro TRACE_IRQS_CHECK_ON
-       tm      SP_PSW(%r15),0x03       # irqs enabled?
-       jz      0f
-       TRACE_IRQS_ON
-0:
-       .endm
-
-       .macro TRACE_IRQS_CHECK_OFF
-       tm      SP_PSW(%r15),0x03       # irqs enabled?
-       jz      0f
-       TRACE_IRQS_OFF
-0:
-       .endm
 #else
 #define TRACE_IRQS_ON
 #define TRACE_IRQS_OFF
-#define TRACE_IRQS_CHECK_ON
-#define TRACE_IRQS_CHECK_OFF
 #endif
 
 #ifdef CONFIG_LOCKDEP
@@ -207,6 +191,12 @@ _TIF_SYSCALL = (_TIF_SYSCALL_TRACE>>8 | _TIF_SYSCALL_AUDIT>>8 | \
 0:
        .endm
 
+       .macro REENABLE_IRQS
+       mvc     __SF_EMPTY(1,%r15),SP_PSW(%r15)
+       ni      __SF_EMPTY(%r15),0xbf
+       ssm     __SF_EMPTY(%r15)
+       .endm
+
 /*
  * Scheduler resume function, called by switch_to
  *  gpr2 = (task_struct *) prev
@@ -443,14 +433,12 @@ kernel_execve:
        br      %r14
        # execve succeeded.
 0:     stnsm   __SF_EMPTY(%r15),0xfc   # disable interrupts
-#      TRACE_IRQS_OFF
        lg      %r15,__LC_KERNEL_STACK  # load ksp
        aghi    %r15,-SP_SIZE           # make room for registers & psw
        lg      %r13,__LC_SVC_NEW_PSW+8
        mvc     SP_PTREGS(__PT_SIZE,%r15),0(%r12)       # copy pt_regs
        lg      %r12,__LC_THREAD_INFO
        xc      __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
-#      TRACE_IRQS_ON
        stosm   __SF_EMPTY(%r15),0x03   # reenable interrupts
        brasl   %r14,execve_tail
        j       sysc_return
@@ -490,19 +478,18 @@ pgm_check_handler:
        LAST_BREAK
 pgm_no_vtime:
        HANDLE_SIE_INTERCEPT
-       TRACE_IRQS_CHECK_OFF
        stg     %r11,SP_ARGS(%r15)
        lgf     %r3,__LC_PGM_ILC        # load program interruption code
+       lg      %r4,__LC_TRANS_EXC_CODE
+       REENABLE_IRQS
        lghi    %r8,0x7f
        ngr     %r8,%r3
-pgm_do_call:
        sll     %r8,3
        larl    %r1,pgm_check_table
        lg      %r1,0(%r8,%r1)          # load address of handler routine
        la      %r2,SP_PTREGS(%r15)     # address of register-save area
        basr    %r14,%r1                # branch to interrupt-handler
 pgm_exit:
-       TRACE_IRQS_CHECK_ON
        j       sysc_return
 
 #
@@ -533,7 +520,6 @@ pgm_per_std:
        LAST_BREAK
 pgm_no_vtime2:
        HANDLE_SIE_INTERCEPT
-       TRACE_IRQS_CHECK_OFF
        lg      %r1,__TI_task(%r12)
        tm      SP_PSW+1(%r15),0x01     # kernel per event ?
        jz      kernel_per
@@ -542,6 +528,8 @@ pgm_no_vtime2:
        mvc     __THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID
        oi      __TI_flags+7(%r12),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
        lgf     %r3,__LC_PGM_ILC        # load program interruption code
+       lg      %r4,__LC_TRANS_EXC_CODE
+       REENABLE_IRQS
        lghi    %r8,0x7f
        ngr     %r8,%r3                 # clear per-event-bit and ilc
        je      pgm_exit2
@@ -551,8 +539,6 @@ pgm_no_vtime2:
        la      %r2,SP_PTREGS(%r15)     # address of register-save area
        basr    %r14,%r1                # branch to interrupt-handler
 pgm_exit2:
-       TRACE_IRQS_ON
-       stosm   __SF_EMPTY(%r15),0x03   # reenable interrupts
        j       sysc_return
 
 #
@@ -568,13 +554,11 @@ pgm_svcper:
        UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
        mvc     __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
        LAST_BREAK
-       TRACE_IRQS_OFF
        lg      %r8,__TI_task(%r12)
        mvc     __THREAD_per+__PER_atmid(2,%r8),__LC_PER_ATMID
        mvc     __THREAD_per+__PER_address(8,%r8),__LC_PER_ADDRESS
        mvc     __THREAD_per+__PER_access_id(1,%r8),__LC_PER_ACCESS_ID
        oi      __TI_flags+7(%r12),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
-       TRACE_IRQS_ON
        stosm   __SF_EMPTY(%r15),0x03   # reenable interrupts
        lmg     %r2,%r6,SP_R2(%r15)     # load svc arguments
        j       sysc_do_svc
index 5d8f0f3..e9b063e 100644 (file)
@@ -329,27 +329,19 @@ int is_valid_bugaddr(unsigned long addr)
        return 1;
 }
 
-static void __kprobes inline do_trap(long interruption_code, int signr,
-                                       char *str, struct pt_regs *regs,
-                                       siginfo_t *info)
+static inline void __kprobes do_trap(long pgm_int_code, int signr, char *str,
+                                    struct pt_regs *regs, siginfo_t *info)
 {
-       /*
-        * We got all needed information from the lowcore and can
-        * now safely switch on interrupts.
-        */
-        if (regs->psw.mask & PSW_MASK_PSTATE)
-               local_irq_enable();
-
-       if (notify_die(DIE_TRAP, str, regs, interruption_code,
-                               interruption_code, signr) == NOTIFY_STOP)
+       if (notify_die(DIE_TRAP, str, regs, pgm_int_code,
+                      pgm_int_code, signr) == NOTIFY_STOP)
                return;
 
         if (regs->psw.mask & PSW_MASK_PSTATE) {
                 struct task_struct *tsk = current;
 
-                tsk->thread.trap_no = interruption_code & 0xffff;
+               tsk->thread.trap_no = pgm_int_code & 0xffff;
                force_sig_info(signr, info, tsk);
-               report_user_fault(regs, interruption_code, signr);
+               report_user_fault(regs, pgm_int_code, signr);
         } else {
                 const struct exception_table_entry *fixup;
                 fixup = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN);
@@ -361,14 +353,16 @@ static void __kprobes inline do_trap(long interruption_code, int signr,
                        btt = report_bug(regs->psw.addr & PSW_ADDR_INSN, regs);
                        if (btt == BUG_TRAP_TYPE_WARN)
                                return;
-                       die(str, regs, interruption_code);
+                       die(str, regs, pgm_int_code);
                }
         }
 }
 
-static inline void __user *get_check_address(struct pt_regs *regs)
+static inline void __user *get_psw_address(struct pt_regs *regs,
+                                          long pgm_int_code)
 {
-       return (void __user *)((regs->psw.addr-S390_lowcore.pgm_ilc) & PSW_ADDR_INSN);
+       return (void __user *)
+               ((regs->psw.addr - (pgm_int_code >> 16)) & PSW_ADDR_INSN);
 }
 
 void __kprobes do_single_step(struct pt_regs *regs)
@@ -381,57 +375,57 @@ void __kprobes do_single_step(struct pt_regs *regs)
                force_sig(SIGTRAP, current);
 }
 
-static void default_trap_handler(struct pt_regs * regs, long interruption_code)
+static void default_trap_handler(struct pt_regs *regs, long pgm_int_code,
+                                unsigned long trans_exc_code)
 {
         if (regs->psw.mask & PSW_MASK_PSTATE) {
-               local_irq_enable();
-               report_user_fault(regs, interruption_code, SIGSEGV);
+               report_user_fault(regs, pgm_int_code, SIGSEGV);
                do_exit(SIGSEGV);
        } else
-               die("Unknown program exception", regs, interruption_code);
+               die("Unknown program exception", regs, pgm_int_code);
 }
 
-#define DO_ERROR_INFO(signr, str, name, sicode, siaddr) \
-static void name(struct pt_regs * regs, long interruption_code) \
+#define DO_ERROR_INFO(name, signr, sicode, str) \
+static void name(struct pt_regs *regs, long pgm_int_code, \
+                unsigned long trans_exc_code) \
 { \
         siginfo_t info; \
         info.si_signo = signr; \
         info.si_errno = 0; \
         info.si_code = sicode; \
-       info.si_addr = siaddr; \
-        do_trap(interruption_code, signr, str, regs, &info); \
+       info.si_addr = get_psw_address(regs, pgm_int_code); \
+       do_trap(pgm_int_code, signr, str, regs, &info);     \
 }
 
-DO_ERROR_INFO(SIGILL, "addressing exception", addressing_exception,
-             ILL_ILLADR, 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(SIGFPE,  "fixpoint overflow exception", overflow_exception,
-             FPE_INTOVF, get_check_address(regs))
-DO_ERROR_INFO(SIGFPE,  "HFP overflow exception", hfp_overflow_exception,
-             FPE_FLTOVF, get_check_address(regs))
-DO_ERROR_INFO(SIGFPE,  "HFP underflow exception", hfp_underflow_exception,
-             FPE_FLTUND, get_check_address(regs))
-DO_ERROR_INFO(SIGFPE,  "HFP significance exception", hfp_significance_exception,
-             FPE_FLTRES, get_check_address(regs))
-DO_ERROR_INFO(SIGFPE,  "HFP divide exception", hfp_divide_exception,
-             FPE_FLTDIV, get_check_address(regs))
-DO_ERROR_INFO(SIGFPE,  "HFP square root exception", hfp_sqrt_exception,
-             FPE_FLTINV, 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 __user *location,
-           int fpc, long interruption_code)
+DO_ERROR_INFO(addressing_exception, SIGILL, ILL_ILLADR,
+             "addressing exception")
+DO_ERROR_INFO(execute_exception, SIGILL, ILL_ILLOPN,
+             "execute exception")
+DO_ERROR_INFO(divide_exception, SIGFPE, FPE_INTDIV,
+             "fixpoint divide exception")
+DO_ERROR_INFO(overflow_exception, SIGFPE, FPE_INTOVF,
+             "fixpoint overflow exception")
+DO_ERROR_INFO(hfp_overflow_exception, SIGFPE, FPE_FLTOVF,
+             "HFP overflow exception")
+DO_ERROR_INFO(hfp_underflow_exception, SIGFPE, FPE_FLTUND,
+             "HFP underflow exception")
+DO_ERROR_INFO(hfp_significance_exception, SIGFPE, FPE_FLTRES,
+             "HFP significance exception")
+DO_ERROR_INFO(hfp_divide_exception, SIGFPE, FPE_FLTDIV,
+             "HFP divide exception")
+DO_ERROR_INFO(hfp_sqrt_exception, SIGFPE, FPE_FLTINV,
+             "HFP square root exception")
+DO_ERROR_INFO(operand_exception, SIGILL, ILL_ILLOPN,
+             "operand exception")
+DO_ERROR_INFO(privileged_op, SIGILL, ILL_PRVOPC,
+             "privileged operation")
+DO_ERROR_INFO(special_op_exception, SIGILL, ILL_ILLOPN,
+             "special operation exception")
+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)
 {
        siginfo_t si;
 
@@ -454,25 +448,19 @@ do_fp_trap(struct pt_regs *regs, void __user *location,
                        si.si_code = FPE_FLTRES;
        }
        current->thread.ieee_instruction_pointer = (addr_t) location;
-       do_trap(interruption_code, SIGFPE,
+       do_trap(pgm_int_code, SIGFPE,
                "floating point exception", regs, &si);
 }
 
-static void illegal_op(struct pt_regs * regs, long interruption_code)
+static void illegal_op(struct pt_regs *regs, long pgm_int_code,
+                      unsigned long trans_exc_code)
 {
        siginfo_t info;
         __u8 opcode[6];
        __u16 __user *location;
        int signal = 0;
 
-       location = get_check_address(regs);
-
-       /*
-        * We got all needed information from the lowcore and can
-        * now safely switch on interrupts.
-        */
-       if (regs->psw.mask & PSW_MASK_PSTATE)
-               local_irq_enable();
+       location = get_psw_address(regs, pgm_int_code);
 
        if (regs->psw.mask & PSW_MASK_PSTATE) {
                if (get_user(*((__u16 *) opcode), (__u16 __user *) location))
@@ -512,7 +500,7 @@ static void illegal_op(struct pt_regs * regs, long interruption_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, interruption_code,
+               if (notify_die(DIE_BPT, "bpt", regs, pgm_int_code,
                               3, SIGTRAP) != NOTIFY_STOP)
                        signal = SIGILL;
        }
@@ -520,13 +508,13 @@ static void illegal_op(struct pt_regs * regs, long interruption_code)
 #ifdef CONFIG_MATHEMU
         if (signal == SIGFPE)
                do_fp_trap(regs, location,
-                           current->thread.fp_regs.fpc, interruption_code);
+                          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(interruption_code, signal,
+               do_trap(pgm_int_code, signal,
                        "user address fault", regs, &info);
        } else
 #endif
@@ -535,28 +523,22 @@ static void illegal_op(struct pt_regs * regs, long interruption_code)
                info.si_errno = 0;
                info.si_code = ILL_ILLOPC;
                info.si_addr = (void __user *) location;
-               do_trap(interruption_code, signal,
+               do_trap(pgm_int_code, signal,
                        "illegal operation", regs, &info);
        }
 }
 
 
 #ifdef CONFIG_MATHEMU
-asmlinkage void 
-specification_exception(struct pt_regs * regs, long interruption_code)
+asmlinkage void specification_exception(struct pt_regs *regs,
+                                       long pgm_int_code,
+                                       unsigned long trans_exc_code)
 {
         __u8 opcode[6];
        __u16 __user *location = NULL;
        int signal = 0;
 
-       location = (__u16 __user *) get_check_address(regs);
-
-       /*
-        * We got all needed information from the lowcore and can
-        * now safely switch on interrupts.
-        */
-        if (regs->psw.mask & PSW_MASK_PSTATE)
-               local_irq_enable();
+       location = (__u16 __user *) get_psw_address(regs, pgm_int_code);
 
         if (regs->psw.mask & PSW_MASK_PSTATE) {
                get_user(*((__u16 *) opcode), location);
@@ -592,35 +574,29 @@ specification_exception(struct pt_regs * regs, long interruption_code)
 
         if (signal == SIGFPE)
                do_fp_trap(regs, location,
-                           current->thread.fp_regs.fpc, interruption_code);
+                          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(interruption_code, signal, 
+               do_trap(pgm_int_code, signal,
                        "specification exception", regs, &info);
        }
 }
 #else
-DO_ERROR_INFO(SIGILL, "specification exception", specification_exception,
-             ILL_ILLOPN, get_check_address(regs));
+DO_ERROR_INFO(specification_exception, SIGILL, ILL_ILLOPN,
+             "specification exception");
 #endif
 
-static void data_exception(struct pt_regs * regs, long interruption_code)
+static void data_exception(struct pt_regs *regs, long pgm_int_code,
+                          unsigned long trans_exc_code)
 {
        __u16 __user *location;
        int signal = 0;
 
-       location = get_check_address(regs);
-
-       /*
-        * We got all needed information from the lowcore and can
-        * now safely switch on interrupts.
-        */
-       if (regs->psw.mask & PSW_MASK_PSTATE)
-               local_irq_enable();
+       location = get_psw_address(regs, pgm_int_code);
 
        if (MACHINE_HAS_IEEE)
                asm volatile("stfpc %0" : "=m" (current->thread.fp_regs.fpc));
@@ -686,19 +662,19 @@ static void data_exception(struct pt_regs * regs, long interruption_code)
                signal = SIGILL;
         if (signal == SIGFPE)
                do_fp_trap(regs, location,
-                           current->thread.fp_regs.fpc, interruption_code);
+                          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(interruption_code, signal, 
-                       "data exception", regs, &info);
+               do_trap(pgm_int_code, signal, "data exception", regs, &info);
        }
 }
 
-static void space_switch_exception(struct pt_regs * regs, long int_code)
+static void space_switch_exception(struct pt_regs *regs, long pgm_int_code,
+                                  unsigned long trans_exc_code)
 {
         siginfo_t info;
 
@@ -709,8 +685,8 @@ static void space_switch_exception(struct pt_regs * regs, long int_code)
         info.si_signo = SIGILL;
         info.si_errno = 0;
         info.si_code = ILL_PRVOPC;
-        info.si_addr = get_check_address(regs);
-        do_trap(int_code, SIGILL, "space switch event", regs, &info);
+       info.si_addr = get_psw_address(regs, pgm_int_code);
+       do_trap(pgm_int_code, SIGILL, "space switch event", regs, &info);
 }
 
 asmlinkage void kernel_stack_overflow(struct pt_regs * regs)
index bae2c28..b657006 100644 (file)
@@ -333,12 +333,6 @@ static inline int do_exception(struct pt_regs *regs, int access,
                goto out;
 
        address = trans_exc_code & __FAIL_ADDR_MASK;
-       /*
-        * When we get here, the fault happened in the current
-        * task's user address space, so we can switch on the
-        * interrupts again and then search the VMAs
-        */
-       local_irq_enable();
        perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, 0, regs, address);
        down_read(&mm->mmap_sem);
 
@@ -397,20 +391,20 @@ out:
        return fault;
 }
 
-void __kprobes do_protection_exception(struct pt_regs *regs, long int_code)
+void __kprobes do_protection_exception(struct pt_regs *regs, long pgm_int_code,
+                                      unsigned long trans_exc_code)
 {
-       unsigned long trans_exc_code = S390_lowcore.trans_exc_code;
        int fault;
 
        /* Protection exception is supressing, decrement psw address. */
-       regs->psw.addr -= (int_code >> 16);
+       regs->psw.addr -= (pgm_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, int_code, trans_exc_code);
+               do_low_address(regs, pgm_int_code, trans_exc_code);
                return;
        }
        fault = do_exception(regs, VM_WRITE, trans_exc_code);
@@ -418,9 +412,9 @@ void __kprobes do_protection_exception(struct pt_regs *regs, long int_code)
                do_fault_error(regs, 4, trans_exc_code, fault);
 }
 
-void __kprobes do_dat_exception(struct pt_regs *regs, long int_code)
+void __kprobes do_dat_exception(struct pt_regs *regs, long pgm_int_code,
+                               unsigned long trans_exc_code)
 {
-       unsigned long trans_exc_code = S390_lowcore.trans_exc_code;
        int access, fault;
 
        access = VM_READ | VM_EXEC | VM_WRITE;
@@ -431,21 +425,19 @@ void __kprobes do_dat_exception(struct pt_regs *regs, long int_code)
 #endif
        fault = do_exception(regs, access, trans_exc_code);
        if (unlikely(fault))
-               do_fault_error(regs, int_code & 255, trans_exc_code, fault);
+               do_fault_error(regs, pgm_int_code & 255, trans_exc_code, fault);
 }
 
 #ifdef CONFIG_64BIT
-void __kprobes do_asce_exception(struct pt_regs *regs, long int_code)
+void __kprobes do_asce_exception(struct pt_regs *regs, long pgm_int_code,
+                                unsigned long trans_exc_code)
 {
-       unsigned long trans_exc_code = S390_lowcore.trans_exc_code;
        struct mm_struct *mm = current->mm;
        struct vm_area_struct *vma;
 
        if (unlikely(!user_space_fault(trans_exc_code) || in_atomic() || !mm))
                goto no_context;
 
-       local_irq_enable();
-
        down_read(&mm->mmap_sem);
        vma = find_vma(mm, trans_exc_code & __FAIL_ADDR_MASK);
        up_read(&mm->mmap_sem);
@@ -457,16 +449,16 @@ void __kprobes do_asce_exception(struct pt_regs *regs, long int_code)
 
        /* User mode accesses just cause a SIGSEGV */
        if (regs->psw.mask & PSW_MASK_PSTATE) {
-               do_sigsegv(regs, int_code, SEGV_MAPERR, trans_exc_code);
+               do_sigsegv(regs, pgm_int_code, SEGV_MAPERR, trans_exc_code);
                return;
        }
 
 no_context:
-       do_no_context(regs, int_code, trans_exc_code);
+       do_no_context(regs, pgm_int_code, trans_exc_code);
 }
 #endif
 
-int __handle_fault(unsigned long uaddr, unsigned long int_code, int write_user)
+int __handle_fault(unsigned long uaddr, unsigned long pgm_int_code, int write)
 {
        struct pt_regs regs;
        int access, fault;
@@ -477,14 +469,14 @@ int __handle_fault(unsigned long uaddr, unsigned long int_code, int write_user)
        regs.psw.addr = (unsigned long) __builtin_return_address(0);
        regs.psw.addr |= PSW_ADDR_AMODE;
        uaddr &= PAGE_MASK;
-       access = write_user ? VM_WRITE : VM_READ;
+       access = write ? VM_WRITE : VM_READ;
        fault = do_exception(&regs, access, uaddr | 2);
        if (unlikely(fault)) {
                if (fault & VM_FAULT_OOM) {
                        pagefault_out_of_memory();
                        fault = 0;
                } else if (fault & VM_FAULT_SIGBUS)
-                       do_sigbus(&regs, int_code, uaddr);
+                       do_sigbus(&regs, pgm_int_code, uaddr);
        }
        return fault ? -EFAULT : 0;
 }