diff options
author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2010-10-25 18:10:37 +0400 |
---|---|---|
committer | Martin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com> | 2010-10-25 18:10:19 +0400 |
commit | 1e54622e0403891b10f2105663e0f9dd595a1f17 (patch) | |
tree | 4d16341d7a3d0f3c46fcc275560a9206bccac07f /arch | |
parent | 84afdcee620b1640f2a145c07febae4ed68947f9 (diff) | |
download | linux-1e54622e0403891b10f2105663e0f9dd595a1f17.tar.xz |
[S390] cleanup lowcore access from program checks
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>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/s390/kernel/asm-offsets.c | 1 | ||||
-rw-r--r-- | arch/s390/kernel/entry.S | 35 | ||||
-rw-r--r-- | arch/s390/kernel/entry.h | 2 | ||||
-rw-r--r-- | arch/s390/kernel/entry64.S | 36 | ||||
-rw-r--r-- | arch/s390/kernel/traps.c | 172 | ||||
-rw-r--r-- | arch/s390/mm/fault.c | 36 |
6 files changed, 110 insertions, 172 deletions
diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c index 5232278d79ad..76328deb31f7 100644 --- a/arch/s390/kernel/asm-offsets.c +++ b/arch/s390/kernel/asm-offsets.c @@ -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)); diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index bea9ee37ac9d..adf25246f72e 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -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) diff --git a/arch/s390/kernel/entry.h b/arch/s390/kernel/entry.h index ff579b6bde06..714ff2e57c6b 100644 --- a/arch/s390/kernel/entry.h +++ b/arch/s390/kernel/entry.h @@ -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; diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S index 8bccec15ea90..2d205e4e7bb6 100644 --- a/arch/s390/kernel/entry64.S +++ b/arch/s390/kernel/entry64.S @@ -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 diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index 5d8f0f3d0250..e9b063e7d75f 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c @@ -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) diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index bae2c282221c..b6570069b127 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -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(®s, 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(®s, int_code, uaddr); + do_sigbus(®s, pgm_int_code, uaddr); } return fault ? -EFAULT : 0; } |