diff options
Diffstat (limited to 'arch/sh/kernel')
24 files changed, 429 insertions, 692 deletions
diff --git a/arch/sh/kernel/cpu/sh3/serial-sh7720.c b/arch/sh/kernel/cpu/sh3/serial-sh7720.c index 8832c526cdf..c4a0336660d 100644 --- a/arch/sh/kernel/cpu/sh3/serial-sh7720.c +++ b/arch/sh/kernel/cpu/sh3/serial-sh7720.c @@ -2,7 +2,7 @@  #include <linux/serial_core.h>  #include <linux/io.h>  #include <cpu/serial.h> -#include <asm/gpio.h> +#include <cpu/gpio.h>  static void sh7720_sci_init_pins(struct uart_port *port, unsigned int cflag)  { diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7343.c b/arch/sh/kernel/cpu/sh4a/clock-sh7343.c index ea01a72f1b9..53638e231cd 100644 --- a/arch/sh/kernel/cpu/sh4a/clock-sh7343.c +++ b/arch/sh/kernel/cpu/sh4a/clock-sh7343.c @@ -283,7 +283,7 @@ int __init arch_clk_init(void)  		ret = sh_clk_div6_register(div6_clks, DIV6_NR);  	if (!ret) -		ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR); +		ret = sh_clk_mstp_register(mstp_clks, MSTP_NR);  	return ret;  } diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7366.c b/arch/sh/kernel/cpu/sh4a/clock-sh7366.c index 7ac07b4f75d..22e485d1990 100644 --- a/arch/sh/kernel/cpu/sh4a/clock-sh7366.c +++ b/arch/sh/kernel/cpu/sh4a/clock-sh7366.c @@ -276,7 +276,7 @@ int __init arch_clk_init(void)  		ret = sh_clk_div6_register(div6_clks, DIV6_NR);  	if (!ret) -		ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR); +		ret = sh_clk_mstp_register(mstp_clks, MSTP_NR);  	return ret;  } diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7722.c b/arch/sh/kernel/cpu/sh4a/clock-sh7722.c index 8e1f97010c0..c4cb740e4d1 100644 --- a/arch/sh/kernel/cpu/sh4a/clock-sh7722.c +++ b/arch/sh/kernel/cpu/sh4a/clock-sh7722.c @@ -261,7 +261,7 @@ int __init arch_clk_init(void)  		ret = sh_clk_div6_register(div6_clks, DIV6_NR);  	if (!ret) -		ret = sh_clk_mstp32_register(mstp_clks, HWBLK_NR); +		ret = sh_clk_mstp_register(mstp_clks, HWBLK_NR);  	return ret;  } diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7723.c b/arch/sh/kernel/cpu/sh4a/clock-sh7723.c index 35f75cf0c7e..37c41c7747a 100644 --- a/arch/sh/kernel/cpu/sh4a/clock-sh7723.c +++ b/arch/sh/kernel/cpu/sh4a/clock-sh7723.c @@ -311,7 +311,7 @@ int __init arch_clk_init(void)  		ret = sh_clk_div6_register(div6_clks, DIV6_NR);  	if (!ret) -		ret = sh_clk_mstp32_register(mstp_clks, HWBLK_NR); +		ret = sh_clk_mstp_register(mstp_clks, HWBLK_NR);  	return ret;  } diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7724.c b/arch/sh/kernel/cpu/sh4a/clock-sh7724.c index 2a87901673f..c87e78f7323 100644 --- a/arch/sh/kernel/cpu/sh4a/clock-sh7724.c +++ b/arch/sh/kernel/cpu/sh4a/clock-sh7724.c @@ -375,7 +375,7 @@ int __init arch_clk_init(void)  		ret = sh_clk_div6_reparent_register(div6_clks, DIV6_NR);  	if (!ret) -		ret = sh_clk_mstp32_register(mstp_clks, HWBLK_NR); +		ret = sh_clk_mstp_register(mstp_clks, HWBLK_NR);  	return ret;  } diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7734.c b/arch/sh/kernel/cpu/sh4a/clock-sh7734.c index 1697642c1f7..deb683abacf 100644 --- a/arch/sh/kernel/cpu/sh4a/clock-sh7734.c +++ b/arch/sh/kernel/cpu/sh4a/clock-sh7734.c @@ -260,7 +260,7 @@ int __init arch_clk_init(void)  			&div4_table);  	if (!ret) -		ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR); +		ret = sh_clk_mstp_register(mstp_clks, MSTP_NR);  	return ret;  } diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7757.c b/arch/sh/kernel/cpu/sh4a/clock-sh7757.c index 04ab5aeaf92..e84a43229b9 100644 --- a/arch/sh/kernel/cpu/sh4a/clock-sh7757.c +++ b/arch/sh/kernel/cpu/sh4a/clock-sh7757.c @@ -148,7 +148,7 @@ int __init arch_clk_init(void)  		ret = sh_clk_div4_register(div4_clks, ARRAY_SIZE(div4_clks),  					   &div4_table);  	if (!ret) -		ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR); +		ret = sh_clk_mstp_register(mstp_clks, MSTP_NR);  	return ret;  } diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7785.c b/arch/sh/kernel/cpu/sh4a/clock-sh7785.c index ab1c58f2d10..1c83788db76 100644 --- a/arch/sh/kernel/cpu/sh4a/clock-sh7785.c +++ b/arch/sh/kernel/cpu/sh4a/clock-sh7785.c @@ -175,7 +175,7 @@ int __init arch_clk_init(void)  		ret = sh_clk_div4_register(div4_clks, ARRAY_SIZE(div4_clks),  					   &div4_table);  	if (!ret) -		ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR); +		ret = sh_clk_mstp_register(mstp_clks, MSTP_NR);  	return ret;  } diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7786.c b/arch/sh/kernel/cpu/sh4a/clock-sh7786.c index 491709483e1..8bba6f15902 100644 --- a/arch/sh/kernel/cpu/sh4a/clock-sh7786.c +++ b/arch/sh/kernel/cpu/sh4a/clock-sh7786.c @@ -194,7 +194,7 @@ int __init arch_clk_init(void)  		ret = sh_clk_div4_register(div4_clks, ARRAY_SIZE(div4_clks),  					   &div4_table);  	if (!ret) -		ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR); +		ret = sh_clk_mstp_register(mstp_clks, MSTP_NR);  	return ret;  } diff --git a/arch/sh/kernel/cpu/sh4a/clock-shx3.c b/arch/sh/kernel/cpu/sh4a/clock-shx3.c index 0f11b392bf4..a9422dab0ce 100644 --- a/arch/sh/kernel/cpu/sh4a/clock-shx3.c +++ b/arch/sh/kernel/cpu/sh4a/clock-shx3.c @@ -149,7 +149,7 @@ int __init arch_clk_init(void)  		ret = sh_clk_div4_register(div4_clks, ARRAY_SIZE(div4_clks),  					   &div4_table);  	if (!ret) -		ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR); +		ret = sh_clk_mstp_register(mstp_clks, MSTP_NR);  	return ret;  } diff --git a/arch/sh/kernel/cpu/sh5/entry.S b/arch/sh/kernel/cpu/sh5/entry.S index ff1f0e6e9be..b7cf6a547f1 100644 --- a/arch/sh/kernel/cpu/sh5/entry.S +++ b/arch/sh/kernel/cpu/sh5/entry.S @@ -1569,86 +1569,6 @@ ___clear_user_exit:  #endif /* CONFIG_MMU */  /* - * int __strncpy_from_user(unsigned long __dest, unsigned long __src, - *			   int __count) - * - * Inputs: - * (r2)  target address - * (r3)  source address - * (r4)  maximum size in bytes - * - * Ouputs: - * (*r2) copied data - * (r2)  -EFAULT (in case of faulting) - *       copied data (otherwise) - */ -	.global	__strncpy_from_user -__strncpy_from_user: -	pta	___strncpy_from_user1, tr0 -	pta	___strncpy_from_user_done, tr1 -	or	r4, ZERO, r5		/* r5 = original count */ -	beq/u	r4, r63, tr1		/* early exit if r4==0 */ -	movi	-(EFAULT), r6		/* r6 = reply, no real fixup */ -	or	ZERO, ZERO, r7		/* r7 = data, clear top byte of data */ - -___strncpy_from_user1: -	ld.b	r3, 0, r7		/* Fault address: only in reading */ -	st.b	r2, 0, r7 -	addi	r2, 1, r2 -	addi	r3, 1, r3 -	beq/u	ZERO, r7, tr1 -	addi	r4, -1, r4		/* return real number of copied bytes */ -	bne/l	ZERO, r4, tr0 - -___strncpy_from_user_done: -	sub	r5, r4, r6		/* If done, return copied */ - -___strncpy_from_user_exit: -	or	r6, ZERO, r2 -	ptabs	LINK, tr0 -	blink	tr0, ZERO - -/* - * extern long __strnlen_user(const char *__s, long __n) - * - * Inputs: - * (r2)  source address - * (r3)  source size in bytes - * - * Ouputs: - * (r2)  -EFAULT (in case of faulting) - *       string length (otherwise) - */ -	.global	__strnlen_user -__strnlen_user: -	pta	___strnlen_user_set_reply, tr0 -	pta	___strnlen_user1, tr1 -	or	ZERO, ZERO, r5		/* r5 = counter */ -	movi	-(EFAULT), r6		/* r6 = reply, no real fixup */ -	or	ZERO, ZERO, r7		/* r7 = data, clear top byte of data */ -	beq	r3, ZERO, tr0 - -___strnlen_user1: -	ldx.b	r2, r5, r7		/* Fault address: only in reading */ -	addi	r3, -1, r3		/* No real fixup */ -	addi	r5, 1, r5 -	beq	r3, ZERO, tr0 -	bne	r7, ZERO, tr1 -! The line below used to be active.  This meant led to a junk byte lying between each pair -! of entries in the argv & envp structures in memory.  Whilst the program saw the right data -! via the argv and envp arguments to main, it meant the 'flat' representation visible through -! /proc/$pid/cmdline was corrupt, causing trouble with ps, for example. -!	addi	r5, 1, r5		/* Include '\0' */ - -___strnlen_user_set_reply: -	or	r5, ZERO, r6		/* If done, return counter */ - -___strnlen_user_exit: -	or	r6, ZERO, r2 -	ptabs	LINK, tr0 -	blink	tr0, ZERO - -/*   * extern long __get_user_asm_?(void *val, long addr)   *   * Inputs: @@ -1982,8 +1902,6 @@ asm_uaccess_start:  	.long	___copy_user2, ___copy_user_exit  	.long	___clear_user1, ___clear_user_exit  #endif -	.long	___strncpy_from_user1, ___strncpy_from_user_exit -	.long	___strnlen_user1, ___strnlen_user_exit  	.long	___get_user_asm_b1, ___get_user_asm_b_exit  	.long	___get_user_asm_w1, ___get_user_asm_w_exit  	.long	___get_user_asm_l1, ___get_user_asm_l_exit diff --git a/arch/sh/kernel/cpu/sh5/unwind.c b/arch/sh/kernel/cpu/sh5/unwind.c index b205b25eaf4..10aed41757f 100644 --- a/arch/sh/kernel/cpu/sh5/unwind.c +++ b/arch/sh/kernel/cpu/sh5/unwind.c @@ -16,6 +16,8 @@  #include <asm/ptrace.h>  #include <asm/processor.h>  #include <asm/io.h> +#include <asm/unwinder.h> +#include <asm/stacktrace.h>  static u8 regcache[63]; @@ -199,8 +201,11 @@ static int lookup_prev_stack_frame(unsigned long fp, unsigned long pc,  	return 0;  } -/* Don't put this on the stack since we'll want to call sh64_unwind - * when we're close to underflowing the stack anyway. */ +/* + * Don't put this on the stack since we'll want to call in to + * sh64_unwinder_dump() when we're close to underflowing the stack + * anyway. + */  static struct pt_regs here_regs;  extern const char syscall_ret; @@ -208,17 +213,19 @@ extern const char ret_from_syscall;  extern const char ret_from_exception;  extern const char ret_from_irq; -static void sh64_unwind_inner(struct pt_regs *regs); +static void sh64_unwind_inner(const struct stacktrace_ops *ops, +			      void *data, struct pt_regs *regs); -static void unwind_nested (unsigned long pc, unsigned long fp) +static inline void unwind_nested(const struct stacktrace_ops *ops, void *data, +				 unsigned long pc, unsigned long fp)  {  	if ((fp >= __MEMORY_START) && -	    ((fp & 7) == 0)) { -		sh64_unwind_inner((struct pt_regs *) fp); -	} +	    ((fp & 7) == 0)) +		sh64_unwind_inner(ops, data, (struct pt_regs *)fp);  } -static void sh64_unwind_inner(struct pt_regs *regs) +static void sh64_unwind_inner(const struct stacktrace_ops *ops, +			      void *data, struct pt_regs *regs)  {  	unsigned long pc, fp;  	int ofs = 0; @@ -232,29 +239,29 @@ static void sh64_unwind_inner(struct pt_regs *regs)  		int cond;  		unsigned long next_fp, next_pc; -		if (pc == ((unsigned long) &syscall_ret & ~1)) { +		if (pc == ((unsigned long)&syscall_ret & ~1)) {  			printk("SYSCALL\n"); -			unwind_nested(pc,fp); +			unwind_nested(ops, data, pc, fp);  			return;  		} -		if (pc == ((unsigned long) &ret_from_syscall & ~1)) { +		if (pc == ((unsigned long)&ret_from_syscall & ~1)) {  			printk("SYSCALL (PREEMPTED)\n"); -			unwind_nested(pc,fp); +			unwind_nested(ops, data, pc, fp);  			return;  		}  		/* In this case, the PC is discovered by lookup_prev_stack_frame but  		   it has 4 taken off it to look like the 'caller' */ -		if (pc == ((unsigned long) &ret_from_exception & ~1)) { +		if (pc == ((unsigned long)&ret_from_exception & ~1)) {  			printk("EXCEPTION\n"); -			unwind_nested(pc,fp); +			unwind_nested(ops, data, pc, fp);  			return;  		} -		if (pc == ((unsigned long) &ret_from_irq & ~1)) { +		if (pc == ((unsigned long)&ret_from_irq & ~1)) {  			printk("IRQ\n"); -			unwind_nested(pc,fp); +			unwind_nested(ops, data, pc, fp);  			return;  		} @@ -263,8 +270,7 @@ static void sh64_unwind_inner(struct pt_regs *regs)  		pc -= ofs; -		printk("[<%08lx>] ", pc); -		print_symbol("%s\n", pc); +		ops->address(data, pc, 1);  		if (first_pass) {  			/* If the innermost frame is a leaf function, it's @@ -287,10 +293,13 @@ static void sh64_unwind_inner(struct pt_regs *regs)  	}  	printk("\n"); -  } -void sh64_unwind(struct pt_regs *regs) +static void sh64_unwinder_dump(struct task_struct *task, +			       struct pt_regs *regs, +			       unsigned long *sp, +			       const struct stacktrace_ops *ops, +			       void *data)  {  	if (!regs) {  		/* @@ -320,7 +329,17 @@ void sh64_unwind(struct pt_regs *regs)  		);  	} -	printk("\nCall Trace:\n"); -	sh64_unwind_inner(regs); +	sh64_unwind_inner(ops, data, regs);  } +static struct unwinder sh64_unwinder = { +	.name	= "sh64-unwinder", +	.dump	= sh64_unwinder_dump, +	.rating	= 150, +}; + +static int __init sh64_unwinder_init(void) +{ +	return unwinder_register(&sh64_unwinder); +} +early_initcall(sh64_unwinder_init); diff --git a/arch/sh/kernel/dumpstack.c b/arch/sh/kernel/dumpstack.c index 694158b9a50..7617dc4129a 100644 --- a/arch/sh/kernel/dumpstack.c +++ b/arch/sh/kernel/dumpstack.c @@ -2,13 +2,48 @@   *  Copyright (C) 1991, 1992  Linus Torvalds   *  Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs   *  Copyright (C) 2009  Matt Fleming + *  Copyright (C) 2002 - 2012  Paul Mundt + * + * This file is subject to the terms and conditions of the GNU General Public + * License.  See the file "COPYING" in the main directory of this archive + * for more details.   */  #include <linux/kallsyms.h>  #include <linux/ftrace.h>  #include <linux/debug_locks.h> +#include <linux/kdebug.h> +#include <linux/export.h> +#include <linux/uaccess.h>  #include <asm/unwinder.h>  #include <asm/stacktrace.h> +void dump_mem(const char *str, unsigned long bottom, unsigned long top) +{ +	unsigned long p; +	int i; + +	printk("%s(0x%08lx to 0x%08lx)\n", str, bottom, top); + +	for (p = bottom & ~31; p < top; ) { +		printk("%04lx: ", p & 0xffff); + +		for (i = 0; i < 8; i++, p += 4) { +			unsigned int val; + +			if (p < bottom || p >= top) +				printk("         "); +			else { +				if (__get_user(val, (unsigned int __user *)p)) { +					printk("\n"); +					return; +				} +				printk("%08x ", val); +			} +		} +		printk("\n"); +	} +} +  void printk_address(unsigned long address, int reliable)  {  	printk(" [<%p>] %s%pS\n", (void *) address, @@ -106,3 +141,26 @@ void show_trace(struct task_struct *tsk, unsigned long *sp,  	debug_show_held_locks(tsk);  } + +void show_stack(struct task_struct *tsk, unsigned long *sp) +{ +	unsigned long stack; + +	if (!tsk) +		tsk = current; +	if (tsk == current) +		sp = (unsigned long *)current_stack_pointer; +	else +		sp = (unsigned long *)tsk->thread.sp; + +	stack = (unsigned long)sp; +	dump_mem("Stack: ", stack, THREAD_SIZE + +		 (unsigned long)task_stack_page(tsk)); +	show_trace(tsk, sp, NULL); +} + +void dump_stack(void) +{ +	show_stack(NULL, NULL); +} +EXPORT_SYMBOL(dump_stack); diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c index dadce735f74..063af10ff3c 100644 --- a/arch/sh/kernel/irq.c +++ b/arch/sh/kernel/irq.c @@ -231,16 +231,6 @@ void __init init_IRQ(void)  	irq_ctx_init(smp_processor_id());  } -#ifdef CONFIG_SPARSE_IRQ -int __init arch_probe_nr_irqs(void) -{ -	/* -	 * No pre-allocated IRQs. -	 */ -	return 0; -} -#endif -  #ifdef CONFIG_HOTPLUG_CPU  static void route_irq(struct irq_data *data, unsigned int irq, unsigned int cpu)  { diff --git a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c index 9b7a459a461..055d91b7030 100644 --- a/arch/sh/kernel/process.c +++ b/arch/sh/kernel/process.c @@ -4,6 +4,7 @@  #include <linux/sched.h>  #include <linux/export.h>  #include <linux/stackprotector.h> +#include <asm/fpu.h>  struct kmem_cache *task_xstate_cachep = NULL;  unsigned int xstate_size; diff --git a/arch/sh/kernel/process_64.c b/arch/sh/kernel/process_64.c index 4264583eaba..602545b12a8 100644 --- a/arch/sh/kernel/process_64.c +++ b/arch/sh/kernel/process_64.c @@ -33,6 +33,7 @@  #include <asm/switch_to.h>  struct task_struct *last_task_used_math = NULL; +struct pt_regs fake_swapper_regs = { 0, };  void show_regs(struct pt_regs *regs)  { diff --git a/arch/sh/kernel/sh_ksyms_64.c b/arch/sh/kernel/sh_ksyms_64.c index 45afa5c51f6..26a0774f527 100644 --- a/arch/sh/kernel/sh_ksyms_64.c +++ b/arch/sh/kernel/sh_ksyms_64.c @@ -32,8 +32,6 @@ EXPORT_SYMBOL(__get_user_asm_b);  EXPORT_SYMBOL(__get_user_asm_w);  EXPORT_SYMBOL(__get_user_asm_l);  EXPORT_SYMBOL(__get_user_asm_q); -EXPORT_SYMBOL(__strnlen_user); -EXPORT_SYMBOL(__strncpy_from_user);  EXPORT_SYMBOL(__clear_user);  EXPORT_SYMBOL(copy_page);  EXPORT_SYMBOL(__copy_user); diff --git a/arch/sh/kernel/signal_32.c b/arch/sh/kernel/signal_32.c index cb4172c8af7..d6b7b6154f8 100644 --- a/arch/sh/kernel/signal_32.c +++ b/arch/sh/kernel/signal_32.c @@ -32,8 +32,6 @@  #include <asm/syscalls.h>  #include <asm/fpu.h> -#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) -  struct fdpic_func_descriptor {  	unsigned long	text;  	unsigned long	GOT; @@ -226,7 +224,6 @@ asmlinkage int sys_sigreturn(unsigned long r4, unsigned long r5,  				    sizeof(frame->extramask))))  		goto badframe; -	sigdelsetmask(&set, ~_BLOCKABLE);  	set_current_blocked(&set);  	if (restore_sigcontext(regs, &frame->sc, &r0)) @@ -256,7 +253,6 @@ asmlinkage int sys_rt_sigreturn(unsigned long r4, unsigned long r5,  	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))  		goto badframe; -	sigdelsetmask(&set, ~_BLOCKABLE);  	set_current_blocked(&set);  	if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &r0)) @@ -522,10 +518,11 @@ handle_syscall_restart(unsigned long save_r0, struct pt_regs *regs,  /*   * OK, we're invoking a handler   */ -static int +static void  handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, -	      sigset_t *oldset, struct pt_regs *regs, unsigned int save_r0) +	      struct pt_regs *regs, unsigned int save_r0)  { +	sigset_t *oldset = sigmask_to_save();  	int ret;  	/* Set up the stack frame */ @@ -534,10 +531,10 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,  	else  		ret = setup_frame(sig, ka, oldset, regs); -	if (ret == 0) -		block_sigmask(ka, sig); - -	return ret; +	if (ret) +		return; +	signal_delivered(sig, info, ka, regs, +			test_thread_flag(TIF_SINGLESTEP));  }  /* @@ -554,7 +551,6 @@ static void do_signal(struct pt_regs *regs, unsigned int save_r0)  	siginfo_t info;  	int signr;  	struct k_sigaction ka; -	sigset_t *oldset;  	/*  	 * We want the common case to go fast, which @@ -565,30 +561,12 @@ static void do_signal(struct pt_regs *regs, unsigned int save_r0)  	if (!user_mode(regs))  		return; -	if (current_thread_info()->status & TS_RESTORE_SIGMASK) -		oldset = ¤t->saved_sigmask; -	else -		oldset = ¤t->blocked; -  	signr = get_signal_to_deliver(&info, &ka, regs, NULL);  	if (signr > 0) {  		handle_syscall_restart(save_r0, regs, &ka.sa);  		/* Whee!  Actually deliver the signal.  */ -		if (handle_signal(signr, &ka, &info, oldset, -				  regs, save_r0) == 0) { -			/* -			 * A signal was successfully delivered; the saved -			 * sigmask will have been stored in the signal frame, -			 * and will be restored by sigreturn, so we can simply -			 * clear the TS_RESTORE_SIGMASK flag -			 */ -			current_thread_info()->status &= ~TS_RESTORE_SIGMASK; - -			tracehook_signal_handler(signr, &info, &ka, regs, -					test_thread_flag(TIF_SINGLESTEP)); -		} - +		handle_signal(signr, &ka, &info, regs, save_r0);  		return;  	} @@ -610,10 +588,7 @@ static void do_signal(struct pt_regs *regs, unsigned int save_r0)  	 * If there's no signal to deliver, we just put the saved sigmask  	 * back.  	 */ -	if (current_thread_info()->status & TS_RESTORE_SIGMASK) { -		current_thread_info()->status &= ~TS_RESTORE_SIGMASK; -		sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); -	} +	restore_saved_sigmask();  }  asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned int save_r0, @@ -626,7 +601,5 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned int save_r0,  	if (thread_info_flags & _TIF_NOTIFY_RESUME) {  		clear_thread_flag(TIF_NOTIFY_RESUME);  		tracehook_notify_resume(regs); -		if (current->replacement_session_keyring) -			key_replace_session_keyring();  	}  } diff --git a/arch/sh/kernel/signal_64.c b/arch/sh/kernel/signal_64.c index b589a354c06..6b5b3dfe886 100644 --- a/arch/sh/kernel/signal_64.c +++ b/arch/sh/kernel/signal_64.c @@ -41,11 +41,9 @@  #define DEBUG_SIG 0 -#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) - -static int +static void  handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, -		sigset_t *oldset, struct pt_regs * regs); +		struct pt_regs * regs);  static inline void  handle_syscall_restart(struct pt_regs *regs, struct sigaction *sa) @@ -88,7 +86,6 @@ static void do_signal(struct pt_regs *regs)  	siginfo_t info;  	int signr;  	struct k_sigaction ka; -	sigset_t *oldset;  	/*  	 * We want the common case to go fast, which @@ -99,28 +96,13 @@ static void do_signal(struct pt_regs *regs)  	if (!user_mode(regs))  		return; -	if (current_thread_info()->status & TS_RESTORE_SIGMASK) -		oldset = ¤t->saved_sigmask; -	else -		oldset = ¤t->blocked; -  	signr = get_signal_to_deliver(&info, &ka, regs, 0);  	if (signr > 0) {  		handle_syscall_restart(regs, &ka.sa);  		/* Whee!  Actually deliver the signal.  */ -		if (handle_signal(signr, &info, &ka, oldset, regs) == 0) { -			/* -			 * If a signal was successfully delivered, the -			 * saved sigmask is in its frame, and we can -			 * clear the TS_RESTORE_SIGMASK flag. -			 */ -			current_thread_info()->status &= ~TS_RESTORE_SIGMASK; - -			tracehook_signal_handler(signr, &info, &ka, regs, -					test_thread_flag(TIF_SINGLESTEP)); -			return; -		} +		handle_signal(signr, &info, &ka, regs); +		return;  	}  	/* Did we come from a system call? */ @@ -143,12 +125,7 @@ static void do_signal(struct pt_regs *regs)  	}  	/* No signal to deliver -- put the saved sigmask back */ -	if (current_thread_info()->status & TS_RESTORE_SIGMASK) { -		current_thread_info()->status &= ~TS_RESTORE_SIGMASK; -		sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); -	} - -	return; +	restore_saved_sigmask();  }  /* @@ -351,7 +328,6 @@ asmlinkage int sys_sigreturn(unsigned long r2, unsigned long r3,  				    sizeof(frame->extramask))))  		goto badframe; -	sigdelsetmask(&set, ~_BLOCKABLE);  	set_current_blocked(&set);  	if (restore_sigcontext(regs, &frame->sc, &ret)) @@ -384,7 +360,6 @@ asmlinkage int sys_rt_sigreturn(unsigned long r2, unsigned long r3,  	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))  		goto badframe; -	sigdelsetmask(&set, ~_BLOCKABLE);  	set_current_blocked(&set);  	if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ret)) @@ -659,10 +634,11 @@ give_sigsegv:  /*   * OK, we're invoking a handler   */ -static int +static void  handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, -		sigset_t *oldset, struct pt_regs * regs) +		struct pt_regs * regs)  { +	sigset_t *oldset = sigmask_to_save();  	int ret;  	/* Set up the stack frame */ @@ -671,10 +647,11 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,  	else  		ret = setup_frame(sig, ka, oldset, regs); -	if (ret == 0) -		block_sigmask(ka, sig); +	if (ret) +		return; -	return ret; +	signal_delivered(sig, info, ka, regs, +			test_thread_flag(TIF_SINGLESTEP));  }  asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags) @@ -685,7 +662,5 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned long thread_info  	if (thread_info_flags & _TIF_NOTIFY_RESUME) {  		clear_thread_flag(TIF_NOTIFY_RESUME);  		tracehook_notify_resume(regs); -		if (current->replacement_session_keyring) -			key_replace_session_keyring();  	}  } diff --git a/arch/sh/kernel/smp.c b/arch/sh/kernel/smp.c index b86e9ca7945..2062aa88af4 100644 --- a/arch/sh/kernel/smp.c +++ b/arch/sh/kernel/smp.c @@ -123,7 +123,6 @@ void native_play_dead(void)  int __cpu_disable(void)  {  	unsigned int cpu = smp_processor_id(); -	struct task_struct *p;  	int ret;  	ret = mp_ops->cpu_disable(cpu); @@ -153,11 +152,7 @@ int __cpu_disable(void)  	flush_cache_all();  	local_flush_tlb_all(); -	read_lock(&tasklist_lock); -	for_each_process(p) -		if (p->mm) -			cpumask_clear_cpu(cpu, mm_cpumask(p->mm)); -	read_unlock(&tasklist_lock); +	clear_tasks_mm_cpumask(cpu);  	return 0;  } diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c index a87e58a9e38..72246bc0688 100644 --- a/arch/sh/kernel/traps.c +++ b/arch/sh/kernel/traps.c @@ -6,9 +6,80 @@  #include <linux/sched.h>  #include <linux/uaccess.h>  #include <linux/hardirq.h> +#include <linux/kernel.h> +#include <linux/kexec.h> +#include <linux/module.h>  #include <asm/unwinder.h>  #include <asm/traps.h> +static DEFINE_SPINLOCK(die_lock); + +void die(const char *str, struct pt_regs *regs, long err) +{ +	static int die_counter; + +	oops_enter(); + +	spin_lock_irq(&die_lock); +	console_verbose(); +	bust_spinlocks(1); + +	printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter); +	print_modules(); +	show_regs(regs); + +	printk("Process: %s (pid: %d, stack limit = %p)\n", current->comm, +			task_pid_nr(current), task_stack_page(current) + 1); + +	if (!user_mode(regs) || in_interrupt()) +		dump_mem("Stack: ", regs->regs[15], THREAD_SIZE + +			 (unsigned long)task_stack_page(current)); + +	notify_die(DIE_OOPS, str, regs, err, 255, SIGSEGV); + +	bust_spinlocks(0); +	add_taint(TAINT_DIE); +	spin_unlock_irq(&die_lock); +	oops_exit(); + +	if (kexec_should_crash(current)) +		crash_kexec(regs); + +	if (in_interrupt()) +		panic("Fatal exception in interrupt"); + +	if (panic_on_oops) +		panic("Fatal exception"); + +	do_exit(SIGSEGV); +} + +void die_if_kernel(const char *str, struct pt_regs *regs, long err) +{ +	if (!user_mode(regs)) +		die(str, regs, err); +} + +/* + * try and fix up kernelspace address errors + * - userspace errors just cause EFAULT to be returned, resulting in SEGV + * - kernel/userspace interfaces cause a jump to an appropriate handler + * - other kernel errors are bad + */ +void die_if_no_fixup(const char *str, struct pt_regs *regs, long err) +{ +	if (!user_mode(regs)) { +		const struct exception_table_entry *fixup; +		fixup = search_exception_tables(regs->pc); +		if (fixup) { +			regs->pc = fixup->fixup; +			return; +		} + +		die(str, regs, err); +	} +} +  #ifdef CONFIG_GENERIC_BUG  static void handle_BUG(struct pt_regs *regs)  { diff --git a/arch/sh/kernel/traps_32.c b/arch/sh/kernel/traps_32.c index a37175deb73..5f513a64ded 100644 --- a/arch/sh/kernel/traps_32.c +++ b/arch/sh/kernel/traps_32.c @@ -16,13 +16,11 @@  #include <linux/hardirq.h>  #include <linux/init.h>  #include <linux/spinlock.h> -#include <linux/module.h>  #include <linux/kallsyms.h>  #include <linux/io.h>  #include <linux/bug.h>  #include <linux/debug_locks.h>  #include <linux/kdebug.h> -#include <linux/kexec.h>  #include <linux/limits.h>  #include <linux/sysfs.h>  #include <linux/uaccess.h> @@ -48,102 +46,6 @@  #define TRAP_ILLEGAL_SLOT_INST	13  #endif -static void dump_mem(const char *str, unsigned long bottom, unsigned long top) -{ -	unsigned long p; -	int i; - -	printk("%s(0x%08lx to 0x%08lx)\n", str, bottom, top); - -	for (p = bottom & ~31; p < top; ) { -		printk("%04lx: ", p & 0xffff); - -		for (i = 0; i < 8; i++, p += 4) { -			unsigned int val; - -			if (p < bottom || p >= top) -				printk("         "); -			else { -				if (__get_user(val, (unsigned int __user *)p)) { -					printk("\n"); -					return; -				} -				printk("%08x ", val); -			} -		} -		printk("\n"); -	} -} - -static DEFINE_SPINLOCK(die_lock); - -void die(const char * str, struct pt_regs * regs, long err) -{ -	static int die_counter; - -	oops_enter(); - -	spin_lock_irq(&die_lock); -	console_verbose(); -	bust_spinlocks(1); - -	printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter); -	print_modules(); -	show_regs(regs); - -	printk("Process: %s (pid: %d, stack limit = %p)\n", current->comm, -			task_pid_nr(current), task_stack_page(current) + 1); - -	if (!user_mode(regs) || in_interrupt()) -		dump_mem("Stack: ", regs->regs[15], THREAD_SIZE + -			 (unsigned long)task_stack_page(current)); - -	notify_die(DIE_OOPS, str, regs, err, 255, SIGSEGV); - -	bust_spinlocks(0); -	add_taint(TAINT_DIE); -	spin_unlock_irq(&die_lock); -	oops_exit(); - -	if (kexec_should_crash(current)) -		crash_kexec(regs); - -	if (in_interrupt()) -		panic("Fatal exception in interrupt"); - -	if (panic_on_oops) -		panic("Fatal exception"); - -	do_exit(SIGSEGV); -} - -static inline void die_if_kernel(const char *str, struct pt_regs *regs, -				 long err) -{ -	if (!user_mode(regs)) -		die(str, regs, err); -} - -/* - * try and fix up kernelspace address errors - * - userspace errors just cause EFAULT to be returned, resulting in SEGV - * - kernel/userspace interfaces cause a jump to an appropriate handler - * - other kernel errors are bad - */ -static void die_if_no_fixup(const char * str, struct pt_regs * regs, long err) -{ -	if (!user_mode(regs)) { -		const struct exception_table_entry *fixup; -		fixup = search_exception_tables(regs->pc); -		if (fixup) { -			regs->pc = fixup->fixup; -			return; -		} - -		die(str, regs, err); -	} -} -  static inline void sign_extend(unsigned int count, unsigned char *dst)  {  #ifdef __LITTLE_ENDIAN__ @@ -900,26 +802,3 @@ void __init trap_init(void)  	set_exception_table_vec(TRAP_UBC, breakpoint_trap_handler);  #endif  } - -void show_stack(struct task_struct *tsk, unsigned long *sp) -{ -	unsigned long stack; - -	if (!tsk) -		tsk = current; -	if (tsk == current) -		sp = (unsigned long *)current_stack_pointer; -	else -		sp = (unsigned long *)tsk->thread.sp; - -	stack = (unsigned long)sp; -	dump_mem("Stack: ", stack, THREAD_SIZE + -		 (unsigned long)task_stack_page(tsk)); -	show_trace(tsk, sp, NULL); -} - -void dump_stack(void) -{ -	show_stack(NULL, NULL); -} -EXPORT_SYMBOL(dump_stack); diff --git a/arch/sh/kernel/traps_64.c b/arch/sh/kernel/traps_64.c index 8dae93ed8af..f87d20da179 100644 --- a/arch/sh/kernel/traps_64.c +++ b/arch/sh/kernel/traps_64.c @@ -27,283 +27,25 @@  #include <linux/perf_event.h>  #include <asm/uaccess.h>  #include <asm/io.h> -#include <linux/atomic.h> +#include <asm/alignment.h>  #include <asm/processor.h>  #include <asm/pgtable.h>  #include <asm/fpu.h> -#undef DEBUG_EXCEPTION -#ifdef DEBUG_EXCEPTION -/* implemented in ../lib/dbg.c */ -extern void show_excp_regs(char *fname, int trapnr, int signr, -			   struct pt_regs *regs); -#else -#define show_excp_regs(a, b, c, d) -#endif - -static void do_unhandled_exception(int trapnr, int signr, char *str, char *fn_name, -		unsigned long error_code, struct pt_regs *regs, struct task_struct *tsk); - -#define DO_ERROR(trapnr, signr, str, name, tsk) \ -asmlinkage void do_##name(unsigned long error_code, struct pt_regs *regs) \ -{ \ -	do_unhandled_exception(trapnr, signr, str, __stringify(name), error_code, regs, current); \ -} - -static DEFINE_SPINLOCK(die_lock); - -void die(const char * str, struct pt_regs * regs, long err) -{ -	console_verbose(); -	spin_lock_irq(&die_lock); -	printk("%s: %lx\n", str, (err & 0xffffff)); -	show_regs(regs); -	spin_unlock_irq(&die_lock); -	do_exit(SIGSEGV); -} - -static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err) -{ -	if (!user_mode(regs)) -		die(str, regs, err); -} - -static void die_if_no_fixup(const char * str, struct pt_regs * regs, long err) -{ -	if (!user_mode(regs)) { -		const struct exception_table_entry *fixup; -		fixup = search_exception_tables(regs->pc); -		if (fixup) { -			regs->pc = fixup->fixup; -			return; -		} -		die(str, regs, err); -	} -} - -DO_ERROR(13, SIGILL,  "illegal slot instruction", illegal_slot_inst, current) -DO_ERROR(87, SIGSEGV, "address error (exec)", address_error_exec, current) - - -/* Implement misaligned load/store handling for kernel (and optionally for user -   mode too).  Limitation : only SHmedia mode code is handled - there is no -   handling at all for misaligned accesses occurring in SHcompact code yet. */ - -static int misaligned_fixup(struct pt_regs *regs); - -asmlinkage void do_address_error_load(unsigned long error_code, struct pt_regs *regs) -{ -	if (misaligned_fixup(regs) < 0) { -		do_unhandled_exception(7, SIGSEGV, "address error(load)", -				"do_address_error_load", -				error_code, regs, current); -	} -	return; -} - -asmlinkage void do_address_error_store(unsigned long error_code, struct pt_regs *regs) -{ -	if (misaligned_fixup(regs) < 0) { -		do_unhandled_exception(8, SIGSEGV, "address error(store)", -				"do_address_error_store", -				error_code, regs, current); -	} -	return; -} - -#if defined(CONFIG_SH64_ID2815_WORKAROUND) - -#define OPCODE_INVALID      0 -#define OPCODE_USER_VALID   1 -#define OPCODE_PRIV_VALID   2 - -/* getcon/putcon - requires checking which control register is referenced. */ -#define OPCODE_CTRL_REG     3 - -/* Table of valid opcodes for SHmedia mode. -   Form a 10-bit value by concatenating the major/minor opcodes i.e. -   opcode[31:26,20:16].  The 6 MSBs of this value index into the following -   array.  The 4 LSBs select the bit-pair in the entry (bits 1:0 correspond to -   LSBs==4'b0000 etc). */ -static unsigned long shmedia_opcode_table[64] = { -	0x55554044,0x54445055,0x15141514,0x14541414,0x00000000,0x10001000,0x01110055,0x04050015, -	0x00000444,0xc0000000,0x44545515,0x40405555,0x55550015,0x10005555,0x55555505,0x04050000, -	0x00000555,0x00000404,0x00040445,0x15151414,0x00000000,0x00000000,0x00000000,0x00000000, -	0x00000055,0x40404444,0x00000404,0xc0009495,0x00000000,0x00000000,0x00000000,0x00000000, -	0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555, -	0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555, -	0x80005050,0x04005055,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555, -	0x81055554,0x00000404,0x55555555,0x55555555,0x00000000,0x00000000,0x00000000,0x00000000 -}; - -void do_reserved_inst(unsigned long error_code, struct pt_regs *regs) -{ -	/* Workaround SH5-101 cut2 silicon defect #2815 : -	   in some situations, inter-mode branches from SHcompact -> SHmedia -	   which should take ITLBMISS or EXECPROT exceptions at the target -	   falsely take RESINST at the target instead. */ - -	unsigned long opcode = 0x6ff4fff0; /* guaranteed reserved opcode */ -	unsigned long pc, aligned_pc; -	int get_user_error; -	int trapnr = 12; -	int signr = SIGILL; -	char *exception_name = "reserved_instruction"; - -	pc = regs->pc; -	if ((pc & 3) == 1) { -		/* SHmedia : check for defect.  This requires executable vmas -		   to be readable too. */ -		aligned_pc = pc & ~3; -		if (!access_ok(VERIFY_READ, aligned_pc, sizeof(unsigned long))) { -			get_user_error = -EFAULT; -		} else { -			get_user_error = __get_user(opcode, (unsigned long *)aligned_pc); -		} -		if (get_user_error >= 0) { -			unsigned long index, shift; -			unsigned long major, minor, combined; -			unsigned long reserved_field; -			reserved_field = opcode & 0xf; /* These bits are currently reserved as zero in all valid opcodes */ -			major = (opcode >> 26) & 0x3f; -			minor = (opcode >> 16) & 0xf; -			combined = (major << 4) | minor; -			index = major; -			shift = minor << 1; -			if (reserved_field == 0) { -				int opcode_state = (shmedia_opcode_table[index] >> shift) & 0x3; -				switch (opcode_state) { -					case OPCODE_INVALID: -						/* Trap. */ -						break; -					case OPCODE_USER_VALID: -						/* Restart the instruction : the branch to the instruction will now be from an RTE -						   not from SHcompact so the silicon defect won't be triggered. */ -						return; -					case OPCODE_PRIV_VALID: -						if (!user_mode(regs)) { -							/* Should only ever get here if a module has -							   SHcompact code inside it.  If so, the same fix up is needed. */ -							return; /* same reason */ -						} -						/* Otherwise, user mode trying to execute a privileged instruction - -						   fall through to trap. */ -						break; -					case OPCODE_CTRL_REG: -						/* If in privileged mode, return as above. */ -						if (!user_mode(regs)) return; -						/* In user mode ... */ -						if (combined == 0x9f) { /* GETCON */ -							unsigned long regno = (opcode >> 20) & 0x3f; -							if (regno >= 62) { -								return; -							} -							/* Otherwise, reserved or privileged control register, => trap */ -						} else if (combined == 0x1bf) { /* PUTCON */ -							unsigned long regno = (opcode >> 4) & 0x3f; -							if (regno >= 62) { -								return; -							} -							/* Otherwise, reserved or privileged control register, => trap */ -						} else { -							/* Trap */ -						} -						break; -					default: -						/* Fall through to trap. */ -						break; -				} -			} -			/* fall through to normal resinst processing */ -		} else { -			/* Error trying to read opcode.  This typically means a -			   real fault, not a RESINST any more.  So change the -			   codes. */ -			trapnr = 87; -			exception_name = "address error (exec)"; -			signr = SIGSEGV; -		} -	} - -	do_unhandled_exception(trapnr, signr, exception_name, "do_reserved_inst", error_code, regs, current); -} - -#else /* CONFIG_SH64_ID2815_WORKAROUND */ - -/* If the workaround isn't needed, this is just a straightforward reserved -   instruction */ -DO_ERROR(12, SIGILL,  "reserved instruction", reserved_inst, current) - -#endif /* CONFIG_SH64_ID2815_WORKAROUND */ - -/* Called with interrupts disabled */ -asmlinkage void do_exception_error(unsigned long ex, struct pt_regs *regs) -{ -	show_excp_regs(__func__, -1, -1, regs); -	die_if_kernel("exception", regs, ex); -} - -int do_unknown_trapa(unsigned long scId, struct pt_regs *regs) -{ -	/* Syscall debug */ -        printk("System call ID error: [0x1#args:8 #syscall:16  0x%lx]\n", scId); - -	die_if_kernel("unknown trapa", regs, scId); - -	return -ENOSYS; -} - -void show_stack(struct task_struct *tsk, unsigned long *sp) -{ -#ifdef CONFIG_KALLSYMS -	extern void sh64_unwind(struct pt_regs *regs); -	struct pt_regs *regs; - -	regs = tsk ? tsk->thread.kregs : NULL; - -	sh64_unwind(regs); -#else -	printk(KERN_ERR "Can't backtrace on sh64 without CONFIG_KALLSYMS\n"); -#endif -} - -void show_task(unsigned long *sp) -{ -	show_stack(NULL, sp); -} - -void dump_stack(void) -{ -	show_task(NULL); -} -/* Needed by any user of WARN_ON in view of the defn in include/asm-sh/bug.h */ -EXPORT_SYMBOL(dump_stack); - -static void do_unhandled_exception(int trapnr, int signr, char *str, char *fn_name, -		unsigned long error_code, struct pt_regs *regs, struct task_struct *tsk) -{ -	show_excp_regs(fn_name, trapnr, signr, regs); - -	if (user_mode(regs)) -		force_sig(signr, tsk); - -	die_if_no_fixup(str, regs, error_code); -} - -static int read_opcode(unsigned long long pc, unsigned long *result_opcode, int from_user_mode) +static int read_opcode(reg_size_t pc, insn_size_t *result_opcode, int from_user_mode)  {  	int get_user_error;  	unsigned long aligned_pc; -	unsigned long opcode; +	insn_size_t opcode;  	if ((pc & 3) == 1) {  		/* SHmedia */  		aligned_pc = pc & ~3;  		if (from_user_mode) { -			if (!access_ok(VERIFY_READ, aligned_pc, sizeof(unsigned long))) { +			if (!access_ok(VERIFY_READ, aligned_pc, sizeof(insn_size_t))) {  				get_user_error = -EFAULT;  			} else { -				get_user_error = __get_user(opcode, (unsigned long *)aligned_pc); +				get_user_error = __get_user(opcode, (insn_size_t *)aligned_pc);  				*result_opcode = opcode;  			}  			return get_user_error; @@ -311,7 +53,7 @@ static int read_opcode(unsigned long long pc, unsigned long *result_opcode, int  			/* If the fault was in the kernel, we can either read  			 * this directly, or if not, we fault.  			*/ -			*result_opcode = *(unsigned long *) aligned_pc; +			*result_opcode = *(insn_size_t *)aligned_pc;  			return 0;  		}  	} else if ((pc & 1) == 0) { @@ -337,17 +79,23 @@ static int address_is_sign_extended(__u64 a)  #endif  } +/* return -1 for fault, 0 for OK */  static int generate_and_check_address(struct pt_regs *regs, -				      __u32 opcode, +				      insn_size_t opcode,  				      int displacement_not_indexed,  				      int width_shift,  				      __u64 *address)  { -	/* return -1 for fault, 0 for OK */ -  	__u64 base_address, addr;  	int basereg; +	switch (1 << width_shift) { +	case 1: inc_unaligned_byte_access(); break; +	case 2: inc_unaligned_word_access(); break; +	case 4: inc_unaligned_dword_access(); break; +	case 8: inc_unaligned_multi_access(); break; +	} +  	basereg = (opcode >> 20) & 0x3f;  	base_address = regs->regs[basereg];  	if (displacement_not_indexed) { @@ -364,28 +112,28 @@ static int generate_and_check_address(struct pt_regs *regs,  	}  	/* Check sign extended */ -	if (!address_is_sign_extended(addr)) { +	if (!address_is_sign_extended(addr))  		return -1; -	}  	/* Check accessible.  For misaligned access in the kernel, assume the  	   address is always accessible (and if not, just fault when the  	   load/store gets done.) */  	if (user_mode(regs)) { -		if (addr >= TASK_SIZE) { +		inc_unaligned_user_access(); + +		if (addr >= TASK_SIZE)  			return -1; -		} -		/* Do access_ok check later - it depends on whether it's a load or a store. */ -	} +	} else +		inc_unaligned_kernel_access();  	*address = addr; + +	perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, addr); +	unaligned_fixups_notify(current, opcode, regs); +  	return 0;  } -static int user_mode_unaligned_fixup_count = 10; -static int user_mode_unaligned_fixup_enable = 1; -static int kernel_mode_unaligned_fixup_count = 32; -  static void misaligned_kernel_word_load(__u64 address, int do_sign_extend, __u64 *result)  {  	unsigned short x; @@ -415,7 +163,7 @@ static void misaligned_kernel_word_store(__u64 address, __u64 value)  }  static int misaligned_load(struct pt_regs *regs, -			   __u32 opcode, +			   insn_size_t opcode,  			   int displacement_not_indexed,  			   int width_shift,  			   int do_sign_extend) @@ -427,11 +175,8 @@ static int misaligned_load(struct pt_regs *regs,  	error = generate_and_check_address(regs, opcode,  			displacement_not_indexed, width_shift, &address); -	if (error < 0) { +	if (error < 0)  		return error; -	} - -	perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, regs, address);  	destreg = (opcode >> 4) & 0x3f;  	if (user_mode(regs)) { @@ -490,11 +235,10 @@ static int misaligned_load(struct pt_regs *regs,  	}  	return 0; -  }  static int misaligned_store(struct pt_regs *regs, -			    __u32 opcode, +			    insn_size_t opcode,  			    int displacement_not_indexed,  			    int width_shift)  { @@ -505,11 +249,8 @@ static int misaligned_store(struct pt_regs *regs,  	error = generate_and_check_address(regs, opcode,  			displacement_not_indexed, width_shift, &address); -	if (error < 0) { +	if (error < 0)  		return error; -	} - -	perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, regs, address);  	srcreg = (opcode >> 4) & 0x3f;  	if (user_mode(regs)) { @@ -563,13 +304,12 @@ static int misaligned_store(struct pt_regs *regs,  	}  	return 0; -  }  /* Never need to fix up misaligned FPU accesses within the kernel since that's a real     error. */  static int misaligned_fpu_load(struct pt_regs *regs, -			   __u32 opcode, +			   insn_size_t opcode,  			   int displacement_not_indexed,  			   int width_shift,  			   int do_paired_load) @@ -581,11 +321,8 @@ static int misaligned_fpu_load(struct pt_regs *regs,  	error = generate_and_check_address(regs, opcode,  			displacement_not_indexed, width_shift, &address); -	if (error < 0) { +	if (error < 0)  		return error; -	} - -	perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, address);  	destreg = (opcode >> 4) & 0x3f;  	if (user_mode(regs)) { @@ -641,12 +378,10 @@ static int misaligned_fpu_load(struct pt_regs *regs,  		die ("Misaligned FPU load inside kernel", regs, 0);  		return -1;  	} - -  }  static int misaligned_fpu_store(struct pt_regs *regs, -			   __u32 opcode, +			   insn_size_t opcode,  			   int displacement_not_indexed,  			   int width_shift,  			   int do_paired_load) @@ -658,11 +393,8 @@ static int misaligned_fpu_store(struct pt_regs *regs,  	error = generate_and_check_address(regs, opcode,  			displacement_not_indexed, width_shift, &address); -	if (error < 0) { +	if (error < 0)  		return error; -	} - -	perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, address);  	srcreg = (opcode >> 4) & 0x3f;  	if (user_mode(regs)) { @@ -723,11 +455,13 @@ static int misaligned_fpu_store(struct pt_regs *regs,  static int misaligned_fixup(struct pt_regs *regs)  { -	unsigned long opcode; +	insn_size_t opcode;  	int error;  	int major, minor; +	unsigned int user_action; -	if (!user_mode_unaligned_fixup_enable) +	user_action = unaligned_user_action(); +	if (!(user_action & UM_FIXUP))  		return -1;  	error = read_opcode(regs->pc, &opcode, user_mode(regs)); @@ -737,23 +471,6 @@ static int misaligned_fixup(struct pt_regs *regs)  	major = (opcode >> 26) & 0x3f;  	minor = (opcode >> 16) & 0xf; -	if (user_mode(regs) && (user_mode_unaligned_fixup_count > 0)) { -		--user_mode_unaligned_fixup_count; -		/* Only do 'count' worth of these reports, to remove a potential DoS against syslog */ -		printk("Fixing up unaligned userspace access in \"%s\" pid=%d pc=0x%08x ins=0x%08lx\n", -		       current->comm, task_pid_nr(current), (__u32)regs->pc, opcode); -	} else if (!user_mode(regs) && (kernel_mode_unaligned_fixup_count > 0)) { -		--kernel_mode_unaligned_fixup_count; -		if (in_interrupt()) { -			printk("Fixing up unaligned kernelspace access in interrupt pc=0x%08x ins=0x%08lx\n", -			       (__u32)regs->pc, opcode); -		} else { -			printk("Fixing up unaligned kernelspace access in \"%s\" pid=%d pc=0x%08x ins=0x%08lx\n", -			       current->comm, task_pid_nr(current), (__u32)regs->pc, opcode); -		} -	} - -  	switch (major) {  		case (0x84>>2): /* LD.W */  			error = misaligned_load(regs, opcode, 1, 1, 1); @@ -878,59 +595,202 @@ static int misaligned_fixup(struct pt_regs *regs)  		regs->pc += 4; /* Skip the instruction that's just been emulated */  		return 0;  	} +} +static void do_unhandled_exception(int signr, char *str, unsigned long error, +				   struct pt_regs *regs) +{ +	if (user_mode(regs)) +		force_sig(signr, current); + +	die_if_no_fixup(str, regs, error);  } -static ctl_table unaligned_table[] = { -	{ -		.procname	= "kernel_reports", -		.data		= &kernel_mode_unaligned_fixup_count, -		.maxlen		= sizeof(int), -		.mode		= 0644, -		.proc_handler	= proc_dointvec -	}, -	{ -		.procname	= "user_reports", -		.data		= &user_mode_unaligned_fixup_count, -		.maxlen		= sizeof(int), -		.mode		= 0644, -		.proc_handler	= proc_dointvec -	}, -	{ -		.procname	= "user_enable", -		.data		= &user_mode_unaligned_fixup_enable, -		.maxlen		= sizeof(int), -		.mode		= 0644, -		.proc_handler	= proc_dointvec}, -	{} -}; +#define DO_ERROR(signr, str, name) \ +asmlinkage void do_##name(unsigned long error_code, struct pt_regs *regs) \ +{ \ +	do_unhandled_exception(signr, str, error_code, regs); \ +} -static ctl_table unaligned_root[] = { -	{ -		.procname	= "unaligned_fixup", -		.mode		= 0555, -		.child		= unaligned_table -	}, -	{} -}; +DO_ERROR(SIGILL,  "illegal slot instruction", illegal_slot_inst) +DO_ERROR(SIGSEGV, "address error (exec)", address_error_exec) -static ctl_table sh64_root[] = { -	{ -		.procname	= "sh64", -		.mode		= 0555, -		.child		= unaligned_root -	}, -	{} +#if defined(CONFIG_SH64_ID2815_WORKAROUND) + +#define OPCODE_INVALID      0 +#define OPCODE_USER_VALID   1 +#define OPCODE_PRIV_VALID   2 + +/* getcon/putcon - requires checking which control register is referenced. */ +#define OPCODE_CTRL_REG     3 + +/* Table of valid opcodes for SHmedia mode. +   Form a 10-bit value by concatenating the major/minor opcodes i.e. +   opcode[31:26,20:16].  The 6 MSBs of this value index into the following +   array.  The 4 LSBs select the bit-pair in the entry (bits 1:0 correspond to +   LSBs==4'b0000 etc). */ +static unsigned long shmedia_opcode_table[64] = { +	0x55554044,0x54445055,0x15141514,0x14541414,0x00000000,0x10001000,0x01110055,0x04050015, +	0x00000444,0xc0000000,0x44545515,0x40405555,0x55550015,0x10005555,0x55555505,0x04050000, +	0x00000555,0x00000404,0x00040445,0x15151414,0x00000000,0x00000000,0x00000000,0x00000000, +	0x00000055,0x40404444,0x00000404,0xc0009495,0x00000000,0x00000000,0x00000000,0x00000000, +	0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555, +	0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555, +	0x80005050,0x04005055,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555, +	0x81055554,0x00000404,0x55555555,0x55555555,0x00000000,0x00000000,0x00000000,0x00000000  }; -static struct ctl_table_header *sysctl_header; -static int __init init_sysctl(void) + +/* Workaround SH5-101 cut2 silicon defect #2815 : +   in some situations, inter-mode branches from SHcompact -> SHmedia +   which should take ITLBMISS or EXECPROT exceptions at the target +   falsely take RESINST at the target instead. */ +void do_reserved_inst(unsigned long error_code, struct pt_regs *regs)  { -	sysctl_header = register_sysctl_table(sh64_root); -	return 0; +	insn_size_t opcode = 0x6ff4fff0; /* guaranteed reserved opcode */ +	unsigned long pc, aligned_pc; +	unsigned long index, shift; +	unsigned long major, minor, combined; +	unsigned long reserved_field; +	int opcode_state; +	int get_user_error; +	int signr = SIGILL; +	char *exception_name = "reserved_instruction"; + +	pc = regs->pc; + +	/* SHcompact is not handled */ +	if (unlikely((pc & 3) == 0)) +		goto out; + +	/* SHmedia : check for defect.  This requires executable vmas +	   to be readable too. */ +	aligned_pc = pc & ~3; +	if (!access_ok(VERIFY_READ, aligned_pc, sizeof(insn_size_t))) +		get_user_error = -EFAULT; +	else +		get_user_error = __get_user(opcode, (insn_size_t *)aligned_pc); + +	if (get_user_error < 0) { +		/* +		 * Error trying to read opcode.  This typically means a +		 * real fault, not a RESINST any more.  So change the +		 * codes. +		 */ +		exception_name = "address error (exec)"; +		signr = SIGSEGV; +		goto out; +	} + +	/* These bits are currently reserved as zero in all valid opcodes */ +	reserved_field = opcode & 0xf; +	if (unlikely(reserved_field)) +		goto out;	/* invalid opcode */ + +	major = (opcode >> 26) & 0x3f; +	minor = (opcode >> 16) & 0xf; +	combined = (major << 4) | minor; +	index = major; +	shift = minor << 1; +	opcode_state = (shmedia_opcode_table[index] >> shift) & 0x3; +	switch (opcode_state) { +	case OPCODE_INVALID: +		/* Trap. */ +		break; +	case OPCODE_USER_VALID: +		/* +		 * Restart the instruction: the branch to the instruction +		 * will now be from an RTE not from SHcompact so the +		 * silicon defect won't be triggered. +		 */ +		return; +	case OPCODE_PRIV_VALID: +		if (!user_mode(regs)) { +			/* +			 * Should only ever get here if a module has +			 * SHcompact code inside it. If so, the same fix +			 * up is needed. +			 */ +			return; /* same reason */ +		} + +		/* +		 * Otherwise, user mode trying to execute a privileged +		 * instruction - fall through to trap. +		 */ +		break; +	case OPCODE_CTRL_REG: +		/* If in privileged mode, return as above. */ +		if (!user_mode(regs)) +			return; + +		/* In user mode ... */ +		if (combined == 0x9f) { /* GETCON */ +			unsigned long regno = (opcode >> 20) & 0x3f; + +			if (regno >= 62) +				return; + +			/* reserved/privileged control register => trap */ +		} else if (combined == 0x1bf) { /* PUTCON */ +			unsigned long regno = (opcode >> 4) & 0x3f; + +			if (regno >= 62) +				return; + +			/* reserved/privileged control register => trap */ +		} + +		break; +	default: +		/* Fall through to trap. */ +		break; +	} + +out: +	do_unhandled_exception(signr, exception_name, error_code, regs);  } -__initcall(init_sysctl); +#else /* CONFIG_SH64_ID2815_WORKAROUND */ +/* If the workaround isn't needed, this is just a straightforward reserved +   instruction */ +DO_ERROR(SIGILL, "reserved instruction", reserved_inst) + +#endif /* CONFIG_SH64_ID2815_WORKAROUND */ + +/* Called with interrupts disabled */ +asmlinkage void do_exception_error(unsigned long ex, struct pt_regs *regs) +{ +	die_if_kernel("exception", regs, ex); +} + +asmlinkage int do_unknown_trapa(unsigned long scId, struct pt_regs *regs) +{ +	/* Syscall debug */ +	printk("System call ID error: [0x1#args:8 #syscall:16  0x%lx]\n", scId); + +	die_if_kernel("unknown trapa", regs, scId); + +	return -ENOSYS; +} + +/* Implement misaligned load/store handling for kernel (and optionally for user +   mode too).  Limitation : only SHmedia mode code is handled - there is no +   handling at all for misaligned accesses occurring in SHcompact code yet. */ + +asmlinkage void do_address_error_load(unsigned long error_code, struct pt_regs *regs) +{ +	if (misaligned_fixup(regs) < 0) +		do_unhandled_exception(SIGSEGV, "address error(load)", +				       error_code, regs); +} + +asmlinkage void do_address_error_store(unsigned long error_code, struct pt_regs *regs) +{ +	if (misaligned_fixup(regs) < 0) +		do_unhandled_exception(SIGSEGV, "address error(store)", +				error_code, regs); +}  asmlinkage void do_debug_interrupt(unsigned long code, struct pt_regs *regs)  { @@ -942,10 +802,9 @@ asmlinkage void do_debug_interrupt(unsigned long code, struct pt_regs *regs)  	   of access we make to them - just go direct to their physical  	   addresses. */  	exp_cause = peek_real_address_q(DM_EXP_CAUSE_PHY); -	if (exp_cause & ~4) { +	if (exp_cause & ~4)  		printk("DM.EXP_CAUSE had unexpected bits set (=%08lx)\n",  			(unsigned long)(exp_cause & 0xffffffff)); -	}  	show_state();  	/* Clear all DEBUGINT causes */  	poke_real_address_q(DM_EXP_CAUSE_PHY, 0x0);  |