diff options
Diffstat (limited to 'arch/sparc')
25 files changed, 578 insertions, 310 deletions
diff --git a/arch/sparc/include/asm/pgtsrmmu.h b/arch/sparc/include/asm/pgtsrmmu.h index 1407c07bdad..f6ae2b2b687 100644 --- a/arch/sparc/include/asm/pgtsrmmu.h +++ b/arch/sparc/include/asm/pgtsrmmu.h @@ -280,7 +280,7 @@ static inline unsigned long srmmu_hwprobe(unsigned long vaddr)  	return retval;  }  #else -#define srmmu_hwprobe(addr) (srmmu_swprobe(addr, 0) & SRMMU_PTE_PMASK) +#define srmmu_hwprobe(addr) srmmu_swprobe(addr, 0)  #endif  static inline int diff --git a/arch/sparc/include/asm/sigcontext.h b/arch/sparc/include/asm/sigcontext.h index a1607d18035..69914d74813 100644 --- a/arch/sparc/include/asm/sigcontext.h +++ b/arch/sparc/include/asm/sigcontext.h @@ -45,6 +45,19 @@ typedef struct {  	int			si_mask;  } __siginfo32_t; +#define __SIGC_MAXWIN	7 + +typedef struct { +	unsigned long locals[8]; +	unsigned long ins[8]; +} __siginfo_reg_window; + +typedef struct { +	int			wsaved; +	__siginfo_reg_window	reg_window[__SIGC_MAXWIN]; +	unsigned long		rwbuf_stkptrs[__SIGC_MAXWIN]; +} __siginfo_rwin_t; +  #ifdef CONFIG_SPARC64  typedef struct {  	unsigned   int si_float_regs [64]; @@ -73,6 +86,7 @@ struct sigcontext {  		unsigned long	ss_size;  	}			sigc_stack;  	unsigned long		sigc_mask; +	__siginfo_rwin_t *	sigc_rwin_save;  };  #else diff --git a/arch/sparc/include/asm/spitfire.h b/arch/sparc/include/asm/spitfire.h index 55a17c6efeb..d06a2660175 100644 --- a/arch/sparc/include/asm/spitfire.h +++ b/arch/sparc/include/asm/spitfire.h @@ -43,6 +43,8 @@  #define SUN4V_CHIP_NIAGARA1	0x01  #define SUN4V_CHIP_NIAGARA2	0x02  #define SUN4V_CHIP_NIAGARA3	0x03 +#define SUN4V_CHIP_NIAGARA4	0x04 +#define SUN4V_CHIP_NIAGARA5	0x05  #define SUN4V_CHIP_UNKNOWN	0xff  #ifndef __ASSEMBLY__ diff --git a/arch/sparc/include/asm/xor_64.h b/arch/sparc/include/asm/xor_64.h index 9ed6ff679ab..ee8edc68423 100644 --- a/arch/sparc/include/asm/xor_64.h +++ b/arch/sparc/include/asm/xor_64.h @@ -66,6 +66,8 @@ static struct xor_block_template xor_block_niagara = {  	((tlb_type == hypervisor && \  	  (sun4v_chip_type == SUN4V_CHIP_NIAGARA1 || \  	   sun4v_chip_type == SUN4V_CHIP_NIAGARA2 || \ -	   sun4v_chip_type == SUN4V_CHIP_NIAGARA3)) ? \ +	   sun4v_chip_type == SUN4V_CHIP_NIAGARA3 || \ +	   sun4v_chip_type == SUN4V_CHIP_NIAGARA4 || \ +	   sun4v_chip_type == SUN4V_CHIP_NIAGARA5)) ? \  	 &xor_block_niagara : \  	 &xor_block_VIS) diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile index b90b4a1d070..cb85458f89d 100644 --- a/arch/sparc/kernel/Makefile +++ b/arch/sparc/kernel/Makefile @@ -32,6 +32,7 @@ obj-$(CONFIG_SPARC32)   += sun4m_irq.o sun4c_irq.o sun4d_irq.o  obj-y                   += process_$(BITS).o  obj-y                   += signal_$(BITS).o +obj-y                   += sigutil_$(BITS).o  obj-$(CONFIG_SPARC32)   += ioport.o  obj-y                   += setup_$(BITS).o  obj-y                   += idprom.o diff --git a/arch/sparc/kernel/cpu.c b/arch/sparc/kernel/cpu.c index 9810fd88105..ba9b1cec4e6 100644 --- a/arch/sparc/kernel/cpu.c +++ b/arch/sparc/kernel/cpu.c @@ -481,6 +481,18 @@ static void __init sun4v_cpu_probe(void)  		sparc_pmu_type = "niagara3";  		break; +	case SUN4V_CHIP_NIAGARA4: +		sparc_cpu_type = "UltraSparc T4 (Niagara4)"; +		sparc_fpu_type = "UltraSparc T4 integrated FPU"; +		sparc_pmu_type = "niagara4"; +		break; + +	case SUN4V_CHIP_NIAGARA5: +		sparc_cpu_type = "UltraSparc T5 (Niagara5)"; +		sparc_fpu_type = "UltraSparc T5 integrated FPU"; +		sparc_pmu_type = "niagara5"; +		break; +  	default:  		printk(KERN_WARNING "CPU: Unknown sun4v cpu type [%s]\n",  		       prom_cpu_compatible); diff --git a/arch/sparc/kernel/cpumap.c b/arch/sparc/kernel/cpumap.c index 4197e8d62d4..9323eafccb9 100644 --- a/arch/sparc/kernel/cpumap.c +++ b/arch/sparc/kernel/cpumap.c @@ -325,6 +325,8 @@ static int iterate_cpu(struct cpuinfo_tree *t, unsigned int root_index)  	case SUN4V_CHIP_NIAGARA1:  	case SUN4V_CHIP_NIAGARA2:  	case SUN4V_CHIP_NIAGARA3: +	case SUN4V_CHIP_NIAGARA4: +	case SUN4V_CHIP_NIAGARA5:  		rover_inc_table = niagara_iterate_method;  		break;  	default: diff --git a/arch/sparc/kernel/head_64.S b/arch/sparc/kernel/head_64.S index 0eac1b2fc53..0d810c2f1d0 100644 --- a/arch/sparc/kernel/head_64.S +++ b/arch/sparc/kernel/head_64.S @@ -133,7 +133,7 @@ prom_sun4v_name:  prom_niagara_prefix:  	.asciz	"SUNW,UltraSPARC-T"  prom_sparc_prefix: -	.asciz	"SPARC-T" +	.asciz	"SPARC-"  	.align	4  prom_root_compatible:  	.skip	64 @@ -396,7 +396,7 @@ sun4v_chip_type:  	or	%g1, %lo(prom_cpu_compatible), %g1  	sethi	%hi(prom_sparc_prefix), %g7  	or	%g7, %lo(prom_sparc_prefix), %g7 -	mov	7, %g3 +	mov	6, %g3  90:	ldub	[%g7], %g2  	ldub	[%g1], %g4  	cmp	%g2, %g4 @@ -408,10 +408,23 @@ sun4v_chip_type:  	sethi	%hi(prom_cpu_compatible), %g1  	or	%g1, %lo(prom_cpu_compatible), %g1 -	ldub	[%g1 + 7], %g2 +	ldub	[%g1 + 6], %g2 +	cmp	%g2, 'T' +	be,pt	%xcc, 70f +	 cmp	%g2, 'M' +	bne,pn	%xcc, 4f +	 nop + +70:	ldub	[%g1 + 7], %g2  	cmp	%g2, '3'  	be,pt	%xcc, 5f  	 mov	SUN4V_CHIP_NIAGARA3, %g4 +	cmp	%g2, '4' +	be,pt	%xcc, 5f +	 mov	SUN4V_CHIP_NIAGARA4, %g4 +	cmp	%g2, '5' +	be,pt	%xcc, 5f +	 mov	SUN4V_CHIP_NIAGARA5, %g4  	ba,pt	%xcc, 4f  	 nop @@ -545,6 +558,12 @@ niagara_tlb_fixup:  	cmp	%g1, SUN4V_CHIP_NIAGARA3  	be,pt	%xcc, niagara2_patch  	 nop +	cmp	%g1, SUN4V_CHIP_NIAGARA4 +	be,pt	%xcc, niagara2_patch +	 nop +	cmp	%g1, SUN4V_CHIP_NIAGARA5 +	be,pt	%xcc, niagara2_patch +	 nop  	call	generic_patch_copyops  	 nop diff --git a/arch/sparc/kernel/irq.h b/arch/sparc/kernel/irq.h index 100b9c204e7..42851122bbd 100644 --- a/arch/sparc/kernel/irq.h +++ b/arch/sparc/kernel/irq.h @@ -88,7 +88,7 @@ BTFIXUPDEF_CALL(void, set_irq_udt, int)  #define set_irq_udt(cpu) BTFIXUP_CALL(set_irq_udt)(cpu)  /* All SUN4D IPIs are sent on this IRQ, may be shared with hard IRQs */ -#define SUN4D_IPI_IRQ 14 +#define SUN4D_IPI_IRQ 13  extern void sun4d_ipi_interrupt(void); diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c index 1e94f946570..8aa0d440858 100644 --- a/arch/sparc/kernel/pci.c +++ b/arch/sparc/kernel/pci.c @@ -230,7 +230,8 @@ static void pci_parse_of_addrs(struct platform_device *op,  			res = &dev->resource[(i - PCI_BASE_ADDRESS_0) >> 2];  		} else if (i == dev->rom_base_reg) {  			res = &dev->resource[PCI_ROM_RESOURCE]; -			flags |= IORESOURCE_READONLY | IORESOURCE_CACHEABLE; +			flags |= IORESOURCE_READONLY | IORESOURCE_CACHEABLE +			      | IORESOURCE_SIZEALIGN;  		} else {  			printk(KERN_ERR "PCI: bad cfg reg num 0x%x\n", i);  			continue; diff --git a/arch/sparc/kernel/process_32.c b/arch/sparc/kernel/process_32.c index c8cc461ff75..f793742eec2 100644 --- a/arch/sparc/kernel/process_32.c +++ b/arch/sparc/kernel/process_32.c @@ -380,8 +380,7 @@ void flush_thread(void)  #endif  	} -	/* Now, this task is no longer a kernel thread. */ -	current->thread.current_ds = USER_DS; +	/* This task is no longer a kernel thread. */  	if (current->thread.flags & SPARC_FLAG_KTHREAD) {  		current->thread.flags &= ~SPARC_FLAG_KTHREAD; diff --git a/arch/sparc/kernel/process_64.c b/arch/sparc/kernel/process_64.c index c158a95ec66..d959cd0a4aa 100644 --- a/arch/sparc/kernel/process_64.c +++ b/arch/sparc/kernel/process_64.c @@ -368,9 +368,6 @@ void flush_thread(void)  	/* Clear FPU register state. */  	t->fpsaved[0] = 0; -	 -	if (get_thread_current_ds() != ASI_AIUS) -		set_fs(USER_DS);  }  /* It's a bit more tricky when 64-bit tasks are involved... */ diff --git a/arch/sparc/kernel/setup_32.c b/arch/sparc/kernel/setup_32.c index d26e1f6c717..3e3e2914c70 100644 --- a/arch/sparc/kernel/setup_32.c +++ b/arch/sparc/kernel/setup_32.c @@ -137,7 +137,7 @@ static void __init process_switch(char c)  		prom_halt();  		break;  	case 'p': -		/* Just ignore, this behavior is now the default.  */ +		prom_early_console.flags &= ~CON_BOOT;  		break;  	default:  		printk("Unknown boot switch (-%c)\n", c); diff --git a/arch/sparc/kernel/setup_64.c b/arch/sparc/kernel/setup_64.c index 3e9daea1653..c965595aa7e 100644 --- a/arch/sparc/kernel/setup_64.c +++ b/arch/sparc/kernel/setup_64.c @@ -106,7 +106,7 @@ static void __init process_switch(char c)  		prom_halt();  		break;  	case 'p': -		/* Just ignore, this behavior is now the default.  */ +		prom_early_console.flags &= ~CON_BOOT;  		break;  	case 'P':  		/* Force UltraSPARC-III P-Cache on. */ @@ -425,10 +425,14 @@ static void __init init_sparc64_elf_hwcap(void)  	else if (tlb_type == hypervisor) {  		if (sun4v_chip_type == SUN4V_CHIP_NIAGARA1 ||  		    sun4v_chip_type == SUN4V_CHIP_NIAGARA2 || -		    sun4v_chip_type == SUN4V_CHIP_NIAGARA3) +		    sun4v_chip_type == SUN4V_CHIP_NIAGARA3 || +		    sun4v_chip_type == SUN4V_CHIP_NIAGARA4 || +		    sun4v_chip_type == SUN4V_CHIP_NIAGARA5)  			cap |= HWCAP_SPARC_BLKINIT;  		if (sun4v_chip_type == SUN4V_CHIP_NIAGARA2 || -		    sun4v_chip_type == SUN4V_CHIP_NIAGARA3) +		    sun4v_chip_type == SUN4V_CHIP_NIAGARA3 || +		    sun4v_chip_type == SUN4V_CHIP_NIAGARA4 || +		    sun4v_chip_type == SUN4V_CHIP_NIAGARA5)  			cap |= HWCAP_SPARC_N2;  	} @@ -440,17 +444,27 @@ static void __init init_sparc64_elf_hwcap(void)  			cap |= AV_SPARC_VIS;  		if (tlb_type == cheetah || tlb_type == cheetah_plus)  			cap |= AV_SPARC_VIS | AV_SPARC_VIS2; -		if (tlb_type == cheetah_plus) -			cap |= AV_SPARC_POPC; +		if (tlb_type == cheetah_plus) { +			unsigned long impl, ver; + +			__asm__ __volatile__("rdpr %%ver, %0" : "=r" (ver)); +			impl = ((ver >> 32) & 0xffff); +			if (impl == PANTHER_IMPL) +				cap |= AV_SPARC_POPC; +		}  		if (tlb_type == hypervisor) {  			if (sun4v_chip_type == SUN4V_CHIP_NIAGARA1)  				cap |= AV_SPARC_ASI_BLK_INIT;  			if (sun4v_chip_type == SUN4V_CHIP_NIAGARA2 || -			    sun4v_chip_type == SUN4V_CHIP_NIAGARA3) +			    sun4v_chip_type == SUN4V_CHIP_NIAGARA3 || +			    sun4v_chip_type == SUN4V_CHIP_NIAGARA4 || +			    sun4v_chip_type == SUN4V_CHIP_NIAGARA5)  				cap |= (AV_SPARC_VIS | AV_SPARC_VIS2 |  					AV_SPARC_ASI_BLK_INIT |  					AV_SPARC_POPC); -			if (sun4v_chip_type == SUN4V_CHIP_NIAGARA3) +			if (sun4v_chip_type == SUN4V_CHIP_NIAGARA3 || +			    sun4v_chip_type == SUN4V_CHIP_NIAGARA4 || +			    sun4v_chip_type == SUN4V_CHIP_NIAGARA5)  				cap |= (AV_SPARC_VIS3 | AV_SPARC_HPC |  					AV_SPARC_FMAF);  		} diff --git a/arch/sparc/kernel/signal32.c b/arch/sparc/kernel/signal32.c index 75fad425e24..2caa556db86 100644 --- a/arch/sparc/kernel/signal32.c +++ b/arch/sparc/kernel/signal32.c @@ -29,6 +29,8 @@  #include <asm/visasm.h>  #include <asm/compat_signal.h> +#include "sigutil.h" +  #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))  /* This magic should be in g_upper[0] for all upper parts @@ -44,14 +46,14 @@ typedef struct {  struct signal_frame32 {  	struct sparc_stackf32	ss;  	__siginfo32_t		info; -	/* __siginfo_fpu32_t * */ u32 fpu_save; +	/* __siginfo_fpu_t * */ u32 fpu_save;  	unsigned int		insns[2];  	unsigned int		extramask[_COMPAT_NSIG_WORDS - 1];  	unsigned int		extra_size; /* Should be sizeof(siginfo_extra_v8plus_t) */  	/* Only valid if (info.si_regs.psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS */  	siginfo_extra_v8plus_t	v8plus; -	__siginfo_fpu_t		fpu_state; -}; +	/* __siginfo_rwin_t * */u32 rwin_save; +} __attribute__((aligned(8)));  typedef struct compat_siginfo{  	int si_signo; @@ -110,18 +112,14 @@ struct rt_signal_frame32 {  	compat_siginfo_t	info;  	struct pt_regs32	regs;  	compat_sigset_t		mask; -	/* __siginfo_fpu32_t * */ u32 fpu_save; +	/* __siginfo_fpu_t * */ u32 fpu_save;  	unsigned int		insns[2];  	stack_t32		stack;  	unsigned int		extra_size; /* Should be sizeof(siginfo_extra_v8plus_t) */  	/* Only valid if (regs.psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS */  	siginfo_extra_v8plus_t	v8plus; -	__siginfo_fpu_t		fpu_state; -}; - -/* Align macros */ -#define SF_ALIGNEDSZ  (((sizeof(struct signal_frame32) + 15) & (~15))) -#define RT_ALIGNEDSZ  (((sizeof(struct rt_signal_frame32) + 15) & (~15))) +	/* __siginfo_rwin_t * */u32 rwin_save; +} __attribute__((aligned(8)));  int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)  { @@ -192,30 +190,13 @@ int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)  	return 0;  } -static int restore_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t __user *fpu) -{ -	unsigned long *fpregs = current_thread_info()->fpregs; -	unsigned long fprs; -	int err; -	 -	err = __get_user(fprs, &fpu->si_fprs); -	fprs_write(0); -	regs->tstate &= ~TSTATE_PEF; -	if (fprs & FPRS_DL) -		err |= copy_from_user(fpregs, &fpu->si_float_regs[0], (sizeof(unsigned int) * 32)); -	if (fprs & FPRS_DU) -		err |= copy_from_user(fpregs+16, &fpu->si_float_regs[32], (sizeof(unsigned int) * 32)); -	err |= __get_user(current_thread_info()->xfsr[0], &fpu->si_fsr); -	err |= __get_user(current_thread_info()->gsr[0], &fpu->si_gsr); -	current_thread_info()->fpsaved[0] |= fprs; -	return err; -} -  void do_sigreturn32(struct pt_regs *regs)  {  	struct signal_frame32 __user *sf; +	compat_uptr_t fpu_save; +	compat_uptr_t rwin_save;  	unsigned int psr; -	unsigned pc, npc, fpu_save; +	unsigned pc, npc;  	sigset_t set;  	unsigned seta[_COMPAT_NSIG_WORDS];  	int err, i; @@ -273,8 +254,13 @@ void do_sigreturn32(struct pt_regs *regs)  	pt_regs_clear_syscall(regs);  	err |= __get_user(fpu_save, &sf->fpu_save); -	if (fpu_save) -		err |= restore_fpu_state32(regs, &sf->fpu_state); +	if (!err && fpu_save) +		err |= restore_fpu_state(regs, compat_ptr(fpu_save)); +	err |= __get_user(rwin_save, &sf->rwin_save); +	if (!err && rwin_save) { +		if (restore_rwin_state(compat_ptr(rwin_save))) +			goto segv; +	}  	err |= __get_user(seta[0], &sf->info.si_mask);  	err |= copy_from_user(seta+1, &sf->extramask,  			      (_COMPAT_NSIG_WORDS - 1) * sizeof(unsigned int)); @@ -287,10 +273,7 @@ void do_sigreturn32(struct pt_regs *regs)  		case 1: set.sig[0] = seta[0] + (((long)seta[1]) << 32);  	}  	sigdelsetmask(&set, ~_BLOCKABLE); -	spin_lock_irq(¤t->sighand->siglock); -	current->blocked = set; -	recalc_sigpending(); -	spin_unlock_irq(¤t->sighand->siglock); +	set_current_blocked(&set);  	return;  segv: @@ -300,7 +283,9 @@ segv:  asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)  {  	struct rt_signal_frame32 __user *sf; -	unsigned int psr, pc, npc, fpu_save, u_ss_sp; +	unsigned int psr, pc, npc, u_ss_sp; +	compat_uptr_t fpu_save; +	compat_uptr_t rwin_save;  	mm_segment_t old_fs;  	sigset_t set;  	compat_sigset_t seta; @@ -359,8 +344,8 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)  	pt_regs_clear_syscall(regs);  	err |= __get_user(fpu_save, &sf->fpu_save); -	if (fpu_save) -		err |= restore_fpu_state32(regs, &sf->fpu_state); +	if (!err && fpu_save) +		err |= restore_fpu_state(regs, compat_ptr(fpu_save));  	err |= copy_from_user(&seta, &sf->mask, sizeof(compat_sigset_t));  	err |= __get_user(u_ss_sp, &sf->stack.ss_sp);  	st.ss_sp = compat_ptr(u_ss_sp); @@ -376,6 +361,12 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)  	do_sigaltstack((stack_t __user *) &st, NULL, (unsigned long)sf);  	set_fs(old_fs); +	err |= __get_user(rwin_save, &sf->rwin_save); +	if (!err && rwin_save) { +		if (restore_rwin_state(compat_ptr(rwin_save))) +			goto segv; +	} +  	switch (_NSIG_WORDS) {  		case 4: set.sig[3] = seta.sig[6] + (((long)seta.sig[7]) << 32);  		case 3: set.sig[2] = seta.sig[4] + (((long)seta.sig[5]) << 32); @@ -383,10 +374,7 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)  		case 1: set.sig[0] = seta.sig[0] + (((long)seta.sig[1]) << 32);  	}  	sigdelsetmask(&set, ~_BLOCKABLE); -	spin_lock_irq(¤t->sighand->siglock); -	current->blocked = set; -	recalc_sigpending(); -	spin_unlock_irq(¤t->sighand->siglock); +	set_current_blocked(&set);  	return;  segv:  	force_sig(SIGSEGV, current); @@ -433,26 +421,6 @@ static void __user *get_sigframe(struct sigaction *sa, struct pt_regs *regs, uns  	return (void __user *) sp;  } -static int save_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t __user *fpu) -{ -	unsigned long *fpregs = current_thread_info()->fpregs; -	unsigned long fprs; -	int err = 0; -	 -	fprs = current_thread_info()->fpsaved[0]; -	if (fprs & FPRS_DL) -		err |= copy_to_user(&fpu->si_float_regs[0], fpregs, -				    (sizeof(unsigned int) * 32)); -	if (fprs & FPRS_DU) -		err |= copy_to_user(&fpu->si_float_regs[32], fpregs+16, -				    (sizeof(unsigned int) * 32)); -	err |= __put_user(current_thread_info()->xfsr[0], &fpu->si_fsr); -	err |= __put_user(current_thread_info()->gsr[0], &fpu->si_gsr); -	err |= __put_user(fprs, &fpu->si_fprs); - -	return err; -} -  /* The I-cache flush instruction only works in the primary ASI, which   * right now is the nucleus, aka. kernel space.   * @@ -515,18 +483,23 @@ static int setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,  			 int signo, sigset_t *oldset)  {  	struct signal_frame32 __user *sf; +	int i, err, wsaved; +	void __user *tail;  	int sigframe_size;  	u32 psr; -	int i, err;  	unsigned int seta[_COMPAT_NSIG_WORDS];  	/* 1. Make sure everything is clean */  	synchronize_user_stack();  	save_and_clear_fpu(); -	sigframe_size = SF_ALIGNEDSZ; -	if (!(current_thread_info()->fpsaved[0] & FPRS_FEF)) -		sigframe_size -= sizeof(__siginfo_fpu_t); +	wsaved = get_thread_wsaved(); + +	sigframe_size = sizeof(*sf); +	if (current_thread_info()->fpsaved[0] & FPRS_FEF) +		sigframe_size += sizeof(__siginfo_fpu_t); +	if (wsaved) +		sigframe_size += sizeof(__siginfo_rwin_t);  	sf = (struct signal_frame32 __user *)  		get_sigframe(&ka->sa, regs, sigframe_size); @@ -534,8 +507,7 @@ static int setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,  	if (invalid_frame_pointer(sf, sigframe_size))  		goto sigill; -	if (get_thread_wsaved() != 0) -		goto sigill; +	tail = (sf + 1);  	/* 2. Save the current process state */  	if (test_thread_flag(TIF_32BIT)) { @@ -560,11 +532,22 @@ static int setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,  			  &sf->v8plus.asi);  	if (psr & PSR_EF) { -		err |= save_fpu_state32(regs, &sf->fpu_state); -		err |= __put_user((u64)&sf->fpu_state, &sf->fpu_save); +		__siginfo_fpu_t __user *fp = tail; +		tail += sizeof(*fp); +		err |= save_fpu_state(regs, fp); +		err |= __put_user((u64)fp, &sf->fpu_save);  	} else {  		err |= __put_user(0, &sf->fpu_save);  	} +	if (wsaved) { +		__siginfo_rwin_t __user *rwp = tail; +		tail += sizeof(*rwp); +		err |= save_rwin_state(wsaved, rwp); +		err |= __put_user((u64)rwp, &sf->rwin_save); +		set_thread_wsaved(0); +	} else { +		err |= __put_user(0, &sf->rwin_save); +	}  	switch (_NSIG_WORDS) {  	case 4: seta[7] = (oldset->sig[3] >> 32); @@ -580,10 +563,21 @@ static int setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,  	err |= __copy_to_user(sf->extramask, seta + 1,  			      (_COMPAT_NSIG_WORDS - 1) * sizeof(unsigned int)); -	err |= copy_in_user((u32 __user *)sf, -			    (u32 __user *)(regs->u_regs[UREG_FP]), -			    sizeof(struct reg_window32)); -	 +	if (!wsaved) { +		err |= copy_in_user((u32 __user *)sf, +				    (u32 __user *)(regs->u_regs[UREG_FP]), +				    sizeof(struct reg_window32)); +	} else { +		struct reg_window *rp; + +		rp = ¤t_thread_info()->reg_window[wsaved - 1]; +		for (i = 0; i < 8; i++) +			err |= __put_user(rp->locals[i], &sf->ss.locals[i]); +		for (i = 0; i < 6; i++) +			err |= __put_user(rp->ins[i], &sf->ss.ins[i]); +		err |= __put_user(rp->ins[6], &sf->ss.fp); +		err |= __put_user(rp->ins[7], &sf->ss.callers_pc); +	}	  	if (err)  		goto sigsegv; @@ -613,7 +607,6 @@ static int setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,  		err |= __put_user(0x91d02010, &sf->insns[1]); /*t 0x10*/  		if (err)  			goto sigsegv; -  		flush_signal_insns(address);  	}  	return 0; @@ -632,18 +625,23 @@ static int setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,  			    siginfo_t *info)  {  	struct rt_signal_frame32 __user *sf; +	int i, err, wsaved; +	void __user *tail;  	int sigframe_size;  	u32 psr; -	int i, err;  	compat_sigset_t seta;  	/* 1. Make sure everything is clean */  	synchronize_user_stack();  	save_and_clear_fpu(); -	sigframe_size = RT_ALIGNEDSZ; -	if (!(current_thread_info()->fpsaved[0] & FPRS_FEF)) -		sigframe_size -= sizeof(__siginfo_fpu_t); +	wsaved = get_thread_wsaved(); + +	sigframe_size = sizeof(*sf); +	if (current_thread_info()->fpsaved[0] & FPRS_FEF) +		sigframe_size += sizeof(__siginfo_fpu_t); +	if (wsaved) +		sigframe_size += sizeof(__siginfo_rwin_t);  	sf = (struct rt_signal_frame32 __user *)  		get_sigframe(&ka->sa, regs, sigframe_size); @@ -651,8 +649,7 @@ static int setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,  	if (invalid_frame_pointer(sf, sigframe_size))  		goto sigill; -	if (get_thread_wsaved() != 0) -		goto sigill; +	tail = (sf + 1);  	/* 2. Save the current process state */  	if (test_thread_flag(TIF_32BIT)) { @@ -677,11 +674,22 @@ static int setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,  			  &sf->v8plus.asi);  	if (psr & PSR_EF) { -		err |= save_fpu_state32(regs, &sf->fpu_state); -		err |= __put_user((u64)&sf->fpu_state, &sf->fpu_save); +		__siginfo_fpu_t __user *fp = tail; +		tail += sizeof(*fp); +		err |= save_fpu_state(regs, fp); +		err |= __put_user((u64)fp, &sf->fpu_save);  	} else {  		err |= __put_user(0, &sf->fpu_save);  	} +	if (wsaved) { +		__siginfo_rwin_t __user *rwp = tail; +		tail += sizeof(*rwp); +		err |= save_rwin_state(wsaved, rwp); +		err |= __put_user((u64)rwp, &sf->rwin_save); +		set_thread_wsaved(0); +	} else { +		err |= __put_user(0, &sf->rwin_save); +	}  	/* Update the siginfo structure.  */  	err |= copy_siginfo_to_user32(&sf->info, info); @@ -703,9 +711,21 @@ static int setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,  	}  	err |= __copy_to_user(&sf->mask, &seta, sizeof(compat_sigset_t)); -	err |= copy_in_user((u32 __user *)sf, -			    (u32 __user *)(regs->u_regs[UREG_FP]), -			    sizeof(struct reg_window32)); +	if (!wsaved) { +		err |= copy_in_user((u32 __user *)sf, +				    (u32 __user *)(regs->u_regs[UREG_FP]), +				    sizeof(struct reg_window32)); +	} else { +		struct reg_window *rp; + +		rp = ¤t_thread_info()->reg_window[wsaved - 1]; +		for (i = 0; i < 8; i++) +			err |= __put_user(rp->locals[i], &sf->ss.locals[i]); +		for (i = 0; i < 6; i++) +			err |= __put_user(rp->ins[i], &sf->ss.ins[i]); +		err |= __put_user(rp->ins[6], &sf->ss.fp); +		err |= __put_user(rp->ins[7], &sf->ss.callers_pc); +	}  	if (err)  		goto sigsegv; @@ -756,6 +776,7 @@ static inline int handle_signal32(unsigned long signr, struct k_sigaction *ka,  				  siginfo_t *info,  				  sigset_t *oldset, struct pt_regs *regs)  { +	sigset_t blocked;  	int err;  	if (ka->sa.sa_flags & SA_SIGINFO) @@ -766,12 +787,10 @@ static inline int handle_signal32(unsigned long signr, struct k_sigaction *ka,  	if (err)  		return err; -	spin_lock_irq(¤t->sighand->siglock); -	sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); +	sigorsets(&blocked, ¤t->blocked, &ka->sa.sa_mask);  	if (!(ka->sa.sa_flags & SA_NOMASK)) -		sigaddset(¤t->blocked,signr); -	recalc_sigpending(); -	spin_unlock_irq(¤t->sighand->siglock); +		sigaddset(&blocked, signr); +	set_current_blocked(&blocked);  	tracehook_signal_handler(signr, info, ka, regs, 0); @@ -855,7 +874,7 @@ void do_signal32(sigset_t *oldset, struct pt_regs * regs,  	 */  	if (current_thread_info()->status & TS_RESTORE_SIGMASK) {  		current_thread_info()->status &= ~TS_RESTORE_SIGMASK; -		sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); +		set_current_blocked(¤t->saved_sigmask);  	}  } diff --git a/arch/sparc/kernel/signal_32.c b/arch/sparc/kernel/signal_32.c index 5e5c5fd0378..8ce247ac04c 100644 --- a/arch/sparc/kernel/signal_32.c +++ b/arch/sparc/kernel/signal_32.c @@ -26,6 +26,8 @@  #include <asm/pgtable.h>  #include <asm/cacheflush.h>	/* flush_sig_insns */ +#include "sigutil.h" +  #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))  extern void fpsave(unsigned long *fpregs, unsigned long *fsr, @@ -39,8 +41,8 @@ struct signal_frame {  	unsigned long		insns[2] __attribute__ ((aligned (8)));  	unsigned int		extramask[_NSIG_WORDS - 1];  	unsigned int		extra_size; /* Should be 0 */ -	__siginfo_fpu_t		fpu_state; -}; +	__siginfo_rwin_t __user	*rwin_save; +} __attribute__((aligned(8)));  struct rt_signal_frame {  	struct sparc_stackf	ss; @@ -51,8 +53,8 @@ struct rt_signal_frame {  	unsigned int		insns[2];  	stack_t			stack;  	unsigned int		extra_size; /* Should be 0 */ -	__siginfo_fpu_t		fpu_state; -}; +	__siginfo_rwin_t __user	*rwin_save; +} __attribute__((aligned(8)));  /* Align macros */  #define SF_ALIGNEDSZ  (((sizeof(struct signal_frame) + 7) & (~7))) @@ -60,12 +62,13 @@ struct rt_signal_frame {  static int _sigpause_common(old_sigset_t set)  { -	set &= _BLOCKABLE; -	spin_lock_irq(¤t->sighand->siglock); +	sigset_t blocked; +  	current->saved_sigmask = current->blocked; -	siginitset(¤t->blocked, set); -	recalc_sigpending(); -	spin_unlock_irq(¤t->sighand->siglock); + +	set &= _BLOCKABLE; +	siginitset(&blocked, set); +	set_current_blocked(&blocked);  	current->state = TASK_INTERRUPTIBLE;  	schedule(); @@ -79,43 +82,13 @@ asmlinkage int sys_sigsuspend(old_sigset_t set)  	return _sigpause_common(set);  } -static inline int -restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu) -{ -	int err; -#ifdef CONFIG_SMP -	if (test_tsk_thread_flag(current, TIF_USEDFPU)) -		regs->psr &= ~PSR_EF; -#else -	if (current == last_task_used_math) { -		last_task_used_math = NULL; -		regs->psr &= ~PSR_EF; -	} -#endif -	set_used_math(); -	clear_tsk_thread_flag(current, TIF_USEDFPU); - -	if (!access_ok(VERIFY_READ, fpu, sizeof(*fpu))) -		return -EFAULT; - -	err = __copy_from_user(¤t->thread.float_regs[0], &fpu->si_float_regs[0], -			       (sizeof(unsigned long) * 32)); -	err |= __get_user(current->thread.fsr, &fpu->si_fsr); -	err |= __get_user(current->thread.fpqdepth, &fpu->si_fpqdepth); -	if (current->thread.fpqdepth != 0) -		err |= __copy_from_user(¤t->thread.fpqueue[0], -					&fpu->si_fpqueue[0], -					((sizeof(unsigned long) + -					(sizeof(unsigned long *)))*16)); -	return err; -} -  asmlinkage void do_sigreturn(struct pt_regs *regs)  {  	struct signal_frame __user *sf;  	unsigned long up_psr, pc, npc;  	sigset_t set;  	__siginfo_fpu_t __user *fpu_save; +	__siginfo_rwin_t __user *rwin_save;  	int err;  	/* Always make any pending restarted system calls return -EINTR */ @@ -150,9 +123,11 @@ asmlinkage void do_sigreturn(struct pt_regs *regs)  	pt_regs_clear_syscall(regs);  	err |= __get_user(fpu_save, &sf->fpu_save); -  	if (fpu_save)  		err |= restore_fpu_state(regs, fpu_save); +	err |= __get_user(rwin_save, &sf->rwin_save); +	if (rwin_save) +		err |= restore_rwin_state(rwin_save);  	/* This is pretty much atomic, no amount locking would prevent  	 * the races which exist anyways. @@ -165,10 +140,7 @@ asmlinkage void do_sigreturn(struct pt_regs *regs)  		goto segv_and_exit;  	sigdelsetmask(&set, ~_BLOCKABLE); -	spin_lock_irq(¤t->sighand->siglock); -	current->blocked = set; -	recalc_sigpending(); -	spin_unlock_irq(¤t->sighand->siglock); +	set_current_blocked(&set);  	return;  segv_and_exit: @@ -180,6 +152,7 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs)  	struct rt_signal_frame __user *sf;  	unsigned int psr, pc, npc;  	__siginfo_fpu_t __user *fpu_save; +	__siginfo_rwin_t __user *rwin_save;  	mm_segment_t old_fs;  	sigset_t set;  	stack_t st; @@ -207,8 +180,7 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs)  	pt_regs_clear_syscall(regs);  	err |= __get_user(fpu_save, &sf->fpu_save); - -	if (fpu_save) +	if (!err && fpu_save)  		err |= restore_fpu_state(regs, fpu_save);  	err |= __copy_from_user(&set, &sf->mask, sizeof(sigset_t)); @@ -228,11 +200,14 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs)  	do_sigaltstack((const stack_t __user *) &st, NULL, (unsigned long)sf);  	set_fs(old_fs); +	err |= __get_user(rwin_save, &sf->rwin_save); +	if (!err && rwin_save) { +		if (restore_rwin_state(rwin_save)) +			goto segv; +	} +  	sigdelsetmask(&set, ~_BLOCKABLE); -	spin_lock_irq(¤t->sighand->siglock); -	current->blocked = set; -	recalc_sigpending(); -	spin_unlock_irq(¤t->sighand->siglock); +	set_current_blocked(&set);  	return;  segv:  	force_sig(SIGSEGV, current); @@ -280,53 +255,23 @@ static inline void __user *get_sigframe(struct sigaction *sa, struct pt_regs *re  	return (void __user *) sp;  } -static inline int -save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu) -{ -	int err = 0; -#ifdef CONFIG_SMP -	if (test_tsk_thread_flag(current, TIF_USEDFPU)) { -		put_psr(get_psr() | PSR_EF); -		fpsave(¤t->thread.float_regs[0], ¤t->thread.fsr, -		       ¤t->thread.fpqueue[0], ¤t->thread.fpqdepth); -		regs->psr &= ~(PSR_EF); -		clear_tsk_thread_flag(current, TIF_USEDFPU); -	} -#else -	if (current == last_task_used_math) { -		put_psr(get_psr() | PSR_EF); -		fpsave(¤t->thread.float_regs[0], ¤t->thread.fsr, -		       ¤t->thread.fpqueue[0], ¤t->thread.fpqdepth); -		last_task_used_math = NULL; -		regs->psr &= ~(PSR_EF); -	} -#endif -	err |= __copy_to_user(&fpu->si_float_regs[0], -			      ¤t->thread.float_regs[0], -			      (sizeof(unsigned long) * 32)); -	err |= __put_user(current->thread.fsr, &fpu->si_fsr); -	err |= __put_user(current->thread.fpqdepth, &fpu->si_fpqdepth); -	if (current->thread.fpqdepth != 0) -		err |= __copy_to_user(&fpu->si_fpqueue[0], -				      ¤t->thread.fpqueue[0], -				      ((sizeof(unsigned long) + -				      (sizeof(unsigned long *)))*16)); -	clear_used_math(); -	return err; -} -  static int setup_frame(struct k_sigaction *ka, struct pt_regs *regs,  		       int signo, sigset_t *oldset)  {  	struct signal_frame __user *sf; -	int sigframe_size, err; +	int sigframe_size, err, wsaved; +	void __user *tail;  	/* 1. Make sure everything is clean */  	synchronize_user_stack(); -	sigframe_size = SF_ALIGNEDSZ; -	if (!used_math()) -		sigframe_size -= sizeof(__siginfo_fpu_t); +	wsaved = current_thread_info()->w_saved; + +	sigframe_size = sizeof(*sf); +	if (used_math()) +		sigframe_size += sizeof(__siginfo_fpu_t); +	if (wsaved) +		sigframe_size += sizeof(__siginfo_rwin_t);  	sf = (struct signal_frame __user *)  		get_sigframe(&ka->sa, regs, sigframe_size); @@ -334,8 +279,7 @@ static int setup_frame(struct k_sigaction *ka, struct pt_regs *regs,  	if (invalid_frame_pointer(sf, sigframe_size))  		goto sigill_and_return; -	if (current_thread_info()->w_saved != 0) -		goto sigill_and_return; +	tail = sf + 1;  	/* 2. Save the current process state */  	err = __copy_to_user(&sf->info.si_regs, regs, sizeof(struct pt_regs)); @@ -343,17 +287,34 @@ static int setup_frame(struct k_sigaction *ka, struct pt_regs *regs,  	err |= __put_user(0, &sf->extra_size);  	if (used_math()) { -		err |= save_fpu_state(regs, &sf->fpu_state); -		err |= __put_user(&sf->fpu_state, &sf->fpu_save); +		__siginfo_fpu_t __user *fp = tail; +		tail += sizeof(*fp); +		err |= save_fpu_state(regs, fp); +		err |= __put_user(fp, &sf->fpu_save);  	} else {  		err |= __put_user(0, &sf->fpu_save);  	} +	if (wsaved) { +		__siginfo_rwin_t __user *rwp = tail; +		tail += sizeof(*rwp); +		err |= save_rwin_state(wsaved, rwp); +		err |= __put_user(rwp, &sf->rwin_save); +	} else { +		err |= __put_user(0, &sf->rwin_save); +	}  	err |= __put_user(oldset->sig[0], &sf->info.si_mask);  	err |= __copy_to_user(sf->extramask, &oldset->sig[1],  			      (_NSIG_WORDS - 1) * sizeof(unsigned int)); -	err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP], -			      sizeof(struct reg_window32)); +	if (!wsaved) { +		err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP], +				      sizeof(struct reg_window32)); +	} else { +		struct reg_window32 *rp; + +		rp = ¤t_thread_info()->reg_window[wsaved - 1]; +		err |= __copy_to_user(sf, rp, sizeof(struct reg_window32)); +	}  	if (err)  		goto sigsegv; @@ -399,21 +360,24 @@ static int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,  			  int signo, sigset_t *oldset, siginfo_t *info)  {  	struct rt_signal_frame __user *sf; -	int sigframe_size; +	int sigframe_size, wsaved; +	void __user *tail;  	unsigned int psr;  	int err;  	synchronize_user_stack(); -	sigframe_size = RT_ALIGNEDSZ; -	if (!used_math()) -		sigframe_size -= sizeof(__siginfo_fpu_t); +	wsaved = current_thread_info()->w_saved; +	sigframe_size = sizeof(*sf); +	if (used_math()) +		sigframe_size += sizeof(__siginfo_fpu_t); +	if (wsaved) +		sigframe_size += sizeof(__siginfo_rwin_t);  	sf = (struct rt_signal_frame __user *)  		get_sigframe(&ka->sa, regs, sigframe_size);  	if (invalid_frame_pointer(sf, sigframe_size))  		goto sigill; -	if (current_thread_info()->w_saved != 0) -		goto sigill; +	tail = sf + 1;  	err  = __put_user(regs->pc, &sf->regs.pc);  	err |= __put_user(regs->npc, &sf->regs.npc);  	err |= __put_user(regs->y, &sf->regs.y); @@ -425,11 +389,21 @@ static int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,  	err |= __put_user(0, &sf->extra_size);  	if (psr & PSR_EF) { -		err |= save_fpu_state(regs, &sf->fpu_state); -		err |= __put_user(&sf->fpu_state, &sf->fpu_save); +		__siginfo_fpu_t *fp = tail; +		tail += sizeof(*fp); +		err |= save_fpu_state(regs, fp); +		err |= __put_user(fp, &sf->fpu_save);  	} else {  		err |= __put_user(0, &sf->fpu_save);  	} +	if (wsaved) { +		__siginfo_rwin_t *rwp = tail; +		tail += sizeof(*rwp); +		err |= save_rwin_state(wsaved, rwp); +		err |= __put_user(rwp, &sf->rwin_save); +	} else { +		err |= __put_user(0, &sf->rwin_save); +	}  	err |= __copy_to_user(&sf->mask, &oldset->sig[0], sizeof(sigset_t));  	/* Setup sigaltstack */ @@ -437,8 +411,15 @@ static int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,  	err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags);  	err |= __put_user(current->sas_ss_size, &sf->stack.ss_size); -	err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP], -			      sizeof(struct reg_window32)); +	if (!wsaved) { +		err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP], +				      sizeof(struct reg_window32)); +	} else { +		struct reg_window32 *rp; + +		rp = ¤t_thread_info()->reg_window[wsaved - 1]; +		err |= __copy_to_user(sf, rp, sizeof(struct reg_window32)); +	}  	err |= copy_siginfo_to_user(&sf->info, info); @@ -484,6 +465,7 @@ static inline int  handle_signal(unsigned long signr, struct k_sigaction *ka,  	      siginfo_t *info, sigset_t *oldset, struct pt_regs *regs)  { +	sigset_t blocked;  	int err;  	if (ka->sa.sa_flags & SA_SIGINFO) @@ -494,12 +476,10 @@ handle_signal(unsigned long signr, struct k_sigaction *ka,  	if (err)  		return err; -	spin_lock_irq(¤t->sighand->siglock); -	sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); +	sigorsets(&blocked, ¤t->blocked, &ka->sa.sa_mask);  	if (!(ka->sa.sa_flags & SA_NOMASK)) -		sigaddset(¤t->blocked, signr); -	recalc_sigpending(); -	spin_unlock_irq(¤t->sighand->siglock); +		sigaddset(&blocked, signr); +	set_current_blocked(&blocked);  	tracehook_signal_handler(signr, info, ka, regs, 0); @@ -595,7 +575,7 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0)  	 */  	if (test_thread_flag(TIF_RESTORE_SIGMASK)) {  		clear_thread_flag(TIF_RESTORE_SIGMASK); -		sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); +		set_current_blocked(¤t->saved_sigmask);  	}  } diff --git a/arch/sparc/kernel/signal_64.c b/arch/sparc/kernel/signal_64.c index 006fe451588..a2b81598d90 100644 --- a/arch/sparc/kernel/signal_64.c +++ b/arch/sparc/kernel/signal_64.c @@ -34,6 +34,7 @@  #include "entry.h"  #include "systbls.h" +#include "sigutil.h"  #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) @@ -69,10 +70,7 @@ asmlinkage void sparc64_set_context(struct pt_regs *regs)  				goto do_sigsegv;  		}  		sigdelsetmask(&set, ~_BLOCKABLE); -		spin_lock_irq(¤t->sighand->siglock); -		current->blocked = set; -		recalc_sigpending(); -		spin_unlock_irq(¤t->sighand->siglock); +		set_current_blocked(&set);  	}  	if (test_thread_flag(TIF_32BIT)) {  		pc &= 0xffffffff; @@ -236,17 +234,18 @@ struct rt_signal_frame {  	__siginfo_fpu_t __user	*fpu_save;  	stack_t			stack;  	sigset_t		mask; -	__siginfo_fpu_t		fpu_state; +	__siginfo_rwin_t	*rwin_save;  };  static long _sigpause_common(old_sigset_t set)  { -	set &= _BLOCKABLE; -	spin_lock_irq(¤t->sighand->siglock); +	sigset_t blocked; +  	current->saved_sigmask = current->blocked; -	siginitset(¤t->blocked, set); -	recalc_sigpending(); -	spin_unlock_irq(¤t->sighand->siglock); + +	set &= _BLOCKABLE; +	siginitset(&blocked, set); +	set_current_blocked(&blocked);  	current->state = TASK_INTERRUPTIBLE;  	schedule(); @@ -266,33 +265,12 @@ asmlinkage long sys_sigsuspend(old_sigset_t set)  	return _sigpause_common(set);  } -static inline int -restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu) -{ -	unsigned long *fpregs = current_thread_info()->fpregs; -	unsigned long fprs; -	int err; - -	err = __get_user(fprs, &fpu->si_fprs); -	fprs_write(0); -	regs->tstate &= ~TSTATE_PEF; -	if (fprs & FPRS_DL) -		err |= copy_from_user(fpregs, &fpu->si_float_regs[0], -		       	       (sizeof(unsigned int) * 32)); -	if (fprs & FPRS_DU) -		err |= copy_from_user(fpregs+16, &fpu->si_float_regs[32], -		       	       (sizeof(unsigned int) * 32)); -	err |= __get_user(current_thread_info()->xfsr[0], &fpu->si_fsr); -	err |= __get_user(current_thread_info()->gsr[0], &fpu->si_gsr); -	current_thread_info()->fpsaved[0] |= fprs; -	return err; -} -  void do_rt_sigreturn(struct pt_regs *regs)  {  	struct rt_signal_frame __user *sf;  	unsigned long tpc, tnpc, tstate;  	__siginfo_fpu_t __user *fpu_save; +	__siginfo_rwin_t __user *rwin_save;  	sigset_t set;  	int err; @@ -325,8 +303,8 @@ void do_rt_sigreturn(struct pt_regs *regs)  	regs->tstate |= (tstate & (TSTATE_ASI | TSTATE_ICC | TSTATE_XCC));  	err |= __get_user(fpu_save, &sf->fpu_save); -	if (fpu_save) -		err |= restore_fpu_state(regs, &sf->fpu_state); +	if (!err && fpu_save) +		err |= restore_fpu_state(regs, fpu_save);  	err |= __copy_from_user(&set, &sf->mask, sizeof(sigset_t));  	err |= do_sigaltstack(&sf->stack, NULL, (unsigned long)sf); @@ -334,6 +312,12 @@ void do_rt_sigreturn(struct pt_regs *regs)  	if (err)  		goto segv; +	err |= __get_user(rwin_save, &sf->rwin_save); +	if (!err && rwin_save) { +		if (restore_rwin_state(rwin_save)) +			goto segv; +	} +  	regs->tpc = tpc;  	regs->tnpc = tnpc; @@ -341,44 +325,20 @@ void do_rt_sigreturn(struct pt_regs *regs)  	pt_regs_clear_syscall(regs);  	sigdelsetmask(&set, ~_BLOCKABLE); -	spin_lock_irq(¤t->sighand->siglock); -	current->blocked = set; -	recalc_sigpending(); -	spin_unlock_irq(¤t->sighand->siglock); +	set_current_blocked(&set);  	return;  segv:  	force_sig(SIGSEGV, current);  }  /* Checks if the fp is valid */ -static int invalid_frame_pointer(void __user *fp, int fplen) +static int invalid_frame_pointer(void __user *fp)  {  	if (((unsigned long) fp) & 15)  		return 1;  	return 0;  } -static inline int -save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu) -{ -	unsigned long *fpregs = current_thread_info()->fpregs; -	unsigned long fprs; -	int err = 0; -	 -	fprs = current_thread_info()->fpsaved[0]; -	if (fprs & FPRS_DL) -		err |= copy_to_user(&fpu->si_float_regs[0], fpregs, -				    (sizeof(unsigned int) * 32)); -	if (fprs & FPRS_DU) -		err |= copy_to_user(&fpu->si_float_regs[32], fpregs+16, -				    (sizeof(unsigned int) * 32)); -	err |= __put_user(current_thread_info()->xfsr[0], &fpu->si_fsr); -	err |= __put_user(current_thread_info()->gsr[0], &fpu->si_gsr); -	err |= __put_user(fprs, &fpu->si_fprs); - -	return err; -} -  static inline void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, unsigned long framesize)  {  	unsigned long sp = regs->u_regs[UREG_FP] + STACK_BIAS; @@ -414,34 +374,48 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,  	       int signo, sigset_t *oldset, siginfo_t *info)  {  	struct rt_signal_frame __user *sf; -	int sigframe_size, err; +	int wsaved, err, sf_size; +	void __user *tail;  	/* 1. Make sure everything is clean */  	synchronize_user_stack();  	save_and_clear_fpu(); -	sigframe_size = sizeof(struct rt_signal_frame); -	if (!(current_thread_info()->fpsaved[0] & FPRS_FEF)) -		sigframe_size -= sizeof(__siginfo_fpu_t); +	wsaved = get_thread_wsaved(); +	sf_size = sizeof(struct rt_signal_frame); +	if (current_thread_info()->fpsaved[0] & FPRS_FEF) +		sf_size += sizeof(__siginfo_fpu_t); +	if (wsaved) +		sf_size += sizeof(__siginfo_rwin_t);  	sf = (struct rt_signal_frame __user *) -		get_sigframe(ka, regs, sigframe_size); -	 -	if (invalid_frame_pointer (sf, sigframe_size)) -		goto sigill; +		get_sigframe(ka, regs, sf_size); -	if (get_thread_wsaved() != 0) +	if (invalid_frame_pointer (sf))  		goto sigill; +	tail = (sf + 1); +  	/* 2. Save the current process state */  	err = copy_to_user(&sf->regs, regs, sizeof (*regs));  	if (current_thread_info()->fpsaved[0] & FPRS_FEF) { -		err |= save_fpu_state(regs, &sf->fpu_state); -		err |= __put_user((u64)&sf->fpu_state, &sf->fpu_save); +		__siginfo_fpu_t __user *fpu_save = tail; +		tail += sizeof(__siginfo_fpu_t); +		err |= save_fpu_state(regs, fpu_save); +		err |= __put_user((u64)fpu_save, &sf->fpu_save);  	} else {  		err |= __put_user(0, &sf->fpu_save);  	} +	if (wsaved) { +		__siginfo_rwin_t __user *rwin_save = tail; +		tail += sizeof(__siginfo_rwin_t); +		err |= save_rwin_state(wsaved, rwin_save); +		err |= __put_user((u64)rwin_save, &sf->rwin_save); +		set_thread_wsaved(0); +	} else { +		err |= __put_user(0, &sf->rwin_save); +	}  	/* Setup sigaltstack */  	err |= __put_user(current->sas_ss_sp, &sf->stack.ss_sp); @@ -450,10 +424,17 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,  	err |= copy_to_user(&sf->mask, oldset, sizeof(sigset_t)); -	err |= copy_in_user((u64 __user *)sf, -			    (u64 __user *)(regs->u_regs[UREG_FP]+STACK_BIAS), -			    sizeof(struct reg_window)); +	if (!wsaved) { +		err |= copy_in_user((u64 __user *)sf, +				    (u64 __user *)(regs->u_regs[UREG_FP] + +						   STACK_BIAS), +				    sizeof(struct reg_window)); +	} else { +		struct reg_window *rp; +		rp = ¤t_thread_info()->reg_window[wsaved - 1]; +		err |= copy_to_user(sf, rp, sizeof(struct reg_window)); +	}  	if (info)  		err |= copy_siginfo_to_user(&sf->info, info);  	else { @@ -498,18 +479,17 @@ static inline int handle_signal(unsigned long signr, struct k_sigaction *ka,  				siginfo_t *info,  				sigset_t *oldset, struct pt_regs *regs)  { +	sigset_t blocked;  	int err;  	err = setup_rt_frame(ka, regs, signr, oldset,  			     (ka->sa.sa_flags & SA_SIGINFO) ? info : NULL);  	if (err)  		return err; -	spin_lock_irq(¤t->sighand->siglock); -	sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); +	sigorsets(&blocked, ¤t->blocked, &ka->sa.sa_mask);  	if (!(ka->sa.sa_flags & SA_NOMASK)) -		sigaddset(¤t->blocked,signr); -	recalc_sigpending(); -	spin_unlock_irq(¤t->sighand->siglock); +		sigaddset(&blocked, signr); +	set_current_blocked(&blocked);  	tracehook_signal_handler(signr, info, ka, regs, 0); @@ -615,7 +595,7 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0)  	 */  	if (current_thread_info()->status & TS_RESTORE_SIGMASK) {  		current_thread_info()->status &= ~TS_RESTORE_SIGMASK; -		sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); +		set_current_blocked(¤t->saved_sigmask);  	}  } diff --git a/arch/sparc/kernel/sigutil.h b/arch/sparc/kernel/sigutil.h new file mode 100644 index 00000000000..d223aa432bb --- /dev/null +++ b/arch/sparc/kernel/sigutil.h @@ -0,0 +1,9 @@ +#ifndef _SIGUTIL_H +#define _SIGUTIL_H + +int save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu); +int restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu); +int save_rwin_state(int wsaved, __siginfo_rwin_t __user *rwin); +int restore_rwin_state(__siginfo_rwin_t __user *rp); + +#endif /* _SIGUTIL_H */ diff --git a/arch/sparc/kernel/sigutil_32.c b/arch/sparc/kernel/sigutil_32.c new file mode 100644 index 00000000000..35c7897b009 --- /dev/null +++ b/arch/sparc/kernel/sigutil_32.c @@ -0,0 +1,120 @@ +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/thread_info.h> +#include <linux/uaccess.h> +#include <linux/sched.h> + +#include <asm/sigcontext.h> +#include <asm/fpumacro.h> +#include <asm/ptrace.h> + +#include "sigutil.h" + +int save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu) +{ +	int err = 0; +#ifdef CONFIG_SMP +	if (test_tsk_thread_flag(current, TIF_USEDFPU)) { +		put_psr(get_psr() | PSR_EF); +		fpsave(¤t->thread.float_regs[0], ¤t->thread.fsr, +		       ¤t->thread.fpqueue[0], ¤t->thread.fpqdepth); +		regs->psr &= ~(PSR_EF); +		clear_tsk_thread_flag(current, TIF_USEDFPU); +	} +#else +	if (current == last_task_used_math) { +		put_psr(get_psr() | PSR_EF); +		fpsave(¤t->thread.float_regs[0], ¤t->thread.fsr, +		       ¤t->thread.fpqueue[0], ¤t->thread.fpqdepth); +		last_task_used_math = NULL; +		regs->psr &= ~(PSR_EF); +	} +#endif +	err |= __copy_to_user(&fpu->si_float_regs[0], +			      ¤t->thread.float_regs[0], +			      (sizeof(unsigned long) * 32)); +	err |= __put_user(current->thread.fsr, &fpu->si_fsr); +	err |= __put_user(current->thread.fpqdepth, &fpu->si_fpqdepth); +	if (current->thread.fpqdepth != 0) +		err |= __copy_to_user(&fpu->si_fpqueue[0], +				      ¤t->thread.fpqueue[0], +				      ((sizeof(unsigned long) + +				      (sizeof(unsigned long *)))*16)); +	clear_used_math(); +	return err; +} + +int restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu) +{ +	int err; +#ifdef CONFIG_SMP +	if (test_tsk_thread_flag(current, TIF_USEDFPU)) +		regs->psr &= ~PSR_EF; +#else +	if (current == last_task_used_math) { +		last_task_used_math = NULL; +		regs->psr &= ~PSR_EF; +	} +#endif +	set_used_math(); +	clear_tsk_thread_flag(current, TIF_USEDFPU); + +	if (!access_ok(VERIFY_READ, fpu, sizeof(*fpu))) +		return -EFAULT; + +	err = __copy_from_user(¤t->thread.float_regs[0], &fpu->si_float_regs[0], +			       (sizeof(unsigned long) * 32)); +	err |= __get_user(current->thread.fsr, &fpu->si_fsr); +	err |= __get_user(current->thread.fpqdepth, &fpu->si_fpqdepth); +	if (current->thread.fpqdepth != 0) +		err |= __copy_from_user(¤t->thread.fpqueue[0], +					&fpu->si_fpqueue[0], +					((sizeof(unsigned long) + +					(sizeof(unsigned long *)))*16)); +	return err; +} + +int save_rwin_state(int wsaved, __siginfo_rwin_t __user *rwin) +{ +	int i, err = __put_user(wsaved, &rwin->wsaved); + +	for (i = 0; i < wsaved; i++) { +		struct reg_window32 *rp; +		unsigned long fp; + +		rp = ¤t_thread_info()->reg_window[i]; +		fp = current_thread_info()->rwbuf_stkptrs[i]; +		err |= copy_to_user(&rwin->reg_window[i], rp, +				    sizeof(struct reg_window32)); +		err |= __put_user(fp, &rwin->rwbuf_stkptrs[i]); +	} +	return err; +} + +int restore_rwin_state(__siginfo_rwin_t __user *rp) +{ +	struct thread_info *t = current_thread_info(); +	int i, wsaved, err; + +	__get_user(wsaved, &rp->wsaved); +	if (wsaved > NSWINS) +		return -EFAULT; + +	err = 0; +	for (i = 0; i < wsaved; i++) { +		err |= copy_from_user(&t->reg_window[i], +				      &rp->reg_window[i], +				      sizeof(struct reg_window32)); +		err |= __get_user(t->rwbuf_stkptrs[i], +				  &rp->rwbuf_stkptrs[i]); +	} +	if (err) +		return err; + +	t->w_saved = wsaved; +	synchronize_user_stack(); +	if (t->w_saved) +		return -EFAULT; +	return 0; + +} diff --git a/arch/sparc/kernel/sigutil_64.c b/arch/sparc/kernel/sigutil_64.c new file mode 100644 index 00000000000..e7dc508c38e --- /dev/null +++ b/arch/sparc/kernel/sigutil_64.c @@ -0,0 +1,93 @@ +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/thread_info.h> +#include <linux/uaccess.h> + +#include <asm/sigcontext.h> +#include <asm/fpumacro.h> +#include <asm/ptrace.h> + +#include "sigutil.h" + +int save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu) +{ +	unsigned long *fpregs = current_thread_info()->fpregs; +	unsigned long fprs; +	int err = 0; +	 +	fprs = current_thread_info()->fpsaved[0]; +	if (fprs & FPRS_DL) +		err |= copy_to_user(&fpu->si_float_regs[0], fpregs, +				    (sizeof(unsigned int) * 32)); +	if (fprs & FPRS_DU) +		err |= copy_to_user(&fpu->si_float_regs[32], fpregs+16, +				    (sizeof(unsigned int) * 32)); +	err |= __put_user(current_thread_info()->xfsr[0], &fpu->si_fsr); +	err |= __put_user(current_thread_info()->gsr[0], &fpu->si_gsr); +	err |= __put_user(fprs, &fpu->si_fprs); + +	return err; +} + +int restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu) +{ +	unsigned long *fpregs = current_thread_info()->fpregs; +	unsigned long fprs; +	int err; + +	err = __get_user(fprs, &fpu->si_fprs); +	fprs_write(0); +	regs->tstate &= ~TSTATE_PEF; +	if (fprs & FPRS_DL) +		err |= copy_from_user(fpregs, &fpu->si_float_regs[0], +		       	       (sizeof(unsigned int) * 32)); +	if (fprs & FPRS_DU) +		err |= copy_from_user(fpregs+16, &fpu->si_float_regs[32], +		       	       (sizeof(unsigned int) * 32)); +	err |= __get_user(current_thread_info()->xfsr[0], &fpu->si_fsr); +	err |= __get_user(current_thread_info()->gsr[0], &fpu->si_gsr); +	current_thread_info()->fpsaved[0] |= fprs; +	return err; +} + +int save_rwin_state(int wsaved, __siginfo_rwin_t __user *rwin) +{ +	int i, err = __put_user(wsaved, &rwin->wsaved); + +	for (i = 0; i < wsaved; i++) { +		struct reg_window *rp = ¤t_thread_info()->reg_window[i]; +		unsigned long fp = current_thread_info()->rwbuf_stkptrs[i]; + +		err |= copy_to_user(&rwin->reg_window[i], rp, +				    sizeof(struct reg_window)); +		err |= __put_user(fp, &rwin->rwbuf_stkptrs[i]); +	} +	return err; +} + +int restore_rwin_state(__siginfo_rwin_t __user *rp) +{ +	struct thread_info *t = current_thread_info(); +	int i, wsaved, err; + +	__get_user(wsaved, &rp->wsaved); +	if (wsaved > NSWINS) +		return -EFAULT; + +	err = 0; +	for (i = 0; i < wsaved; i++) { +		err |= copy_from_user(&t->reg_window[i], +				      &rp->reg_window[i], +				      sizeof(struct reg_window)); +		err |= __get_user(t->rwbuf_stkptrs[i], +				  &rp->rwbuf_stkptrs[i]); +	} +	if (err) +		return err; + +	set_thread_wsaved(wsaved); +	synchronize_user_stack(); +	if (get_thread_wsaved()) +		return -EFAULT; +	return 0; +} diff --git a/arch/sparc/kernel/sys32.S b/arch/sparc/kernel/sys32.S index 44e5faf1ad5..d97f3eb72e0 100644 --- a/arch/sparc/kernel/sys32.S +++ b/arch/sparc/kernel/sys32.S @@ -81,7 +81,6 @@ SIGN2(sys32_fadvise64, compat_sys_fadvise64, %o0, %o4)  SIGN2(sys32_fadvise64_64, compat_sys_fadvise64_64, %o0, %o5)  SIGN2(sys32_bdflush, sys_bdflush, %o0, %o1)  SIGN1(sys32_mlockall, sys_mlockall, %o0) -SIGN1(sys32_nfsservctl, compat_sys_nfsservctl, %o0)  SIGN1(sys32_clock_nanosleep, compat_sys_clock_nanosleep, %o1)  SIGN1(sys32_timer_settime, compat_sys_timer_settime, %o1)  SIGN1(sys32_io_submit, compat_sys_io_submit, %o1) diff --git a/arch/sparc/kernel/systbls_32.S b/arch/sparc/kernel/systbls_32.S index 6e492d59f6b..09d8ec45445 100644 --- a/arch/sparc/kernel/systbls_32.S +++ b/arch/sparc/kernel/systbls_32.S @@ -67,7 +67,7 @@ sys_call_table:  /*235*/	.long sys_fstatfs64, sys_llseek, sys_mlock, sys_munlock, sys_mlockall  /*240*/	.long sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler  /*245*/	.long sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep -/*250*/	.long sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl +/*250*/	.long sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_ni_syscall  /*255*/	.long sys_sync_file_range, sys_clock_settime, sys_clock_gettime, sys_clock_getres, sys_clock_nanosleep  /*260*/	.long sys_sched_getaffinity, sys_sched_setaffinity, sys_timer_settime, sys_timer_gettime, sys_timer_getoverrun  /*265*/	.long sys_timer_delete, sys_timer_create, sys_nis_syscall, sys_io_setup, sys_io_destroy diff --git a/arch/sparc/kernel/systbls_64.S b/arch/sparc/kernel/systbls_64.S index f566518483b..edbec45d468 100644 --- a/arch/sparc/kernel/systbls_64.S +++ b/arch/sparc/kernel/systbls_64.S @@ -68,7 +68,7 @@ sys_call_table32:  	.word compat_sys_fstatfs64, sys_llseek, sys_mlock, sys_munlock, sys32_mlockall  /*240*/	.word sys_munlockall, sys32_sched_setparam, sys32_sched_getparam, sys32_sched_setscheduler, sys32_sched_getscheduler  	.word sys_sched_yield, sys32_sched_get_priority_max, sys32_sched_get_priority_min, sys32_sched_rr_get_interval, compat_sys_nanosleep -/*250*/	.word sys_mremap, compat_sys_sysctl, sys32_getsid, sys_fdatasync, sys32_nfsservctl +/*250*/	.word sys_mremap, compat_sys_sysctl, sys32_getsid, sys_fdatasync, sys_nis_syscall  	.word sys32_sync_file_range, compat_sys_clock_settime, compat_sys_clock_gettime, compat_sys_clock_getres, sys32_clock_nanosleep  /*260*/	.word compat_sys_sched_getaffinity, compat_sys_sched_setaffinity, sys32_timer_settime, compat_sys_timer_gettime, sys_timer_getoverrun  	.word sys_timer_delete, compat_sys_timer_create, sys_ni_syscall, compat_sys_io_setup, sys_io_destroy @@ -145,7 +145,7 @@ sys_call_table:  	.word sys_fstatfs64, sys_llseek, sys_mlock, sys_munlock, sys_mlockall  /*240*/	.word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler  	.word sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep -/*250*/	.word sys_64_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl +/*250*/	.word sys_64_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nis_syscall  	.word sys_sync_file_range, sys_clock_settime, sys_clock_gettime, sys_clock_getres, sys_clock_nanosleep  /*260*/	.word sys_sched_getaffinity, sys_sched_setaffinity, sys_timer_settime, sys_timer_gettime, sys_timer_getoverrun  	.word sys_timer_delete, sys_timer_create, sys_ni_syscall, sys_io_setup, sys_io_destroy diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c index 581531dbc8b..8e073d80213 100644 --- a/arch/sparc/mm/init_64.c +++ b/arch/sparc/mm/init_64.c @@ -511,6 +511,11 @@ static void __init read_obp_translations(void)  		for (i = 0; i < prom_trans_ents; i++)  			prom_trans[i].data &= ~0x0003fe0000000000UL;  	} + +	/* Force execute bit on.  */ +	for (i = 0; i < prom_trans_ents; i++) +		prom_trans[i].data |= (tlb_type == hypervisor ? +				       _PAGE_EXEC_4V : _PAGE_EXEC_4U);  }  static void __init hypervisor_tlb_lock(unsigned long vaddr, diff --git a/arch/sparc/mm/leon_mm.c b/arch/sparc/mm/leon_mm.c index e485a680499..13c2169822a 100644 --- a/arch/sparc/mm/leon_mm.c +++ b/arch/sparc/mm/leon_mm.c @@ -162,7 +162,7 @@ ready:  		printk(KERN_INFO "swprobe: padde %x\n", paddr_calc);  	if (paddr)  		*paddr = paddr_calc; -	return paddrbase; +	return pte;  }  void leon_flush_icache_all(void)  |