diff options
Diffstat (limited to 'arch/sparc/kernel')
| -rw-r--r-- | arch/sparc/kernel/Makefile | 1 | ||||
| -rw-r--r-- | arch/sparc/kernel/entry.S | 29 | ||||
| -rw-r--r-- | arch/sparc/kernel/kernel.h | 11 | ||||
| -rw-r--r-- | arch/sparc/kernel/leon_smp.c | 1 | ||||
| -rw-r--r-- | arch/sparc/kernel/process.c | 110 | ||||
| -rw-r--r-- | arch/sparc/kernel/process_32.c | 83 | ||||
| -rw-r--r-- | arch/sparc/kernel/process_64.c | 106 | ||||
| -rw-r--r-- | arch/sparc/kernel/ptrace_32.c | 269 | ||||
| -rw-r--r-- | arch/sparc/kernel/ptrace_64.c | 591 | ||||
| -rw-r--r-- | arch/sparc/kernel/setup_32.c | 2 | ||||
| -rw-r--r-- | arch/sparc/kernel/setup_64.c | 2 | ||||
| -rw-r--r-- | arch/sparc/kernel/signal_32.c | 1 | ||||
| -rw-r--r-- | arch/sparc/kernel/smp_32.c | 1 | ||||
| -rw-r--r-- | arch/sparc/kernel/smp_64.c | 1 | ||||
| -rw-r--r-- | arch/sparc/kernel/sun4m_irq.c | 1 | ||||
| -rw-r--r-- | arch/sparc/kernel/sys32.S | 12 | ||||
| -rw-r--r-- | arch/sparc/kernel/syscalls.S | 23 | ||||
| -rw-r--r-- | arch/sparc/kernel/syscalls/syscall.tbl | 7 | ||||
| -rw-r--r-- | arch/sparc/kernel/vdso.c | 1 | 
19 files changed, 586 insertions, 666 deletions
| diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile index 97c0e19263d1..d3a0e072ebe8 100644 --- a/arch/sparc/kernel/Makefile +++ b/arch/sparc/kernel/Makefile @@ -33,6 +33,7 @@ obj-y                   += irq_$(BITS).o  obj-$(CONFIG_SPARC32)   += sun4m_irq.o sun4d_irq.o  obj-y                   += process_$(BITS).o +obj-y                   += process.o  obj-y                   += signal_$(BITS).o  obj-y                   += sigutil_$(BITS).o  obj-$(CONFIG_SPARC32)   += ioport.o diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S index f636acf3312f..d58940280f8d 100644 --- a/arch/sparc/kernel/entry.S +++ b/arch/sparc/kernel/entry.S @@ -869,14 +869,11 @@ flush_patch_two:  	ld	[%curptr + TI_TASK], %o4  	rd	%psr, %g4  	WRITE_PAUSE -	mov	SIGCHLD, %o0			! arg0:	clone flags  	rd	%wim, %g5  	WRITE_PAUSE -	mov	%fp, %o1			! arg1:	usp  	std	%g4, [%o4 + AOFF_task_thread + AOFF_thread_fork_kpsr] -	add	%sp, STACKFRAME_SZ, %o2		! arg2:	pt_regs ptr -	mov	0, %o3 -	call	sparc_do_fork +	add	%sp, STACKFRAME_SZ, %o0 +	call	sparc_fork  	 mov	%l5, %o7  	/* Whee, kernel threads! */ @@ -888,19 +885,11 @@ flush_patch_three:  	ld	[%curptr + TI_TASK], %o4  	rd	%psr, %g4  	WRITE_PAUSE - -	/* arg0,1: flags,usp  -- loaded already */ -	cmp	%o1, 0x0			! Is new_usp NULL?  	rd	%wim, %g5  	WRITE_PAUSE -	be,a	1f -	 mov	%fp, %o1			! yes, use callers usp -	andn	%o1, 7, %o1			! no, align to 8 bytes -1:  	std	%g4, [%o4 + AOFF_task_thread + AOFF_thread_fork_kpsr] -	add	%sp, STACKFRAME_SZ, %o2		! arg2:	pt_regs ptr -	mov	0, %o3 -	call	sparc_do_fork +	add	%sp, STACKFRAME_SZ, %o0 +	call	sparc_clone  	 mov	%l5, %o7  	/* Whee, real vfork! */ @@ -914,13 +903,9 @@ flush_patch_four:  	rd	%wim, %g5  	WRITE_PAUSE  	std	%g4, [%o4 + AOFF_task_thread + AOFF_thread_fork_kpsr] -	sethi	%hi(0x4000 | 0x0100 | SIGCHLD), %o0 -	mov	%fp, %o1 -	or	%o0, %lo(0x4000 | 0x0100 | SIGCHLD), %o0 -	sethi	%hi(sparc_do_fork), %l1 -	mov	0, %o3 -	jmpl	%l1 + %lo(sparc_do_fork), %g0 -	 add	%sp, STACKFRAME_SZ, %o2 +	sethi	%hi(sparc_vfork), %l1 +	jmpl	%l1 + %lo(sparc_vfork), %g0 +	 add	%sp, STACKFRAME_SZ, %o0          .align  4  linux_sparc_ni_syscall: diff --git a/arch/sparc/kernel/kernel.h b/arch/sparc/kernel/kernel.h index f6f498ba3198..9cd09a3ef35f 100644 --- a/arch/sparc/kernel/kernel.h +++ b/arch/sparc/kernel/kernel.h @@ -14,6 +14,11 @@ extern const char *sparc_pmu_type;  extern unsigned int fsr_storage;  extern int ncpus_probed; +/* process{_32,_64}.c */ +asmlinkage long sparc_clone(struct pt_regs *regs); +asmlinkage long sparc_fork(struct pt_regs *regs); +asmlinkage long sparc_vfork(struct pt_regs *regs); +  #ifdef CONFIG_SPARC64  /* setup_64.c */  struct seq_file; @@ -153,12 +158,6 @@ void floppy_hardint(void);  extern unsigned long sun4m_cpu_startup;  extern unsigned long sun4d_cpu_startup; -/* process_32.c */ -asmlinkage int sparc_do_fork(unsigned long clone_flags, -                             unsigned long stack_start, -                             struct pt_regs *regs, -                             unsigned long stack_size); -  /* signal_32.c */  asmlinkage void do_sigreturn(struct pt_regs *regs);  asmlinkage void do_rt_sigreturn(struct pt_regs *regs); diff --git a/arch/sparc/kernel/leon_smp.c b/arch/sparc/kernel/leon_smp.c index 41829c024f92..1eed26d423fb 100644 --- a/arch/sparc/kernel/leon_smp.c +++ b/arch/sparc/kernel/leon_smp.c @@ -38,7 +38,6 @@  #include <asm/delay.h>  #include <asm/irq.h>  #include <asm/page.h> -#include <asm/pgalloc.h>  #include <asm/oplib.h>  #include <asm/cpudata.h>  #include <asm/asi.h> diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c new file mode 100644 index 000000000000..5234b5ccc0b9 --- /dev/null +++ b/arch/sparc/kernel/process.c @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * This file handles the architecture independent parts of process handling.. + */ + +#include <linux/compat.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/ptrace.h> +#include <linux/sched.h> +#include <linux/sched/task.h> +#include <linux/sched/task_stack.h> +#include <linux/signal.h> + +#include "kernel.h" + +asmlinkage long sparc_fork(struct pt_regs *regs) +{ +	unsigned long orig_i1 = regs->u_regs[UREG_I1]; +	long ret; +	struct kernel_clone_args args = { +		.exit_signal	= SIGCHLD, +		/* Reuse the parent's stack for the child. */ +		.stack		= regs->u_regs[UREG_FP], +	}; + +	ret = _do_fork(&args); + +	/* If we get an error and potentially restart the system +	 * call, we're screwed because copy_thread() clobbered +	 * the parent's %o1.  So detect that case and restore it +	 * here. +	 */ +	if ((unsigned long)ret >= -ERESTART_RESTARTBLOCK) +		regs->u_regs[UREG_I1] = orig_i1; + +	return ret; +} + +asmlinkage long sparc_vfork(struct pt_regs *regs) +{ +	unsigned long orig_i1 = regs->u_regs[UREG_I1]; +	long ret; + +	struct kernel_clone_args args = { +		.flags		= CLONE_VFORK | CLONE_VM, +		.exit_signal	= SIGCHLD, +		/* Reuse the parent's stack for the child. */ +		.stack		= regs->u_regs[UREG_FP], +	}; + +	ret = _do_fork(&args); + +	/* If we get an error and potentially restart the system +	 * call, we're screwed because copy_thread() clobbered +	 * the parent's %o1.  So detect that case and restore it +	 * here. +	 */ +	if ((unsigned long)ret >= -ERESTART_RESTARTBLOCK) +		regs->u_regs[UREG_I1] = orig_i1; + +	return ret; +} + +asmlinkage long sparc_clone(struct pt_regs *regs) +{ +	unsigned long orig_i1 = regs->u_regs[UREG_I1]; +	unsigned int flags = lower_32_bits(regs->u_regs[UREG_I0]); +	long ret; + +	struct kernel_clone_args args = { +		.flags		= (flags & ~CSIGNAL), +		.exit_signal	= (flags & CSIGNAL), +		.tls		= regs->u_regs[UREG_I3], +	}; + +#ifdef CONFIG_COMPAT +	if (test_thread_flag(TIF_32BIT)) { +		args.pidfd	= compat_ptr(regs->u_regs[UREG_I2]); +		args.child_tid	= compat_ptr(regs->u_regs[UREG_I4]); +		args.parent_tid	= compat_ptr(regs->u_regs[UREG_I2]); +	} else +#endif +	{ +		args.pidfd	= (int __user *)regs->u_regs[UREG_I2]; +		args.child_tid	= (int __user *)regs->u_regs[UREG_I4]; +		args.parent_tid	= (int __user *)regs->u_regs[UREG_I2]; +	} + +	/* Did userspace give setup a separate stack for the child or are we +	 * reusing the parent's? +	 */ +	if (regs->u_regs[UREG_I1]) +		args.stack = regs->u_regs[UREG_I1]; +	else +		args.stack = regs->u_regs[UREG_FP]; + +	ret = _do_fork(&args); + +	/* If we get an error and potentially restart the system +	 * call, we're screwed because copy_thread() clobbered +	 * the parent's %o1.  So detect that case and restore it +	 * here. +	 */ +	if ((unsigned long)ret >= -ERESTART_RESTARTBLOCK) +		regs->u_regs[UREG_I1] = orig_i1; + +	return ret; +} diff --git a/arch/sparc/kernel/process_32.c b/arch/sparc/kernel/process_32.c index 13cb5638fab8..adfcaeab3ddc 100644 --- a/arch/sparc/kernel/process_32.c +++ b/arch/sparc/kernel/process_32.c @@ -34,7 +34,6 @@  #include <asm/oplib.h>  #include <linux/uaccess.h>  #include <asm/page.h> -#include <asm/pgalloc.h>  #include <asm/delay.h>  #include <asm/processor.h>  #include <asm/psr.h> @@ -257,33 +256,6 @@ clone_stackframe(struct sparc_stackf __user *dst,  	return sp;  } -asmlinkage int sparc_do_fork(unsigned long clone_flags, -                             unsigned long stack_start, -                             struct pt_regs *regs, -                             unsigned long stack_size) -{ -	unsigned long parent_tid_ptr, child_tid_ptr; -	unsigned long orig_i1 = regs->u_regs[UREG_I1]; -	long ret; - -	parent_tid_ptr = regs->u_regs[UREG_I2]; -	child_tid_ptr = regs->u_regs[UREG_I4]; - -	ret = do_fork(clone_flags, stack_start, stack_size, -		      (int __user *) parent_tid_ptr, -		      (int __user *) child_tid_ptr); - -	/* If we get an error and potentially restart the system -	 * call, we're screwed because copy_thread() clobbered -	 * the parent's %o1.  So detect that case and restore it -	 * here. -	 */ -	if ((unsigned long)ret >= -ERESTART_RESTARTBLOCK) -		regs->u_regs[UREG_I1] = orig_i1; - -	return ret; -} -  /* Copy a Sparc thread.  The fork() return value conventions   * under SunOS are nothing short of bletcherous:   * Parent -->  %o0 == childs  pid, %o1 == 0 @@ -300,8 +272,8 @@ asmlinkage int sparc_do_fork(unsigned long clone_flags,  extern void ret_from_fork(void);  extern void ret_from_kernel_thread(void); -int copy_thread(unsigned long clone_flags, unsigned long sp, -		unsigned long arg, struct task_struct *p) +int copy_thread(unsigned long clone_flags, unsigned long sp, unsigned long arg, +		struct task_struct *p, unsigned long tls)  {  	struct thread_info *ti = task_thread_info(p);  	struct pt_regs *childregs, *regs = current_pt_regs(); @@ -403,60 +375,11 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,  	regs->u_regs[UREG_I1] = 0;  	if (clone_flags & CLONE_SETTLS) -		childregs->u_regs[UREG_G7] = regs->u_regs[UREG_I3]; +		childregs->u_regs[UREG_G7] = tls;  	return 0;  } -/* - * fill in the fpu structure for a core dump. - */ -int dump_fpu (struct pt_regs * regs, elf_fpregset_t * fpregs) -{ -	if (used_math()) { -		memset(fpregs, 0, sizeof(*fpregs)); -		fpregs->pr_q_entrysize = 8; -		return 1; -	} -#ifdef CONFIG_SMP -	if (test_thread_flag(TIF_USEDFPU)) { -		put_psr(get_psr() | PSR_EF); -		fpsave(¤t->thread.float_regs[0], ¤t->thread.fsr, -		       ¤t->thread.fpqueue[0], ¤t->thread.fpqdepth); -		if (regs != NULL) { -			regs->psr &= ~(PSR_EF); -			clear_thread_flag(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); -		if (regs != NULL) { -			regs->psr &= ~(PSR_EF); -			last_task_used_math = NULL; -		} -	} -#endif -	memcpy(&fpregs->pr_fr.pr_regs[0], -	       ¤t->thread.float_regs[0], -	       (sizeof(unsigned long) * 32)); -	fpregs->pr_fsr = current->thread.fsr; -	fpregs->pr_qcnt = current->thread.fpqdepth; -	fpregs->pr_q_entrysize = 8; -	fpregs->pr_en = 1; -	if(fpregs->pr_qcnt != 0) { -		memcpy(&fpregs->pr_q[0], -		       ¤t->thread.fpqueue[0], -		       sizeof(struct fpq) * fpregs->pr_qcnt); -	} -	/* Zero out the rest. */ -	memset(&fpregs->pr_q[fpregs->pr_qcnt], 0, -	       sizeof(struct fpq) * (32 - fpregs->pr_qcnt)); -	return 1; -} -  unsigned long get_wchan(struct task_struct *task)  {  	unsigned long pc, fp, bias = 0; diff --git a/arch/sparc/kernel/process_64.c b/arch/sparc/kernel/process_64.c index 54945eacd3b5..a75093b993f9 100644 --- a/arch/sparc/kernel/process_64.c +++ b/arch/sparc/kernel/process_64.c @@ -572,47 +572,13 @@ barf:  	force_sig(SIGSEGV);  } -asmlinkage long sparc_do_fork(unsigned long clone_flags, -			      unsigned long stack_start, -			      struct pt_regs *regs, -			      unsigned long stack_size) -{ -	int __user *parent_tid_ptr, *child_tid_ptr; -	unsigned long orig_i1 = regs->u_regs[UREG_I1]; -	long ret; - -#ifdef CONFIG_COMPAT -	if (test_thread_flag(TIF_32BIT)) { -		parent_tid_ptr = compat_ptr(regs->u_regs[UREG_I2]); -		child_tid_ptr = compat_ptr(regs->u_regs[UREG_I4]); -	} else -#endif -	{ -		parent_tid_ptr = (int __user *) regs->u_regs[UREG_I2]; -		child_tid_ptr = (int __user *) regs->u_regs[UREG_I4]; -	} - -	ret = do_fork(clone_flags, stack_start, stack_size, -		      parent_tid_ptr, child_tid_ptr); - -	/* If we get an error and potentially restart the system -	 * call, we're screwed because copy_thread() clobbered -	 * the parent's %o1.  So detect that case and restore it -	 * here. -	 */ -	if ((unsigned long)ret >= -ERESTART_RESTARTBLOCK) -		regs->u_regs[UREG_I1] = orig_i1; - -	return ret; -} -  /* Copy a Sparc thread.  The fork() return value conventions   * under SunOS are nothing short of bletcherous:   * Parent -->  %o0 == childs  pid, %o1 == 0   * Child  -->  %o0 == parents pid, %o1 == 1   */ -int copy_thread(unsigned long clone_flags, unsigned long sp, -		unsigned long arg, struct task_struct *p) +int copy_thread(unsigned long clone_flags, unsigned long sp, unsigned long arg, +		struct task_struct *p, unsigned long tls)  {  	struct thread_info *t = task_thread_info(p);  	struct pt_regs *regs = current_pt_regs(); @@ -670,7 +636,7 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,  	regs->u_regs[UREG_I1] = 0;  	if (clone_flags & CLONE_SETTLS) -		t->kregs->u_regs[UREG_G7] = regs->u_regs[UREG_I3]; +		t->kregs->u_regs[UREG_G7] = tls;  	return 0;  } @@ -700,72 +666,6 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)  	return 0;  } -typedef struct { -	union { -		unsigned int	pr_regs[32]; -		unsigned long	pr_dregs[16]; -	} pr_fr; -	unsigned int __unused; -	unsigned int	pr_fsr; -	unsigned char	pr_qcnt; -	unsigned char	pr_q_entrysize; -	unsigned char	pr_en; -	unsigned int	pr_q[64]; -} elf_fpregset_t32; - -/* - * fill in the fpu structure for a core dump. - */ -int dump_fpu (struct pt_regs * regs, elf_fpregset_t * fpregs) -{ -	unsigned long *kfpregs = current_thread_info()->fpregs; -	unsigned long fprs = current_thread_info()->fpsaved[0]; - -	if (test_thread_flag(TIF_32BIT)) { -		elf_fpregset_t32 *fpregs32 = (elf_fpregset_t32 *)fpregs; - -		if (fprs & FPRS_DL) -			memcpy(&fpregs32->pr_fr.pr_regs[0], kfpregs, -			       sizeof(unsigned int) * 32); -		else -			memset(&fpregs32->pr_fr.pr_regs[0], 0, -			       sizeof(unsigned int) * 32); -		fpregs32->pr_qcnt = 0; -		fpregs32->pr_q_entrysize = 8; -		memset(&fpregs32->pr_q[0], 0, -		       (sizeof(unsigned int) * 64)); -		if (fprs & FPRS_FEF) { -			fpregs32->pr_fsr = (unsigned int) current_thread_info()->xfsr[0]; -			fpregs32->pr_en = 1; -		} else { -			fpregs32->pr_fsr = 0; -			fpregs32->pr_en = 0; -		} -	} else { -		if(fprs & FPRS_DL) -			memcpy(&fpregs->pr_regs[0], kfpregs, -			       sizeof(unsigned int) * 32); -		else -			memset(&fpregs->pr_regs[0], 0, -			       sizeof(unsigned int) * 32); -		if(fprs & FPRS_DU) -			memcpy(&fpregs->pr_regs[16], kfpregs+16, -			       sizeof(unsigned int) * 32); -		else -			memset(&fpregs->pr_regs[16], 0, -			       sizeof(unsigned int) * 32); -		if(fprs & FPRS_FEF) { -			fpregs->pr_fsr = current_thread_info()->xfsr[0]; -			fpregs->pr_gsr = current_thread_info()->gsr[0]; -		} else { -			fpregs->pr_fsr = fpregs->pr_gsr = 0; -		} -		fpregs->pr_fprs = fprs; -	} -	return 1; -} -EXPORT_SYMBOL(dump_fpu); -  unsigned long get_wchan(struct task_struct *task)  {  	unsigned long pc, fp, bias = 0; diff --git a/arch/sparc/kernel/ptrace_32.c b/arch/sparc/kernel/ptrace_32.c index 47eb315d411c..5318174a0268 100644 --- a/arch/sparc/kernel/ptrace_32.c +++ b/arch/sparc/kernel/ptrace_32.c @@ -83,41 +83,25 @@ static int regwindow32_set(struct task_struct *target,  static int genregs32_get(struct task_struct *target,  			 const struct user_regset *regset, -			 unsigned int pos, unsigned int count, -			 void *kbuf, void __user *ubuf) +			 struct membuf to)  {  	const struct pt_regs *regs = target->thread.kregs;  	u32 uregs[16]; -	int ret;  	if (target == current)  		flush_user_windows(); -	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, -				  regs->u_regs, -				  0, 16 * sizeof(u32)); -	if (ret || !count) -		return ret; - -	if (pos < 32 * sizeof(u32)) { -		if (regwindow32_get(target, regs, uregs)) -			return -EFAULT; -		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, -					  uregs, -					  16 * sizeof(u32), 32 * sizeof(u32)); -		if (ret || !count) -			return ret; -	} - -	uregs[0] = regs->psr; -	uregs[1] = regs->pc; -	uregs[2] = regs->npc; -	uregs[3] = regs->y; -	uregs[4] = 0;	/* WIM */ -	uregs[5] = 0;	/* TBR */ -	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, -				  uregs, -				  32 * sizeof(u32), 38 * sizeof(u32)); +	membuf_write(&to, regs->u_regs, 16 * sizeof(u32)); +	if (!to.left) +		return 0; +	if (regwindow32_get(target, regs, uregs)) +		return -EFAULT; +	membuf_write(&to, uregs, 16 * sizeof(u32)); +	membuf_store(&to, regs->psr); +	membuf_store(&to, regs->pc); +	membuf_store(&to, regs->npc); +	membuf_store(&to, regs->y); +	return membuf_zero(&to, 2 * sizeof(u32));  }  static int genregs32_set(struct task_struct *target, @@ -139,19 +123,18 @@ static int genregs32_set(struct task_struct *target,  	if (ret || !count)  		return ret; -	if (pos < 32 * sizeof(u32)) { -		if (regwindow32_get(target, regs, uregs)) -			return -EFAULT; -		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, -					 uregs, -					 16 * sizeof(u32), 32 * sizeof(u32)); -		if (ret) -			return ret; -		if (regwindow32_set(target, regs, uregs)) -			return -EFAULT; -		if (!count) -			return 0; -	} +	if (regwindow32_get(target, regs, uregs)) +		return -EFAULT; +	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, +				 uregs, +				 16 * sizeof(u32), 32 * sizeof(u32)); +	if (ret) +		return ret; +	if (regwindow32_set(target, regs, uregs)) +		return -EFAULT; +	if (!count) +		return 0; +  	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,  				 &psr,  				 32 * sizeof(u32), 33 * sizeof(u32)); @@ -182,46 +165,18 @@ static int genregs32_set(struct task_struct *target,  static int fpregs32_get(struct task_struct *target,  			const struct user_regset *regset, -			unsigned int pos, unsigned int count, -			void *kbuf, void __user *ubuf) +			struct membuf to)  { -	const unsigned long *fpregs = target->thread.float_regs; -	int ret = 0; -  #if 0  	if (target == current)  		save_and_clear_fpu();  #endif -	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, -				  fpregs, -				  0, 32 * sizeof(u32)); - -	if (!ret) -		ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, -					       32 * sizeof(u32), -					       33 * sizeof(u32)); -	if (!ret) -		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, -					  &target->thread.fsr, -					  33 * sizeof(u32), -					  34 * sizeof(u32)); - -	if (!ret) { -		unsigned long val; - -		val = (1 << 8) | (8 << 16); -		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, -					  &val, -					  34 * sizeof(u32), -					  35 * sizeof(u32)); -	} - -	if (!ret) -		ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, -					       35 * sizeof(u32), -1); - -	return ret; +	membuf_write(&to, target->thread.float_regs, 32 * sizeof(u32)); +	membuf_zero(&to, sizeof(u32)); +	membuf_write(&to, &target->thread.fsr, sizeof(u32)); +	membuf_store(&to, (u32)((1 << 8) | (8 << 16))); +	return membuf_zero(&to, 64 * sizeof(u32));  }  static int fpregs32_set(struct task_struct *target, @@ -243,13 +198,11 @@ static int fpregs32_set(struct task_struct *target,  		user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,  					  32 * sizeof(u32),  					  33 * sizeof(u32)); -	if (!ret && count > 0) { +	if (!ret)  		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,  					 &target->thread.fsr,  					 33 * sizeof(u32),  					 34 * sizeof(u32)); -	} -  	if (!ret)  		ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,  						34 * sizeof(u32), -1); @@ -268,7 +221,7 @@ static const struct user_regset sparc32_regsets[] = {  		.core_note_type = NT_PRSTATUS,  		.n = 38,  		.size = sizeof(u32), .align = sizeof(u32), -		.get = genregs32_get, .set = genregs32_set +		.regset_get = genregs32_get, .set = genregs32_set  	},  	/* Format is:  	 *	F0 --> F31 @@ -284,10 +237,104 @@ static const struct user_regset sparc32_regsets[] = {  		.core_note_type = NT_PRFPREG,  		.n = 99,  		.size = sizeof(u32), .align = sizeof(u32), -		.get = fpregs32_get, .set = fpregs32_set +		.regset_get = fpregs32_get, .set = fpregs32_set +	}, +}; + +static int getregs_get(struct task_struct *target, +			 const struct user_regset *regset, +			 struct membuf to) +{ +	const struct pt_regs *regs = target->thread.kregs; + +	if (target == current) +		flush_user_windows(); + +	membuf_store(&to, regs->psr); +	membuf_store(&to, regs->pc); +	membuf_store(&to, regs->npc); +	membuf_store(&to, regs->y); +	return membuf_write(&to, regs->u_regs + 1, 15 * sizeof(u32)); +} + +static int setregs_set(struct task_struct *target, +			 const struct user_regset *regset, +			 unsigned int pos, unsigned int count, +			 const void *kbuf, const void __user *ubuf) +{ +	struct pt_regs *regs = target->thread.kregs; +	u32 v[4]; +	int ret; + +	if (target == current) +		flush_user_windows(); + +	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, +				 v, +				 0, 4 * sizeof(u32)); +	if (ret) +		return ret; +	regs->psr = (regs->psr & ~(PSR_ICC | PSR_SYSCALL)) | +		    (v[0] & (PSR_ICC | PSR_SYSCALL)); +	regs->pc = v[1]; +	regs->npc = v[2]; +	regs->y = v[3]; +	return user_regset_copyin(&pos, &count, &kbuf, &ubuf, +				 regs->u_regs + 1, +				 4 * sizeof(u32) , 19 * sizeof(u32)); +} + +static int getfpregs_get(struct task_struct *target, +			const struct user_regset *regset, +			struct membuf to) +{ +#if 0 +	if (target == current) +		save_and_clear_fpu(); +#endif +	membuf_write(&to, &target->thread.float_regs, 32 * sizeof(u32)); +	membuf_write(&to, &target->thread.fsr, sizeof(u32)); +	return membuf_zero(&to, 35 * sizeof(u32)); +} + +static int setfpregs_set(struct task_struct *target, +			const struct user_regset *regset, +			unsigned int pos, unsigned int count, +			const void *kbuf, const void __user *ubuf) +{ +	unsigned long *fpregs = target->thread.float_regs; +	int ret; + +#if 0 +	if (target == current) +		save_and_clear_fpu(); +#endif +	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, +				 fpregs, +				 0, 32 * sizeof(u32)); +	if (ret) +		return ret; +	return user_regset_copyin(&pos, &count, &kbuf, &ubuf, +				 &target->thread.fsr, +				 32 * sizeof(u32), +				 33 * sizeof(u32)); +} + +static const struct user_regset ptrace32_regsets[] = { +	[REGSET_GENERAL] = { +		.n = 19, .size = sizeof(u32), +		.regset_get = getregs_get, .set = setregs_set, +	}, +	[REGSET_FP] = { +		.n = 68, .size = sizeof(u32), +		.regset_get = getfpregs_get, .set = setfpregs_set,  	},  }; +static const struct user_regset_view ptrace32_view = { +	.regsets = ptrace32_regsets, .n = ARRAY_SIZE(ptrace32_regsets) +}; +  static const struct user_regset_view user_sparc32_view = {  	.name = "sparc", .e_machine = EM_SPARC,  	.regsets = sparc32_regsets, .n = ARRAY_SIZE(sparc32_regsets) @@ -315,74 +362,44 @@ long arch_ptrace(struct task_struct *child, long request,  {  	unsigned long addr2 = current->thread.kregs->u_regs[UREG_I4];  	void __user *addr2p; -	const struct user_regset_view *view;  	struct pt_regs __user *pregs;  	struct fps __user *fps;  	int ret; -	view = task_user_regset_view(current);  	addr2p = (void __user *) addr2;  	pregs = (struct pt_regs __user *) addr;  	fps = (struct fps __user *) addr;  	switch(request) {  	case PTRACE_GETREGS: { -		ret = copy_regset_to_user(child, view, REGSET_GENERAL, -					  32 * sizeof(u32), -					  4 * sizeof(u32), -					  &pregs->psr); -		if (!ret) -			copy_regset_to_user(child, view, REGSET_GENERAL, -					    1 * sizeof(u32), -					    15 * sizeof(u32), -					    &pregs->u_regs[0]); +		ret = copy_regset_to_user(child, &ptrace32_view, +					  REGSET_GENERAL, 0, +					  19 * sizeof(u32), +					  pregs);  		break;  	}  	case PTRACE_SETREGS: { -		ret = copy_regset_from_user(child, view, REGSET_GENERAL, -					    32 * sizeof(u32), -					    4 * sizeof(u32), -					    &pregs->psr); -		if (!ret) -			copy_regset_from_user(child, view, REGSET_GENERAL, -					      1 * sizeof(u32), -					      15 * sizeof(u32), -					      &pregs->u_regs[0]); +		ret = copy_regset_from_user(child, &ptrace32_view, +					    REGSET_GENERAL, 0, +					    19 * sizeof(u32), +					    pregs);  		break;  	}  	case PTRACE_GETFPREGS: { -		ret = copy_regset_to_user(child, view, REGSET_FP, -					  0 * sizeof(u32), -					  32 * sizeof(u32), -					  &fps->regs[0]); -		if (!ret) -			ret = copy_regset_to_user(child, view, REGSET_FP, -						  33 * sizeof(u32), -						  1 * sizeof(u32), -						  &fps->fsr); - -		if (!ret) { -			if (__put_user(0, &fps->fpqd) || -			    __put_user(0, &fps->flags) || -			    __put_user(0, &fps->extra) || -			    clear_user(fps->fpq, sizeof(fps->fpq))) -				ret = -EFAULT; -		} +		ret = copy_regset_to_user(child, &ptrace32_view, +					  REGSET_FP, 0, +					  68 * sizeof(u32), +					  fps);  		break;  	}  	case PTRACE_SETFPREGS: { -		ret = copy_regset_from_user(child, view, REGSET_FP, -					    0 * sizeof(u32), -					    32 * sizeof(u32), -					    &fps->regs[0]); -		if (!ret) -			ret = copy_regset_from_user(child, view, REGSET_FP, -						    33 * sizeof(u32), -						    1 * sizeof(u32), -						    &fps->fsr); +		ret = copy_regset_from_user(child, &ptrace32_view, +					  REGSET_FP, 0, +					  33 * sizeof(u32), +					  fps);  		break;  	} diff --git a/arch/sparc/kernel/ptrace_64.c b/arch/sparc/kernel/ptrace_64.c index 7122efb4b1cc..2b92155db8a5 100644 --- a/arch/sparc/kernel/ptrace_64.c +++ b/arch/sparc/kernel/ptrace_64.c @@ -246,52 +246,23 @@ enum sparc_regset {  static int genregs64_get(struct task_struct *target,  			 const struct user_regset *regset, -			 unsigned int pos, unsigned int count, -			 void *kbuf, void __user *ubuf) +			 struct membuf to)  {  	const struct pt_regs *regs = task_pt_regs(target); -	int ret; +	struct reg_window window;  	if (target == current)  		flushw_user(); -	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, -				  regs->u_regs, -				  0, 16 * sizeof(u64)); -	if (!ret && count && pos < (32 * sizeof(u64))) { -		struct reg_window window; - -		if (regwindow64_get(target, regs, &window)) -			return -EFAULT; -		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, -					  &window, -					  16 * sizeof(u64), -					  32 * sizeof(u64)); -	} - -	if (!ret) { -		/* TSTATE, TPC, TNPC */ -		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, -					  ®s->tstate, -					  32 * sizeof(u64), -					  35 * sizeof(u64)); -	} - -	if (!ret) { -		unsigned long y = regs->y; - -		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, -					  &y, -					  35 * sizeof(u64), -					  36 * sizeof(u64)); -	} - -	if (!ret) { -		ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, -					       36 * sizeof(u64), -1); - -	} -	return ret; +	membuf_write(&to, regs->u_regs, 16 * sizeof(u64)); +	if (!to.left) +		return 0; +	if (regwindow64_get(target, regs, &window)) +		return -EFAULT; +	membuf_write(&to, &window, 16 * sizeof(u64)); +	/* TSTATE, TPC, TNPC */ +	membuf_write(&to, ®s->tstate, 3 * sizeof(u64)); +	return membuf_store(&to, (u64)regs->y);  }  static int genregs64_set(struct task_struct *target, @@ -370,69 +341,32 @@ static int genregs64_set(struct task_struct *target,  static int fpregs64_get(struct task_struct *target,  			const struct user_regset *regset, -			unsigned int pos, unsigned int count, -			void *kbuf, void __user *ubuf) +			struct membuf to)  { -	const unsigned long *fpregs = task_thread_info(target)->fpregs; -	unsigned long fprs, fsr, gsr; -	int ret; +	struct thread_info *t = task_thread_info(target); +	unsigned long fprs;  	if (target == current)  		save_and_clear_fpu(); -	fprs = task_thread_info(target)->fpsaved[0]; +	fprs = t->fpsaved[0];  	if (fprs & FPRS_DL) -		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, -					  fpregs, -					  0, 16 * sizeof(u64)); +		membuf_write(&to, t->fpregs, 16 * sizeof(u64));  	else -		ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, -					       0, -					       16 * sizeof(u64)); - -	if (!ret) { -		if (fprs & FPRS_DU) -			ret = user_regset_copyout(&pos, &count, -						  &kbuf, &ubuf, -						  fpregs + 16, -						  16 * sizeof(u64), -						  32 * sizeof(u64)); -		else -			ret = user_regset_copyout_zero(&pos, &count, -						       &kbuf, &ubuf, -						       16 * sizeof(u64), -						       32 * sizeof(u64)); -	} +		membuf_zero(&to, 16 * sizeof(u64)); +	if (fprs & FPRS_DU) +		membuf_write(&to, t->fpregs + 16, 16 * sizeof(u64)); +	else +		membuf_zero(&to, 16 * sizeof(u64));  	if (fprs & FPRS_FEF) { -		fsr = task_thread_info(target)->xfsr[0]; -		gsr = task_thread_info(target)->gsr[0]; +		membuf_store(&to, t->xfsr[0]); +		membuf_store(&to, t->gsr[0]);  	} else { -		fsr = gsr = 0; +		membuf_zero(&to, 2 * sizeof(u64));  	} - -	if (!ret) -		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, -					  &fsr, -					  32 * sizeof(u64), -					  33 * sizeof(u64)); -	if (!ret) -		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, -					  &gsr, -					  33 * sizeof(u64), -					  34 * sizeof(u64)); -	if (!ret) -		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, -					  &fprs, -					  34 * sizeof(u64), -					  35 * sizeof(u64)); - -	if (!ret) -		ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, -					       35 * sizeof(u64), -1); - -	return ret; +	return membuf_store(&to, fprs);  }  static int fpregs64_set(struct task_struct *target, @@ -490,7 +424,7 @@ static const struct user_regset sparc64_regsets[] = {  		.core_note_type = NT_PRSTATUS,  		.n = 36,  		.size = sizeof(u64), .align = sizeof(u64), -		.get = genregs64_get, .set = genregs64_set +		.regset_get = genregs64_get, .set = genregs64_set  	},  	/* Format is:  	 *	F0 --> F63 @@ -502,10 +436,96 @@ static const struct user_regset sparc64_regsets[] = {  		.core_note_type = NT_PRFPREG,  		.n = 35,  		.size = sizeof(u64), .align = sizeof(u64), -		.get = fpregs64_get, .set = fpregs64_set +		.regset_get = fpregs64_get, .set = fpregs64_set +	}, +}; + +static int getregs64_get(struct task_struct *target, +			 const struct user_regset *regset, +			 struct membuf to) +{ +	const struct pt_regs *regs = task_pt_regs(target); + +	if (target == current) +		flushw_user(); + +	membuf_write(&to, regs->u_regs + 1, 15 * sizeof(u64)); +	membuf_store(&to, (u64)0); +	membuf_write(&to, ®s->tstate, 3 * sizeof(u64)); +	return membuf_store(&to, (u64)regs->y); +} + +static int setregs64_set(struct task_struct *target, +			 const struct user_regset *regset, +			 unsigned int pos, unsigned int count, +			 const void *kbuf, const void __user *ubuf) +{ +	struct pt_regs *regs = task_pt_regs(target); +	unsigned long y = regs->y; +	unsigned long tstate; +	int ret; + +	if (target == current) +		flushw_user(); + +	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, +				 regs->u_regs + 1, +				 0 * sizeof(u64), +				 15 * sizeof(u64)); +	if (ret) +		return ret; +	ret =user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, +				 15 * sizeof(u64), 16 * sizeof(u64)); +	if (ret) +		return ret; +	/* TSTATE */ +	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, +				 &tstate, +				 16 * sizeof(u64), +				 17 * sizeof(u64)); +	if (ret) +		return ret; +	/* Only the condition codes and the "in syscall" +	 * state can be modified in the %tstate register. +	 */ +	tstate &= (TSTATE_ICC | TSTATE_XCC | TSTATE_SYSCALL); +	regs->tstate &= ~(TSTATE_ICC | TSTATE_XCC | TSTATE_SYSCALL); +	regs->tstate |= tstate; + +	/* TPC, TNPC */ +	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, +				 ®s->tpc, +				 17 * sizeof(u64), +				 19 * sizeof(u64)); +	if (ret) +		return ret; +	/* Y */ +	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, +				 &y, +				 19 * sizeof(u64), +				 20 * sizeof(u64)); +	if (!ret) +		regs->y = y; +	return ret; +} + +static const struct user_regset ptrace64_regsets[] = { +	/* Format is: +	 *      G1 --> G7 +	 *      O0 --> O7 +	 *	0 +	 *      TSTATE, TPC, TNPC, Y +	 */ +	[REGSET_GENERAL] = { +		.n = 20, .size = sizeof(u64), +		.regset_get = getregs64_get, .set = setregs64_set,  	},  }; +static const struct user_regset_view ptrace64_view = { +	.regsets = ptrace64_regsets, .n = ARRAY_SIZE(ptrace64_regsets) +}; +  static const struct user_regset_view user_sparc64_view = {  	.name = "sparc64", .e_machine = EM_SPARCV9,  	.regsets = sparc64_regsets, .n = ARRAY_SIZE(sparc64_regsets) @@ -514,108 +534,28 @@ static const struct user_regset_view user_sparc64_view = {  #ifdef CONFIG_COMPAT  static int genregs32_get(struct task_struct *target,  			 const struct user_regset *regset, -			 unsigned int pos, unsigned int count, -			 void *kbuf, void __user *ubuf) +			 struct membuf to)  {  	const struct pt_regs *regs = task_pt_regs(target); -	compat_ulong_t __user *reg_window; -	compat_ulong_t *k = kbuf; -	compat_ulong_t __user *u = ubuf; -	compat_ulong_t reg; +	u32 uregs[16]; +	int i;  	if (target == current)  		flushw_user(); -	pos /= sizeof(reg); -	count /= sizeof(reg); - -	if (kbuf) { -		for (; count > 0 && pos < 16; count--) -			*k++ = regs->u_regs[pos++]; - -		reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6]; -		reg_window -= 16; -		if (target == current) { -			for (; count > 0 && pos < 32; count--) { -				if (get_user(*k++, ®_window[pos++])) -					return -EFAULT; -			} -		} else { -			for (; count > 0 && pos < 32; count--) { -				if (access_process_vm(target, -						      (unsigned long) -						      ®_window[pos], -						      k, sizeof(*k), -						      FOLL_FORCE) -				    != sizeof(*k)) -					return -EFAULT; -				k++; -				pos++; -			} -		} -	} else { -		for (; count > 0 && pos < 16; count--) { -			if (put_user((compat_ulong_t) regs->u_regs[pos++], u++)) -				return -EFAULT; -		} - -		reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6]; -		reg_window -= 16; -		if (target == current) { -			for (; count > 0 && pos < 32; count--) { -				if (get_user(reg, ®_window[pos++]) || -				    put_user(reg, u++)) -					return -EFAULT; -			} -		} else { -			for (; count > 0 && pos < 32; count--) { -				if (access_process_vm(target, -						      (unsigned long) -						      ®_window[pos++], -						      ®, sizeof(reg), -						      FOLL_FORCE) -				    != sizeof(reg)) -					return -EFAULT; -				if (put_user(reg, u++)) -					return -EFAULT; -			} -		} -	} -	while (count > 0) { -		switch (pos) { -		case 32: /* PSR */ -			reg = tstate_to_psr(regs->tstate); -			break; -		case 33: /* PC */ -			reg = regs->tpc; -			break; -		case 34: /* NPC */ -			reg = regs->tnpc; -			break; -		case 35: /* Y */ -			reg = regs->y; -			break; -		case 36: /* WIM */ -		case 37: /* TBR */ -			reg = 0; -			break; -		default: -			goto finish; -		} - -		if (kbuf) -			*k++ = reg; -		else if (put_user(reg, u++)) -			return -EFAULT; -		pos++; -		count--; -	} -finish: -	pos *= sizeof(reg); -	count *= sizeof(reg); - -	return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, -					38 * sizeof(reg), -1); +	for (i = 0; i < 16; i++) +		membuf_store(&to, (u32)regs->u_regs[i]); +	if (!to.left) +		return 0; +	if (get_from_target(target, regs->u_regs[UREG_I6], +			    uregs, sizeof(uregs))) +		return -EFAULT; +	membuf_write(&to, uregs, 16 * sizeof(u32)); +	membuf_store(&to, (u32)tstate_to_psr(regs->tstate)); +	membuf_store(&to, (u32)(regs->tpc)); +	membuf_store(&to, (u32)(regs->tnpc)); +	membuf_store(&to, (u32)(regs->y)); +	return membuf_zero(&to, 2 * sizeof(u32));  }  static int genregs32_set(struct task_struct *target, @@ -737,56 +677,24 @@ finish:  static int fpregs32_get(struct task_struct *target,  			const struct user_regset *regset, -			unsigned int pos, unsigned int count, -			void *kbuf, void __user *ubuf) +			struct membuf to)  { -	const unsigned long *fpregs = task_thread_info(target)->fpregs; -	compat_ulong_t enabled; -	unsigned long fprs; -	compat_ulong_t fsr; -	int ret = 0; +	struct thread_info *t = task_thread_info(target); +	bool enabled;  	if (target == current)  		save_and_clear_fpu(); -	fprs = task_thread_info(target)->fpsaved[0]; -	if (fprs & FPRS_FEF) { -		fsr = task_thread_info(target)->xfsr[0]; -		enabled = 1; -	} else { -		fsr = 0; -		enabled = 0; -	} - -	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, -				  fpregs, -				  0, 32 * sizeof(u32)); - -	if (!ret) -		ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, -					       32 * sizeof(u32), -					       33 * sizeof(u32)); -	if (!ret) -		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, -					  &fsr, -					  33 * sizeof(u32), -					  34 * sizeof(u32)); - -	if (!ret) { -		compat_ulong_t val; - -		val = (enabled << 8) | (8 << 16); -		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, -					  &val, -					  34 * sizeof(u32), -					  35 * sizeof(u32)); -	} +	enabled = t->fpsaved[0] & FPRS_FEF; -	if (!ret) -		ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, -					       35 * sizeof(u32), -1); - -	return ret; +	membuf_write(&to, t->fpregs, 32 * sizeof(u32)); +	membuf_zero(&to, sizeof(u32)); +	if (enabled) +		membuf_store(&to, (u32)t->xfsr[0]); +	else +		membuf_zero(&to, sizeof(u32)); +	membuf_store(&to, (u32)((enabled << 8) | (8 << 16))); +	return membuf_zero(&to, 64 * sizeof(u32));  }  static int fpregs32_set(struct task_struct *target, @@ -847,7 +755,7 @@ static const struct user_regset sparc32_regsets[] = {  		.core_note_type = NT_PRSTATUS,  		.n = 38,  		.size = sizeof(u32), .align = sizeof(u32), -		.get = genregs32_get, .set = genregs32_set +		.regset_get = genregs32_get, .set = genregs32_set  	},  	/* Format is:  	 *	F0 --> F31 @@ -863,10 +771,133 @@ static const struct user_regset sparc32_regsets[] = {  		.core_note_type = NT_PRFPREG,  		.n = 99,  		.size = sizeof(u32), .align = sizeof(u32), -		.get = fpregs32_get, .set = fpregs32_set +		.regset_get = fpregs32_get, .set = fpregs32_set  	},  }; +static int getregs_get(struct task_struct *target, +			 const struct user_regset *regset, +			 struct membuf to) +{ +	const struct pt_regs *regs = task_pt_regs(target); +	int i; + +	if (target == current) +		flushw_user(); + +	membuf_store(&to, (u32)tstate_to_psr(regs->tstate)); +	membuf_store(&to, (u32)(regs->tpc)); +	membuf_store(&to, (u32)(regs->tnpc)); +	membuf_store(&to, (u32)(regs->y)); +	for (i = 1; i < 16; i++) +		membuf_store(&to, (u32)regs->u_regs[i]); +	return to.left; +} + +static int setregs_set(struct task_struct *target, +			 const struct user_regset *regset, +			 unsigned int pos, unsigned int count, +			 const void *kbuf, const void __user *ubuf) +{ +	struct pt_regs *regs = task_pt_regs(target); +	unsigned long tstate; +	u32 uregs[19]; +	int i, ret; + +	if (target == current) +		flushw_user(); + +	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, +				 uregs, +				 0, 19 * sizeof(u32)); +	if (ret) +		return ret; + +	tstate = regs->tstate; +	tstate &= ~(TSTATE_ICC | TSTATE_XCC | TSTATE_SYSCALL); +	tstate |= psr_to_tstate_icc(uregs[0]); +	if (uregs[0] & PSR_SYSCALL) +		tstate |= TSTATE_SYSCALL; +	regs->tstate = tstate; +	regs->tpc = uregs[1]; +	regs->tnpc = uregs[2]; +	regs->y = uregs[3]; + +	for (i = 1; i < 15; i++) +		regs->u_regs[i] = uregs[3 + i]; +	return 0; +} + +static int getfpregs_get(struct task_struct *target, +			const struct user_regset *regset, +			struct membuf to) +{ +	struct thread_info *t = task_thread_info(target); + +	if (target == current) +		save_and_clear_fpu(); + +	membuf_write(&to, t->fpregs, 32 * sizeof(u32)); +	if (t->fpsaved[0] & FPRS_FEF) +		membuf_store(&to, (u32)t->xfsr[0]); +	else +		membuf_zero(&to, sizeof(u32)); +	return membuf_zero(&to, 35 * sizeof(u32)); +} + +static int setfpregs_set(struct task_struct *target, +			const struct user_regset *regset, +			unsigned int pos, unsigned int count, +			const void *kbuf, const void __user *ubuf) +{ +	unsigned long *fpregs = task_thread_info(target)->fpregs; +	unsigned long fprs; +	int ret; + +	if (target == current) +		save_and_clear_fpu(); + +	fprs = task_thread_info(target)->fpsaved[0]; + +	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, +				 fpregs, +				 0, 32 * sizeof(u32)); +	if (!ret) { +		compat_ulong_t fsr; +		unsigned long val; + +		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, +					 &fsr, +					 32 * sizeof(u32), +					 33 * sizeof(u32)); +		if (!ret) { +			val = task_thread_info(target)->xfsr[0]; +			val &= 0xffffffff00000000UL; +			val |= fsr; +			task_thread_info(target)->xfsr[0] = val; +		} +	} + +	fprs |= (FPRS_FEF | FPRS_DL); +	task_thread_info(target)->fpsaved[0] = fprs; +	return ret; +} + +static const struct user_regset ptrace32_regsets[] = { +	[REGSET_GENERAL] = { +		.n = 19, .size = sizeof(u32), +		.regset_get = getregs_get, .set = setregs_set, +	}, +	[REGSET_FP] = { +		.n = 68, .size = sizeof(u32), +		.regset_get = getfpregs_get, .set = setfpregs_set, +	}, +}; + +static const struct user_regset_view ptrace32_view = { +	.regsets = ptrace32_regsets, .n = ARRAY_SIZE(ptrace32_regsets) +}; +  static const struct user_regset_view user_sparc32_view = {  	.name = "sparc", .e_machine = EM_SPARC,  	.regsets = sparc32_regsets, .n = ARRAY_SIZE(sparc32_regsets) @@ -898,7 +929,6 @@ struct compat_fps {  long compat_arch_ptrace(struct task_struct *child, compat_long_t request,  			compat_ulong_t caddr, compat_ulong_t cdata)  { -	const struct user_regset_view *view = task_user_regset_view(current);  	compat_ulong_t caddr2 = task_pt_regs(current)->u_regs[UREG_I4];  	struct pt_regs32 __user *pregs;  	struct compat_fps __user *fps; @@ -916,58 +946,31 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,  		break;  	case PTRACE_GETREGS: -		ret = copy_regset_to_user(child, view, REGSET_GENERAL, -					  32 * sizeof(u32), -					  4 * sizeof(u32), -					  &pregs->psr); -		if (!ret) -			ret = copy_regset_to_user(child, view, REGSET_GENERAL, -						  1 * sizeof(u32), -						  15 * sizeof(u32), -						  &pregs->u_regs[0]); +		ret = copy_regset_to_user(child, &ptrace32_view, +					  REGSET_GENERAL, 0, +					  19 * sizeof(u32), +					  pregs);  		break;  	case PTRACE_SETREGS: -		ret = copy_regset_from_user(child, view, REGSET_GENERAL, -					    32 * sizeof(u32), -					    4 * sizeof(u32), -					    &pregs->psr); -		if (!ret) -			ret = copy_regset_from_user(child, view, REGSET_GENERAL, -						    1 * sizeof(u32), -						    15 * sizeof(u32), -						    &pregs->u_regs[0]); +		ret = copy_regset_from_user(child, &ptrace32_view, +					  REGSET_GENERAL, 0, +					  19 * sizeof(u32), +					  pregs);  		break;  	case PTRACE_GETFPREGS: -		ret = copy_regset_to_user(child, view, REGSET_FP, -					  0 * sizeof(u32), -					  32 * sizeof(u32), -					  &fps->regs[0]); -		if (!ret) -			ret = copy_regset_to_user(child, view, REGSET_FP, -						  33 * sizeof(u32), -						  1 * sizeof(u32), -						  &fps->fsr); -		if (!ret) { -			if (__put_user(0, &fps->flags) || -			    __put_user(0, &fps->extra) || -			    __put_user(0, &fps->fpqd) || -			    clear_user(&fps->fpq[0], 32 * sizeof(unsigned int))) -				ret = -EFAULT; -		} +		ret = copy_regset_to_user(child, &ptrace32_view, +					  REGSET_FP, 0, +					  68 * sizeof(u32), +					  fps);  		break;  	case PTRACE_SETFPREGS: -		ret = copy_regset_from_user(child, view, REGSET_FP, -					    0 * sizeof(u32), -					    32 * sizeof(u32), -					    &fps->regs[0]); -		if (!ret) -			ret = copy_regset_from_user(child, view, REGSET_FP, -						    33 * sizeof(u32), -						    1 * sizeof(u32), -						    &fps->fsr); +		ret = copy_regset_from_user(child, &ptrace32_view, +					  REGSET_FP, 0, +					  33 * sizeof(u32), +					  fps);  		break;  	case PTRACE_READTEXT: @@ -1026,31 +1029,17 @@ long arch_ptrace(struct task_struct *child, long request,  		break;  	case PTRACE_GETREGS64: -		ret = copy_regset_to_user(child, view, REGSET_GENERAL, -					  1 * sizeof(u64), -					  15 * sizeof(u64), -					  &pregs->u_regs[0]); -		if (!ret) { -			/* XXX doesn't handle 'y' register correctly XXX */ -			ret = copy_regset_to_user(child, view, REGSET_GENERAL, -						  32 * sizeof(u64), -						  4 * sizeof(u64), -						  &pregs->tstate); -		} +		ret = copy_regset_to_user(child, &ptrace64_view, +					  REGSET_GENERAL, 0, +					  19 * sizeof(u64), +					  pregs);  		break;  	case PTRACE_SETREGS64: -		ret = copy_regset_from_user(child, view, REGSET_GENERAL, -					    1 * sizeof(u64), -					    15 * sizeof(u64), -					    &pregs->u_regs[0]); -		if (!ret) { -			/* XXX doesn't handle 'y' register correctly XXX */ -			ret = copy_regset_from_user(child, view, REGSET_GENERAL, -						    32 * sizeof(u64), -						    4 * sizeof(u64), -						    &pregs->tstate); -		} +		ret = copy_regset_from_user(child, &ptrace64_view, +					  REGSET_GENERAL, 0, +					  19 * sizeof(u64), +					  pregs);  		break;  	case PTRACE_GETFPREGS64: diff --git a/arch/sparc/kernel/setup_32.c b/arch/sparc/kernel/setup_32.c index 6d07b85b9e24..eea43a1aef1b 100644 --- a/arch/sparc/kernel/setup_32.c +++ b/arch/sparc/kernel/setup_32.c @@ -353,8 +353,6 @@ void __init setup_arch(char **cmdline_p)  	ROOT_DEV = old_decode_dev(root_dev);  #ifdef CONFIG_BLK_DEV_RAM  	rd_image_start = ram_flags & RAMDISK_IMAGE_START_MASK; -	rd_prompt = ((ram_flags & RAMDISK_PROMPT_FLAG) != 0); -	rd_doload = ((ram_flags & RAMDISK_LOAD_FLAG) != 0);	  #endif  	prom_setsync(prom_sync_me); diff --git a/arch/sparc/kernel/setup_64.c b/arch/sparc/kernel/setup_64.c index f765fda871eb..d87244197d5c 100644 --- a/arch/sparc/kernel/setup_64.c +++ b/arch/sparc/kernel/setup_64.c @@ -659,8 +659,6 @@ void __init setup_arch(char **cmdline_p)  	ROOT_DEV = old_decode_dev(root_dev);  #ifdef CONFIG_BLK_DEV_RAM  	rd_image_start = ram_flags & RAMDISK_IMAGE_START_MASK; -	rd_prompt = ((ram_flags & RAMDISK_PROMPT_FLAG) != 0); -	rd_doload = ((ram_flags & RAMDISK_LOAD_FLAG) != 0);  #endif  	task_thread_info(&init_task)->kregs = &fake_swapper_regs; diff --git a/arch/sparc/kernel/signal_32.c b/arch/sparc/kernel/signal_32.c index 3b005b6c3e0f..f1f8c8ebe641 100644 --- a/arch/sparc/kernel/signal_32.c +++ b/arch/sparc/kernel/signal_32.c @@ -23,7 +23,6 @@  #include <linux/uaccess.h>  #include <asm/ptrace.h> -#include <asm/pgalloc.h>  #include <asm/cacheflush.h>	/* flush_sig_insns */  #include <asm/switch_to.h> diff --git a/arch/sparc/kernel/smp_32.c b/arch/sparc/kernel/smp_32.c index 76ce290c67cf..50c127ab46d5 100644 --- a/arch/sparc/kernel/smp_32.c +++ b/arch/sparc/kernel/smp_32.c @@ -29,7 +29,6 @@  #include <asm/irq.h>  #include <asm/page.h> -#include <asm/pgalloc.h>  #include <asm/oplib.h>  #include <asm/cacheflush.h>  #include <asm/tlbflush.h> diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c index 0085e28bf019..e286e2badc8a 100644 --- a/arch/sparc/kernel/smp_64.c +++ b/arch/sparc/kernel/smp_64.c @@ -47,6 +47,7 @@  #include <linux/uaccess.h>  #include <asm/starfire.h>  #include <asm/tlb.h> +#include <asm/pgalloc.h>  #include <asm/sections.h>  #include <asm/prom.h>  #include <asm/mdesc.h> diff --git a/arch/sparc/kernel/sun4m_irq.c b/arch/sparc/kernel/sun4m_irq.c index 91b61f012d19..1079638986b5 100644 --- a/arch/sparc/kernel/sun4m_irq.c +++ b/arch/sparc/kernel/sun4m_irq.c @@ -16,7 +16,6 @@  #include <asm/timer.h>  #include <asm/traps.h> -#include <asm/pgalloc.h>  #include <asm/irq.h>  #include <asm/io.h>  #include <asm/cacheflush.h> diff --git a/arch/sparc/kernel/sys32.S b/arch/sparc/kernel/sys32.S index 489ffab918a8..a45f0f31fe51 100644 --- a/arch/sparc/kernel/sys32.S +++ b/arch/sparc/kernel/sys32.S @@ -157,22 +157,22 @@ do_sys_shutdown: /* sys_shutdown(int, int) */  	nop  	nop  	nop -do_sys_setsockopt: /* compat_sys_setsockopt(int, int, int, char *, int) */ +do_sys_setsockopt: /* sys_setsockopt(int, int, int, char *, int) */  47:	ldswa		[%o1 + 0x0] %asi, %o0 -	sethi		%hi(compat_sys_setsockopt), %g1 +	sethi		%hi(sys_setsockopt), %g1  48:	ldswa		[%o1 + 0x8] %asi, %o2  49:	lduwa		[%o1 + 0xc] %asi, %o3  50:	ldswa		[%o1 + 0x10] %asi, %o4 -	jmpl		%g1 + %lo(compat_sys_setsockopt), %g0 +	jmpl		%g1 + %lo(sys_setsockopt), %g0  51:	 ldswa		[%o1 + 0x4] %asi, %o1  	nop -do_sys_getsockopt: /* compat_sys_getsockopt(int, int, int, u32, u32) */ +do_sys_getsockopt: /* sys_getsockopt(int, int, int, u32, u32) */  52:	ldswa		[%o1 + 0x0] %asi, %o0 -	sethi		%hi(compat_sys_getsockopt), %g1 +	sethi		%hi(sys_getsockopt), %g1  53:	ldswa		[%o1 + 0x8] %asi, %o2  54:	lduwa		[%o1 + 0xc] %asi, %o3  55:	lduwa		[%o1 + 0x10] %asi, %o4 -	jmpl		%g1 + %lo(compat_sys_getsockopt), %g0 +	jmpl		%g1 + %lo(sys_getsockopt), %g0  56:	 ldswa		[%o1 + 0x4] %asi, %o1  	nop  do_sys_sendmsg: /* compat_sys_sendmsg(int, struct compat_msghdr *, unsigned int) */ diff --git a/arch/sparc/kernel/syscalls.S b/arch/sparc/kernel/syscalls.S index db42b4fb3708..0e8ab0602c36 100644 --- a/arch/sparc/kernel/syscalls.S +++ b/arch/sparc/kernel/syscalls.S @@ -86,19 +86,22 @@ sys32_rt_sigreturn:  	 * during system calls...  	 */  	.align	32 -sys_vfork: /* Under Linux, vfork and fork are just special cases of clone. */ -	sethi	%hi(0x4000 | 0x0100 | SIGCHLD), %o0 -	or	%o0, %lo(0x4000 | 0x0100 | SIGCHLD), %o0 -	ba,pt	%xcc, sys_clone +sys_vfork: +	flushw +	ba,pt	%xcc, sparc_vfork +	 add	%sp, PTREGS_OFF, %o0 + +	.align	32  sys_fork: -	 clr	%o1 -	mov	SIGCHLD, %o0 +	flushw +	ba,pt	%xcc, sparc_fork +	 add	%sp, PTREGS_OFF, %o0 + +	.align	32  sys_clone:  	flushw -	movrz	%o1, %fp, %o1 -	mov	0, %o3 -	ba,pt	%xcc, sparc_do_fork -	 add	%sp, PTREGS_OFF, %o2 +	ba,pt	%xcc, sparc_clone +	 add	%sp, PTREGS_OFF, %o0  	.globl	ret_from_fork  ret_from_fork: diff --git a/arch/sparc/kernel/syscalls/syscall.tbl b/arch/sparc/kernel/syscalls/syscall.tbl index 8004a276cb74..4af114e84f20 100644 --- a/arch/sparc/kernel/syscalls/syscall.tbl +++ b/arch/sparc/kernel/syscalls/syscall.tbl @@ -147,7 +147,7 @@  115	32	getgroups32		sys_getgroups  116	common	gettimeofday		sys_gettimeofday		compat_sys_gettimeofday  117	common	getrusage		sys_getrusage			compat_sys_getrusage -118	common	getsockopt		sys_getsockopt			compat_sys_getsockopt +118	common	getsockopt		sys_getsockopt			sys_getsockopt  119	common	getcwd			sys_getcwd  120	common	readv			sys_readv			compat_sys_readv  121	common	writev			sys_writev			compat_sys_writev @@ -300,7 +300,7 @@  249	64	nanosleep		sys_nanosleep  250	32	mremap			sys_mremap  250	64	mremap			sys_64_mremap -251	common	_sysctl			sys_sysctl			compat_sys_sysctl +251	common	_sysctl			sys_ni_syscall  252	common	getsid			sys_getsid  253	common	fdatasync		sys_fdatasync  254	32	nfsservctl		sys_ni_syscall			sys_nis_syscall @@ -425,7 +425,7 @@  352	common	userfaultfd		sys_userfaultfd  353	common	bind			sys_bind  354	common	listen			sys_listen -355	common	setsockopt		sys_setsockopt			compat_sys_setsockopt +355	common	setsockopt		sys_setsockopt			sys_setsockopt  356	common	mlock2			sys_mlock2  357	common	copy_file_range		sys_copy_file_range  358	common	preadv2			sys_preadv2			compat_sys_preadv2 @@ -481,6 +481,7 @@  433	common	fspick				sys_fspick  434	common	pidfd_open			sys_pidfd_open  # 435 reserved for clone3 +436	common	close_range			sys_close_range  437	common	openat2			sys_openat2  438	common	pidfd_getfd			sys_pidfd_getfd  439	common	faccessat2			sys_faccessat2 diff --git a/arch/sparc/kernel/vdso.c b/arch/sparc/kernel/vdso.c index 58880662b271..0e27437eb97b 100644 --- a/arch/sparc/kernel/vdso.c +++ b/arch/sparc/kernel/vdso.c @@ -7,7 +7,6 @@   *  a different vsyscall implementation for Linux/IA32 and for the name.   */ -#include <linux/seqlock.h>  #include <linux/time.h>  #include <linux/timekeeper_internal.h> |