X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fs390%2Fkernel%2Ftraps.c;h=bde1d1d598586cc483bcb84ca0211008d3a70711;hb=a030541d6dd71712d1989c26d9e63a698c64d5d8;hp=e67ee2702eb430a62382a52030a83b86450744a8;hpb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;p=linux-2.6.git diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index e67ee2702..bde1d1d59 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c @@ -14,7 +14,6 @@ * 'Traps.c' handles hardware traps and faults after we have saved some * state in 'asm.s'. */ -#include #include #include #include @@ -29,6 +28,7 @@ #include #include #include +#include #include #include @@ -38,6 +38,7 @@ #include #include #include +#include /* Called from entry.S only */ extern void handle_per_exception(struct pt_regs *regs); @@ -55,7 +56,6 @@ int sysctl_userprocess_debug = 0; extern pgm_check_handler_t do_protection_exception; extern pgm_check_handler_t do_dat_exception; -extern pgm_check_handler_t do_pseudo_page_fault; #ifdef CONFIG_PFAULT extern int pfault_init(void); extern void pfault_fini(void); @@ -66,13 +66,13 @@ extern pgm_check_handler_t do_monitor_call; #define stack_pointer ({ void **sp; asm("la %0,0(15)" : "=&d" (sp)); sp; }) -#ifndef CONFIG_ARCH_S390X +#ifndef CONFIG_64BIT #define FOURLONG "%08lx %08lx %08lx %08lx\n" static int kstack_depth_to_print = 12; -#else /* CONFIG_ARCH_S390X */ +#else /* CONFIG_64BIT */ #define FOURLONG "%016lx %016lx %016lx %016lx\n" static int kstack_depth_to_print = 20; -#endif /* CONFIG_ARCH_S390X */ +#endif /* CONFIG_64BIT */ /* * For show_trace we have tree different stack to consider: @@ -135,8 +135,8 @@ void show_trace(struct task_struct *task, unsigned long * stack) sp = __show_trace(sp, S390_lowcore.async_stack - ASYNC_SIZE, S390_lowcore.async_stack); if (task) - __show_trace(sp, (unsigned long) task->thread_info, - (unsigned long) task->thread_info + THREAD_SIZE); + __show_trace(sp, (unsigned long) task_stack_page(task), + (unsigned long) task_stack_page(task) + THREAD_SIZE); else __show_trace(sp, S390_lowcore.thread_info, S390_lowcore.thread_info + THREAD_SIZE); @@ -149,13 +149,11 @@ void show_stack(struct task_struct *task, unsigned long *sp) unsigned long *stack; int i; - // debugging aid: "show_stack(NULL);" prints the - // back trace for this cpu. - if (!sp) - sp = task ? (unsigned long *) task->thread.ksp : __r15; + stack = task ? (unsigned long *) task->thread.ksp : __r15; + else + stack = sp; - stack = sp; for (i = 0; i < kstack_depth_to_print; i++) { if (((addr_t) stack & (THREAD_SIZE-1)) == 0) break; @@ -172,7 +170,7 @@ void show_stack(struct task_struct *task, unsigned long *sp) */ void dump_stack(void) { - show_stack(0, 0); + show_stack(NULL, NULL); } EXPORT_SYMBOL(dump_stack); @@ -239,7 +237,7 @@ char *task_show_regs(struct task_struct *task, char *buffer) { struct pt_regs *regs; - regs = __KSTK_PTREGS(task); + regs = task_pt_regs(task); buffer += sprintf(buffer, "task: %p, ksp: %p\n", task, (void *)task->thread.ksp); buffer += sprintf(buffer, "User PSW : %p %p\n", @@ -272,13 +270,15 @@ char *task_show_regs(struct task_struct *task, char *buffer) return buffer; } -spinlock_t die_lock = SPIN_LOCK_UNLOCKED; +DEFINE_SPINLOCK(die_lock); void die(const char * str, struct pt_regs * regs, long err) { static int die_counter; - console_verbose(); - spin_lock_irq(&die_lock); + + debug_stop_all(); + console_verbose(); + spin_lock_irq(&die_lock); bust_spinlocks(1); printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter); show_regs(regs); @@ -291,6 +291,20 @@ void die(const char * str, struct pt_regs * regs, long err) do_exit(SIGSEGV); } +static void inline +report_user_fault(long interruption_code, struct pt_regs *regs) +{ +#if defined(CONFIG_SYSCTL) + if (!sysctl_userprocess_debug) + return; +#endif +#if defined(CONFIG_SYSCTL) || defined(CONFIG_PROCESS_DEBUG) + printk("User process fault: interruption code 0x%lX\n", + interruption_code); + show_regs(regs); +#endif +} + static void inline do_trap(long interruption_code, int signr, char *str, struct pt_regs *regs, siginfo_t *info) { @@ -305,23 +319,8 @@ static void inline do_trap(long interruption_code, int signr, char *str, struct task_struct *tsk = current; tsk->thread.trap_no = interruption_code & 0xffff; - if (info) - force_sig_info(signr, info, tsk); - else - force_sig(signr, tsk); -#ifndef CONFIG_SYSCTL -#ifdef CONFIG_PROCESS_DEBUG - printk("User process fault: interruption code 0x%lX\n", - interruption_code); - show_regs(regs); -#endif -#else - if (sysctl_userprocess_debug) { - printk("User process fault: interruption code 0x%lX\n", - interruption_code); - show_regs(regs); - } -#endif + force_sig_info(signr, info, tsk); + report_user_fault(interruption_code, regs); } else { const struct exception_table_entry *fixup; fixup = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN); @@ -332,9 +331,9 @@ static void inline do_trap(long interruption_code, int signr, char *str, } } -static inline void *get_check_address(struct pt_regs *regs) +static inline void __user *get_check_address(struct pt_regs *regs) { - return (void *)((regs->psw.addr-S390_lowcore.pgm_ilc) & PSW_ADDR_INSN); + return (void __user *)((regs->psw.addr-S390_lowcore.pgm_ilc) & PSW_ADDR_INSN); } void do_single_step(struct pt_regs *regs) @@ -343,10 +342,15 @@ void do_single_step(struct pt_regs *regs) force_sig(SIGTRAP, current); } -#define DO_ERROR(signr, str, name) \ -asmlinkage void name(struct pt_regs * regs, long interruption_code) \ -{ \ - do_trap(interruption_code, signr, str, regs, NULL); \ +asmlinkage void +default_trap_handler(struct pt_regs * regs, long interruption_code) +{ + if (regs->psw.mask & PSW_MASK_PSTATE) { + local_irq_enable(); + do_exit(SIGSEGV); + report_user_fault(interruption_code, regs); + } else + die("Unknown program exception", regs, interruption_code); } #define DO_ERROR_INFO(signr, str, name, sicode, siaddr) \ @@ -356,12 +360,10 @@ asmlinkage void name(struct pt_regs * regs, long interruption_code) \ info.si_signo = signr; \ info.si_errno = 0; \ info.si_code = sicode; \ - info.si_addr = (void *)siaddr; \ + info.si_addr = siaddr; \ do_trap(interruption_code, signr, str, regs, &info); \ } -DO_ERROR(SIGSEGV, "Unknown program exception", default_trap_handler) - DO_ERROR_INFO(SIGILL, "addressing exception", addressing_exception, ILL_ILLADR, get_check_address(regs)) DO_ERROR_INFO(SIGILL, "execute exception", execute_exception, @@ -390,7 +392,7 @@ DO_ERROR_INFO(SIGILL, "translation exception", translation_exception, ILL_ILLOPN, get_check_address(regs)) static inline void -do_fp_trap(struct pt_regs *regs, void *location, +do_fp_trap(struct pt_regs *regs, void __user *location, int fpc, long interruption_code) { siginfo_t si; @@ -420,11 +422,12 @@ do_fp_trap(struct pt_regs *regs, void *location, asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code) { + siginfo_t info; __u8 opcode[6]; - __u16 *location; + __u16 __user *location; int signal = 0; - location = (__u16 *) get_check_address(regs); + location = get_check_address(regs); /* * We got all needed information from the lowcore and can @@ -463,12 +466,27 @@ asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code) } else signal = SIGILL; +#ifdef CONFIG_MATHEMU if (signal == SIGFPE) do_fp_trap(regs, location, current->thread.fp_regs.fpc, interruption_code); - else if (signal) + else if (signal == SIGSEGV) { + info.si_signo = signal; + info.si_errno = 0; + info.si_code = SEGV_MAPERR; + info.si_addr = (void *) location; do_trap(interruption_code, signal, - "illegal operation", regs, NULL); + "user address fault", regs, &info); + } 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(interruption_code, signal, + "illegal operation", regs, &info); + } } @@ -541,10 +559,10 @@ DO_ERROR_INFO(SIGILL, "specification exception", specification_exception, asmlinkage void data_exception(struct pt_regs * regs, long interruption_code) { - __u16 *location; + __u16 __user *location; int signal = 0; - location = (__u16 *) get_check_address(regs); + location = get_check_address(regs); /* * We got all needed information from the lowcore and can @@ -630,13 +648,30 @@ asmlinkage void data_exception(struct pt_regs * regs, long interruption_code) } } +asmlinkage void space_switch_exception(struct pt_regs * regs, long int_code) +{ + 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_check_address(regs); + do_trap(int_code, SIGILL, "space switch event", regs, &info); +} + asmlinkage void kernel_stack_overflow(struct pt_regs * regs) { - die("Kernel stack overflow", regs, 0); + bust_spinlocks(1); + printk("Kernel stack overflow.\n"); + show_regs(regs); + bust_spinlocks(0); panic("Corrupt kernel stack, can't continue."); } - /* init is done in lowcore.S and head.S */ void __init trap_init(void) @@ -664,26 +699,22 @@ void __init trap_init(void) pgm_check_table[0x11] = &do_dat_exception; pgm_check_table[0x12] = &translation_exception; pgm_check_table[0x13] = &special_op_exception; -#ifndef CONFIG_ARCH_S390X - pgm_check_table[0x14] = &do_pseudo_page_fault; -#else /* CONFIG_ARCH_S390X */ +#ifdef CONFIG_64BIT pgm_check_table[0x38] = &do_dat_exception; pgm_check_table[0x39] = &do_dat_exception; pgm_check_table[0x3A] = &do_dat_exception; pgm_check_table[0x3B] = &do_dat_exception; -#endif /* CONFIG_ARCH_S390X */ +#endif /* CONFIG_64BIT */ pgm_check_table[0x15] = &operand_exception; - pgm_check_table[0x1C] = &privileged_op; + pgm_check_table[0x1C] = &space_switch_exception; pgm_check_table[0x1D] = &hfp_sqrt_exception; pgm_check_table[0x40] = &do_monitor_call; if (MACHINE_IS_VM) { +#ifdef CONFIG_PFAULT /* - * First try to get pfault pseudo page faults going. - * If this isn't available turn on pagex page faults. + * Try to get pfault pseudo page faults going. */ -#ifdef CONFIG_PFAULT - /* request the 0x2603 external interrupt */ if (register_early_external_interrupt(0x2603, pfault_interrupt, &ext_int_pfault) != 0) panic("Couldn't request external interrupt 0x2603"); @@ -694,9 +725,6 @@ void __init trap_init(void) /* Tough luck, no pfault. */ unregister_early_external_interrupt(0x2603, pfault_interrupt, &ext_int_pfault); -#endif -#ifndef CONFIG_ARCH_S390X - cpcmd("SET PAGEX ON", NULL, 0); #endif } }