diff options
41 files changed, 1370 insertions, 2349 deletions
| diff --git a/arch/arc/kernel/ptrace.c b/arch/arc/kernel/ptrace.c index f49a054a1016..883391977fdf 100644 --- a/arch/arc/kernel/ptrace.c +++ b/arch/arc/kernel/ptrace.c @@ -18,88 +18,61 @@ static struct callee_regs *task_callee_regs(struct task_struct *tsk)  static int genregs_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 *ptregs = task_pt_regs(target);  	const struct callee_regs *cregs = task_callee_regs(target); -	int ret = 0;  	unsigned int stop_pc_val; -#define REG_O_CHUNK(START, END, PTR)	\ -	if (!ret)	\ -		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, PTR, \ -			offsetof(struct user_regs_struct, START), \ -			offsetof(struct user_regs_struct, END)); - -#define REG_O_ONE(LOC, PTR)	\ -	if (!ret)		\ -		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, PTR, \ -			offsetof(struct user_regs_struct, LOC), \ -			offsetof(struct user_regs_struct, LOC) + 4); - -#define REG_O_ZERO(LOC)		\ -	if (!ret)		\ -		ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, \ -			offsetof(struct user_regs_struct, LOC), \ -			offsetof(struct user_regs_struct, LOC) + 4); - -	REG_O_ZERO(pad); -	REG_O_ONE(scratch.bta, &ptregs->bta); -	REG_O_ONE(scratch.lp_start, &ptregs->lp_start); -	REG_O_ONE(scratch.lp_end, &ptregs->lp_end); -	REG_O_ONE(scratch.lp_count, &ptregs->lp_count); -	REG_O_ONE(scratch.status32, &ptregs->status32); -	REG_O_ONE(scratch.ret, &ptregs->ret); -	REG_O_ONE(scratch.blink, &ptregs->blink); -	REG_O_ONE(scratch.fp, &ptregs->fp); -	REG_O_ONE(scratch.gp, &ptregs->r26); -	REG_O_ONE(scratch.r12, &ptregs->r12); -	REG_O_ONE(scratch.r11, &ptregs->r11); -	REG_O_ONE(scratch.r10, &ptregs->r10); -	REG_O_ONE(scratch.r9, &ptregs->r9); -	REG_O_ONE(scratch.r8, &ptregs->r8); -	REG_O_ONE(scratch.r7, &ptregs->r7); -	REG_O_ONE(scratch.r6, &ptregs->r6); -	REG_O_ONE(scratch.r5, &ptregs->r5); -	REG_O_ONE(scratch.r4, &ptregs->r4); -	REG_O_ONE(scratch.r3, &ptregs->r3); -	REG_O_ONE(scratch.r2, &ptregs->r2); -	REG_O_ONE(scratch.r1, &ptregs->r1); -	REG_O_ONE(scratch.r0, &ptregs->r0); -	REG_O_ONE(scratch.sp, &ptregs->sp); - -	REG_O_ZERO(pad2); - -	REG_O_ONE(callee.r25, &cregs->r25); -	REG_O_ONE(callee.r24, &cregs->r24); -	REG_O_ONE(callee.r23, &cregs->r23); -	REG_O_ONE(callee.r22, &cregs->r22); -	REG_O_ONE(callee.r21, &cregs->r21); -	REG_O_ONE(callee.r20, &cregs->r20); -	REG_O_ONE(callee.r19, &cregs->r19); -	REG_O_ONE(callee.r18, &cregs->r18); -	REG_O_ONE(callee.r17, &cregs->r17); -	REG_O_ONE(callee.r16, &cregs->r16); -	REG_O_ONE(callee.r15, &cregs->r15); -	REG_O_ONE(callee.r14, &cregs->r14); -	REG_O_ONE(callee.r13, &cregs->r13); - -	REG_O_ONE(efa, &target->thread.fault_address); - -	if (!ret) { -		if (in_brkpt_trap(ptregs)) { -			stop_pc_val = target->thread.fault_address; -			pr_debug("\t\tstop_pc (brk-pt)\n"); -		} else { -			stop_pc_val = ptregs->ret; -			pr_debug("\t\tstop_pc (others)\n"); -		} - -		REG_O_ONE(stop_pc, &stop_pc_val); +	membuf_zero(&to, 4);	// pad +	membuf_store(&to, ptregs->bta); +	membuf_store(&to, ptregs->lp_start); +	membuf_store(&to, ptregs->lp_end); +	membuf_store(&to, ptregs->lp_count); +	membuf_store(&to, ptregs->status32); +	membuf_store(&to, ptregs->ret); +	membuf_store(&to, ptregs->blink); +	membuf_store(&to, ptregs->fp); +	membuf_store(&to, ptregs->r26);	// gp +	membuf_store(&to, ptregs->r12); +	membuf_store(&to, ptregs->r11); +	membuf_store(&to, ptregs->r10); +	membuf_store(&to, ptregs->r9); +	membuf_store(&to, ptregs->r8); +	membuf_store(&to, ptregs->r7); +	membuf_store(&to, ptregs->r6); +	membuf_store(&to, ptregs->r5); +	membuf_store(&to, ptregs->r4); +	membuf_store(&to, ptregs->r3); +	membuf_store(&to, ptregs->r2); +	membuf_store(&to, ptregs->r1); +	membuf_store(&to, ptregs->r0); +	membuf_store(&to, ptregs->sp); +	membuf_zero(&to, 4);	// pad2 +	membuf_store(&to, cregs->r25); +	membuf_store(&to, cregs->r24); +	membuf_store(&to, cregs->r23); +	membuf_store(&to, cregs->r22); +	membuf_store(&to, cregs->r21); +	membuf_store(&to, cregs->r20); +	membuf_store(&to, cregs->r19); +	membuf_store(&to, cregs->r18); +	membuf_store(&to, cregs->r17); +	membuf_store(&to, cregs->r16); +	membuf_store(&to, cregs->r15); +	membuf_store(&to, cregs->r14); +	membuf_store(&to, cregs->r13); +	membuf_store(&to, target->thread.fault_address); // efa + +	if (in_brkpt_trap(ptregs)) { +		stop_pc_val = target->thread.fault_address; +		pr_debug("\t\tstop_pc (brk-pt)\n"); +	} else { +		stop_pc_val = ptregs->ret; +		pr_debug("\t\tstop_pc (others)\n");  	} -	return ret; +	return membuf_store(&to, stop_pc_val); // stop_pc  }  static int genregs_set(struct task_struct *target, @@ -184,25 +157,20 @@ static int genregs_set(struct task_struct *target,  #ifdef CONFIG_ISA_ARCV2  static int arcv2regs_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, copy_sz;  	if (IS_ENABLED(CONFIG_ARC_HAS_ACCL_REGS)) -		copy_sz = sizeof(struct user_regs_arcv2); -	else -		copy_sz = 4;	/* r30 only */ +		/* +		 * itemized copy not needed like above as layout of regs (r30,r58,r59) +		 * is exactly same in kernel (pt_regs) and userspace (user_regs_arcv2) +		 */ +		return membuf_write(&to, ®s->r30, sizeof(struct user_regs_arcv2)); -	/* -	 * itemized copy not needed like above as layout of regs (r30,r58,r59) -	 * is exactly same in kernel (pt_regs) and userspace (user_regs_arcv2) -	 */ -	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, ®s->r30, -				  0, copy_sz); -	return ret; +	membuf_write(&to, ®s->r30, 4); /* r30 only */ +	return membuf_zero(&to, sizeof(struct user_regs_arcv2) - 4);  }  static int arcv2regs_set(struct task_struct *target, @@ -237,7 +205,7 @@ static const struct user_regset arc_regsets[] = {  	       .n = ELF_NGREG,  	       .size = sizeof(unsigned long),  	       .align = sizeof(unsigned long), -	       .get = genregs_get, +	       .regset_get = genregs_get,  	       .set = genregs_set,  	},  #ifdef CONFIG_ISA_ARCV2 @@ -246,7 +214,7 @@ static const struct user_regset arc_regsets[] = {  	       .n = ELF_ARCV2REG,  	       .size = sizeof(unsigned long),  	       .align = sizeof(unsigned long), -	       .get = arcv2regs_get, +	       .regset_get = arcv2regs_get,  	       .set = arcv2regs_set,  	},  #endif diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index d0f7c8896c96..2771e682220b 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c @@ -569,14 +569,9 @@ out:  static int gpr_get(struct task_struct *target,  		   const struct user_regset *regset, -		   unsigned int pos, unsigned int count, -		   void *kbuf, void __user *ubuf) +		   struct membuf to)  { -	struct pt_regs *regs = task_pt_regs(target); - -	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, -				   regs, -				   0, sizeof(*regs)); +	return membuf_write(&to, task_pt_regs(target), sizeof(struct pt_regs));  }  static int gpr_set(struct task_struct *target, @@ -602,12 +597,10 @@ static int gpr_set(struct task_struct *target,  static int fpa_get(struct task_struct *target,  		   const struct user_regset *regset, -		   unsigned int pos, unsigned int count, -		   void *kbuf, void __user *ubuf) +		   struct membuf to)  { -	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, -				   &task_thread_info(target)->fpstate, -				   0, sizeof(struct user_fp)); +	return membuf_write(&to, &task_thread_info(target)->fpstate, +				 sizeof(struct user_fp));  }  static int fpa_set(struct task_struct *target, @@ -642,41 +635,20 @@ static int fpa_set(struct task_struct *target,   *	vfp_set() ignores this chunk   *   * 1 word for the FPSCR - * - * The bounds-checking logic built into user_regset_copyout and friends - * means that we can make a simple sequence of calls to map the relevant data - * to/from the specified slice of the user regset structure.   */  static int vfp_get(struct task_struct *target,  		   const struct user_regset *regset, -		   unsigned int pos, unsigned int count, -		   void *kbuf, void __user *ubuf) +		   struct membuf to)  { -	int ret;  	struct thread_info *thread = task_thread_info(target);  	struct vfp_hard_struct const *vfp = &thread->vfpstate.hard; -	const size_t user_fpregs_offset = offsetof(struct user_vfp, fpregs);  	const size_t user_fpscr_offset = offsetof(struct user_vfp, fpscr);  	vfp_sync_hwstate(thread); -	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, -				  &vfp->fpregs, -				  user_fpregs_offset, -				  user_fpregs_offset + sizeof(vfp->fpregs)); -	if (ret) -		return ret; - -	ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, -				       user_fpregs_offset + sizeof(vfp->fpregs), -				       user_fpscr_offset); -	if (ret) -		return ret; - -	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, -				   &vfp->fpscr, -				   user_fpscr_offset, -				   user_fpscr_offset + sizeof(vfp->fpscr)); +	membuf_write(&to, vfp->fpregs, sizeof(vfp->fpregs)); +	membuf_zero(&to, user_fpscr_offset - sizeof(vfp->fpregs)); +	return membuf_store(&to, vfp->fpscr);  }  /* @@ -739,7 +711,7 @@ static const struct user_regset arm_regsets[] = {  		.n = ELF_NGREG,  		.size = sizeof(u32),  		.align = sizeof(u32), -		.get = gpr_get, +		.regset_get = gpr_get,  		.set = gpr_set  	},  	[REGSET_FPR] = { @@ -751,7 +723,7 @@ static const struct user_regset arm_regsets[] = {  		.n = sizeof(struct user_fp) / sizeof(u32),  		.size = sizeof(u32),  		.align = sizeof(u32), -		.get = fpa_get, +		.regset_get = fpa_get,  		.set = fpa_set  	},  #ifdef CONFIG_VFP @@ -764,7 +736,7 @@ static const struct user_regset arm_regsets[] = {  		.n = ARM_VFPREGS_SIZE / sizeof(u32),  		.size = sizeof(u32),  		.align = sizeof(u32), -		.get = vfp_get, +		.regset_get = vfp_get,  		.set = vfp_set  	},  #endif /* CONFIG_VFP */ diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c index 1e02e98e68dd..d8ebfd813e28 100644 --- a/arch/arm64/kernel/ptrace.c +++ b/arch/arm64/kernel/ptrace.c @@ -474,11 +474,10 @@ static int ptrace_hbp_set_addr(unsigned int note_type,  static int hw_break_get(struct task_struct *target,  			const struct user_regset *regset, -			unsigned int pos, unsigned int count, -			void *kbuf, void __user *ubuf) +			struct membuf to)  {  	unsigned int note_type = regset->core_note_type; -	int ret, idx = 0, offset, limit; +	int ret, idx = 0;  	u32 info, ctrl;  	u64 addr; @@ -487,49 +486,21 @@ static int hw_break_get(struct task_struct *target,  	if (ret)  		return ret; -	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &info, 0, -				  sizeof(info)); -	if (ret) -		return ret; - -	/* Pad */ -	offset = offsetof(struct user_hwdebug_state, pad); -	ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, offset, -				       offset + PTRACE_HBP_PAD_SZ); -	if (ret) -		return ret; - +	membuf_write(&to, &info, sizeof(info)); +	membuf_zero(&to, sizeof(u32));  	/* (address, ctrl) registers */ -	offset = offsetof(struct user_hwdebug_state, dbg_regs); -	limit = regset->n * regset->size; -	while (count && offset < limit) { +	while (to.left) {  		ret = ptrace_hbp_get_addr(note_type, target, idx, &addr);  		if (ret)  			return ret; -		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &addr, -					  offset, offset + PTRACE_HBP_ADDR_SZ); -		if (ret) -			return ret; -		offset += PTRACE_HBP_ADDR_SZ; -  		ret = ptrace_hbp_get_ctrl(note_type, target, idx, &ctrl);  		if (ret)  			return ret; -		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &ctrl, -					  offset, offset + PTRACE_HBP_CTRL_SZ); -		if (ret) -			return ret; -		offset += PTRACE_HBP_CTRL_SZ; - -		ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, -					       offset, -					       offset + PTRACE_HBP_PAD_SZ); -		if (ret) -			return ret; -		offset += PTRACE_HBP_PAD_SZ; +		membuf_store(&to, addr); +		membuf_store(&to, ctrl); +		membuf_zero(&to, sizeof(u32));  		idx++;  	} -  	return 0;  } @@ -589,11 +560,10 @@ static int hw_break_set(struct task_struct *target,  static int gpr_get(struct task_struct *target,  		   const struct user_regset *regset, -		   unsigned int pos, unsigned int count, -		   void *kbuf, void __user *ubuf) +		   struct membuf to)  {  	struct user_pt_regs *uregs = &task_pt_regs(target)->user_regs; -	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0, -1); +	return membuf_write(&to, uregs, sizeof(*uregs));  }  static int gpr_set(struct task_struct *target, const struct user_regset *regset, @@ -626,8 +596,7 @@ static int fpr_active(struct task_struct *target, const struct user_regset *regs   */  static int __fpr_get(struct task_struct *target,  		     const struct user_regset *regset, -		     unsigned int pos, unsigned int count, -		     void *kbuf, void __user *ubuf, unsigned int start_pos) +		     struct membuf to)  {  	struct user_fpsimd_state *uregs; @@ -635,13 +604,11 @@ static int __fpr_get(struct task_struct *target,  	uregs = &target->thread.uw.fpsimd_state; -	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, -				   start_pos, start_pos + sizeof(*uregs)); +	return membuf_write(&to, uregs, sizeof(*uregs));  }  static int fpr_get(struct task_struct *target, const struct user_regset *regset, -		   unsigned int pos, unsigned int count, -		   void *kbuf, void __user *ubuf) +		   struct membuf to)  {  	if (!system_supports_fpsimd())  		return -EINVAL; @@ -649,7 +616,7 @@ static int fpr_get(struct task_struct *target, const struct user_regset *regset,  	if (target == current)  		fpsimd_preserve_current_state(); -	return __fpr_get(target, regset, pos, count, kbuf, ubuf, 0); +	return __fpr_get(target, regset, to);  }  static int __fpr_set(struct task_struct *target, @@ -699,15 +666,12 @@ static int fpr_set(struct task_struct *target, const struct user_regset *regset,  }  static int tls_get(struct task_struct *target, const struct user_regset *regset, -		   unsigned int pos, unsigned int count, -		   void *kbuf, void __user *ubuf) +		   struct membuf to)  { -	unsigned long *tls = &target->thread.uw.tp_value; -  	if (target == current)  		tls_preserve_current_state(); -	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, tls, 0, -1); +	return membuf_store(&to, target->thread.uw.tp_value);  }  static int tls_set(struct task_struct *target, const struct user_regset *regset, @@ -727,13 +691,9 @@ static int tls_set(struct task_struct *target, const struct user_regset *regset,  static int system_call_get(struct task_struct *target,  			   const struct user_regset *regset, -			   unsigned int pos, unsigned int count, -			   void *kbuf, void __user *ubuf) +			   struct membuf to)  { -	int syscallno = task_pt_regs(target)->syscallno; - -	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, -				   &syscallno, 0, -1); +	return membuf_store(&to, task_pt_regs(target)->syscallno);  }  static int system_call_set(struct task_struct *target, @@ -780,24 +740,10 @@ static unsigned int sve_size_from_header(struct user_sve_header const *header)  	return ALIGN(header->size, SVE_VQ_BYTES);  } -static unsigned int sve_get_size(struct task_struct *target, -				 const struct user_regset *regset) -{ -	struct user_sve_header header; - -	if (!system_supports_sve()) -		return 0; - -	sve_init_header_from_task(&header, target); -	return sve_size_from_header(&header); -} -  static int sve_get(struct task_struct *target,  		   const struct user_regset *regset, -		   unsigned int pos, unsigned int count, -		   void *kbuf, void __user *ubuf) +		   struct membuf to)  { -	int ret;  	struct user_sve_header header;  	unsigned int vq;  	unsigned long start, end; @@ -809,10 +755,7 @@ static int sve_get(struct task_struct *target,  	sve_init_header_from_task(&header, target);  	vq = sve_vq_from_vl(header.vl); -	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &header, -				  0, sizeof(header)); -	if (ret) -		return ret; +	membuf_write(&to, &header, sizeof(header));  	if (target == current)  		fpsimd_preserve_current_state(); @@ -821,26 +764,18 @@ static int sve_get(struct task_struct *target,  	BUILD_BUG_ON(SVE_PT_FPSIMD_OFFSET != sizeof(header));  	if ((header.flags & SVE_PT_REGS_MASK) == SVE_PT_REGS_FPSIMD) -		return __fpr_get(target, regset, pos, count, kbuf, ubuf, -				 SVE_PT_FPSIMD_OFFSET); +		return __fpr_get(target, regset, to);  	/* Otherwise: full SVE case */  	BUILD_BUG_ON(SVE_PT_SVE_OFFSET != sizeof(header));  	start = SVE_PT_SVE_OFFSET;  	end = SVE_PT_SVE_FFR_OFFSET(vq) + SVE_PT_SVE_FFR_SIZE(vq); -	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, -				  target->thread.sve_state, -				  start, end); -	if (ret) -		return ret; +	membuf_write(&to, target->thread.sve_state, end - start);  	start = end;  	end = SVE_PT_SVE_FPSR_OFFSET(vq); -	ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, -				       start, end); -	if (ret) -		return ret; +	membuf_zero(&to, end - start);  	/*  	 * Copy fpsr, and fpcr which must follow contiguously in @@ -848,16 +783,11 @@ static int sve_get(struct task_struct *target,  	 */  	start = end;  	end = SVE_PT_SVE_FPCR_OFFSET(vq) + SVE_PT_SVE_FPCR_SIZE; -	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, -				  &target->thread.uw.fpsimd_state.fpsr, -				  start, end); -	if (ret) -		return ret; +	membuf_write(&to, &target->thread.uw.fpsimd_state.fpsr, end - start);  	start = end;  	end = sve_size_from_header(&header); -	return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, -					start, end); +	return membuf_zero(&to, end - start);  }  static int sve_set(struct task_struct *target, @@ -961,8 +891,7 @@ out:  #ifdef CONFIG_ARM64_PTR_AUTH  static int pac_mask_get(struct task_struct *target,  			const struct user_regset *regset, -			unsigned int pos, unsigned int count, -			void *kbuf, void __user *ubuf) +			struct membuf to)  {  	/*  	 * The PAC bits can differ across data and instruction pointers @@ -978,7 +907,7 @@ static int pac_mask_get(struct task_struct *target,  	if (!system_supports_address_auth())  		return -EINVAL; -	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &uregs, 0, -1); +	return membuf_write(&to, &uregs, sizeof(uregs));  }  #ifdef CONFIG_CHECKPOINT_RESTORE @@ -1017,8 +946,7 @@ static void pac_address_keys_from_user(struct ptrauth_keys_user *keys,  static int pac_address_keys_get(struct task_struct *target,  				const struct user_regset *regset, -				unsigned int pos, unsigned int count, -				void *kbuf, void __user *ubuf) +				struct membuf to)  {  	struct ptrauth_keys_user *keys = &target->thread.keys_user;  	struct user_pac_address_keys user_keys; @@ -1028,8 +956,7 @@ static int pac_address_keys_get(struct task_struct *target,  	pac_address_keys_to_user(&user_keys, keys); -	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, -				   &user_keys, 0, -1); +	return membuf_write(&to, &user_keys, sizeof(user_keys));  }  static int pac_address_keys_set(struct task_struct *target, @@ -1068,8 +995,7 @@ static void pac_generic_keys_from_user(struct ptrauth_keys_user *keys,  static int pac_generic_keys_get(struct task_struct *target,  				const struct user_regset *regset, -				unsigned int pos, unsigned int count, -				void *kbuf, void __user *ubuf) +				struct membuf to)  {  	struct ptrauth_keys_user *keys = &target->thread.keys_user;  	struct user_pac_generic_keys user_keys; @@ -1079,8 +1005,7 @@ static int pac_generic_keys_get(struct task_struct *target,  	pac_generic_keys_to_user(&user_keys, keys); -	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, -				   &user_keys, 0, -1); +	return membuf_write(&to, &user_keys, sizeof(user_keys));  }  static int pac_generic_keys_set(struct task_struct *target, @@ -1134,7 +1059,7 @@ static const struct user_regset aarch64_regsets[] = {  		.n = sizeof(struct user_pt_regs) / sizeof(u64),  		.size = sizeof(u64),  		.align = sizeof(u64), -		.get = gpr_get, +		.regset_get = gpr_get,  		.set = gpr_set  	},  	[REGSET_FPR] = { @@ -1147,7 +1072,7 @@ static const struct user_regset aarch64_regsets[] = {  		.size = sizeof(u32),  		.align = sizeof(u32),  		.active = fpr_active, -		.get = fpr_get, +		.regset_get = fpr_get,  		.set = fpr_set  	},  	[REGSET_TLS] = { @@ -1155,7 +1080,7 @@ static const struct user_regset aarch64_regsets[] = {  		.n = 1,  		.size = sizeof(void *),  		.align = sizeof(void *), -		.get = tls_get, +		.regset_get = tls_get,  		.set = tls_set,  	},  #ifdef CONFIG_HAVE_HW_BREAKPOINT @@ -1164,7 +1089,7 @@ static const struct user_regset aarch64_regsets[] = {  		.n = sizeof(struct user_hwdebug_state) / sizeof(u32),  		.size = sizeof(u32),  		.align = sizeof(u32), -		.get = hw_break_get, +		.regset_get = hw_break_get,  		.set = hw_break_set,  	},  	[REGSET_HW_WATCH] = { @@ -1172,7 +1097,7 @@ static const struct user_regset aarch64_regsets[] = {  		.n = sizeof(struct user_hwdebug_state) / sizeof(u32),  		.size = sizeof(u32),  		.align = sizeof(u32), -		.get = hw_break_get, +		.regset_get = hw_break_get,  		.set = hw_break_set,  	},  #endif @@ -1181,7 +1106,7 @@ static const struct user_regset aarch64_regsets[] = {  		.n = 1,  		.size = sizeof(int),  		.align = sizeof(int), -		.get = system_call_get, +		.regset_get = system_call_get,  		.set = system_call_set,  	},  #ifdef CONFIG_ARM64_SVE @@ -1191,9 +1116,8 @@ static const struct user_regset aarch64_regsets[] = {  				  SVE_VQ_BYTES),  		.size = SVE_VQ_BYTES,  		.align = SVE_VQ_BYTES, -		.get = sve_get, +		.regset_get = sve_get,  		.set = sve_set, -		.get_size = sve_get_size,  	},  #endif  #ifdef CONFIG_ARM64_PTR_AUTH @@ -1202,7 +1126,7 @@ static const struct user_regset aarch64_regsets[] = {  		.n = sizeof(struct user_pac_mask) / sizeof(u64),  		.size = sizeof(u64),  		.align = sizeof(u64), -		.get = pac_mask_get, +		.regset_get = pac_mask_get,  		/* this cannot be set dynamically */  	},  #ifdef CONFIG_CHECKPOINT_RESTORE @@ -1211,7 +1135,7 @@ static const struct user_regset aarch64_regsets[] = {  		.n = sizeof(struct user_pac_address_keys) / sizeof(__uint128_t),  		.size = sizeof(__uint128_t),  		.align = sizeof(__uint128_t), -		.get = pac_address_keys_get, +		.regset_get = pac_address_keys_get,  		.set = pac_address_keys_set,  	},  	[REGSET_PACG_KEYS] = { @@ -1219,7 +1143,7 @@ static const struct user_regset aarch64_regsets[] = {  		.n = sizeof(struct user_pac_generic_keys) / sizeof(__uint128_t),  		.size = sizeof(__uint128_t),  		.align = sizeof(__uint128_t), -		.get = pac_generic_keys_get, +		.regset_get = pac_generic_keys_get,  		.set = pac_generic_keys_set,  	},  #endif @@ -1237,57 +1161,31 @@ enum compat_regset {  	REGSET_COMPAT_VFP,  }; -static int compat_gpr_get(struct task_struct *target, -			  const struct user_regset *regset, -			  unsigned int pos, unsigned int count, -			  void *kbuf, void __user *ubuf) +static inline compat_ulong_t compat_get_user_reg(struct task_struct *task, int idx)  { -	int ret = 0; -	unsigned int i, start, num_regs; +	struct pt_regs *regs = task_pt_regs(task); -	/* Calculate the number of AArch32 registers contained in count */ -	num_regs = count / regset->size; - -	/* Convert pos into an register number */ -	start = pos / regset->size; - -	if (start + num_regs > regset->n) -		return -EIO; - -	for (i = 0; i < num_regs; ++i) { -		unsigned int idx = start + i; -		compat_ulong_t reg; - -		switch (idx) { -		case 15: -			reg = task_pt_regs(target)->pc; -			break; -		case 16: -			reg = task_pt_regs(target)->pstate; -			reg = pstate_to_compat_psr(reg); -			break; -		case 17: -			reg = task_pt_regs(target)->orig_x0; -			break; -		default: -			reg = task_pt_regs(target)->regs[idx]; -		} - -		if (kbuf) { -			memcpy(kbuf, ®, sizeof(reg)); -			kbuf += sizeof(reg); -		} else { -			ret = copy_to_user(ubuf, ®, sizeof(reg)); -			if (ret) { -				ret = -EFAULT; -				break; -			} - -			ubuf += sizeof(reg); -		} +	switch (idx) { +	case 15: +		return regs->pc; +	case 16: +		return pstate_to_compat_psr(regs->pstate); +	case 17: +		return regs->orig_x0; +	default: +		return regs->regs[idx];  	} +} -	return ret; +static int compat_gpr_get(struct task_struct *target, +			  const struct user_regset *regset, +			  struct membuf to) +{ +	int i = 0; + +	while (to.left) +		membuf_store(&to, compat_get_user_reg(target, i++)); +	return 0;  }  static int compat_gpr_set(struct task_struct *target, @@ -1354,12 +1252,10 @@ static int compat_gpr_set(struct task_struct *target,  static int compat_vfp_get(struct task_struct *target,  			  const struct user_regset *regset, -			  unsigned int pos, unsigned int count, -			  void *kbuf, void __user *ubuf) +			  struct membuf to)  {  	struct user_fpsimd_state *uregs;  	compat_ulong_t fpscr; -	int ret, vregs_end_pos;  	if (!system_supports_fpsimd())  		return -EINVAL; @@ -1373,19 +1269,10 @@ static int compat_vfp_get(struct task_struct *target,  	 * The VFP registers are packed into the fpsimd_state, so they all sit  	 * nicely together for us. We just need to create the fpscr separately.  	 */ -	vregs_end_pos = VFP_STATE_SIZE - sizeof(compat_ulong_t); -	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, -				  0, vregs_end_pos); - -	if (count && !ret) { -		fpscr = (uregs->fpsr & VFP_FPSCR_STAT_MASK) | -			(uregs->fpcr & VFP_FPSCR_CTRL_MASK); - -		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &fpscr, -					  vregs_end_pos, VFP_STATE_SIZE); -	} - -	return ret; +	membuf_write(&to, uregs, VFP_STATE_SIZE - sizeof(compat_ulong_t)); +	fpscr = (uregs->fpsr & VFP_FPSCR_STAT_MASK) | +		(uregs->fpcr & VFP_FPSCR_CTRL_MASK); +	return membuf_store(&to, fpscr);  }  static int compat_vfp_set(struct task_struct *target, @@ -1420,11 +1307,10 @@ static int compat_vfp_set(struct task_struct *target,  }  static int compat_tls_get(struct task_struct *target, -			  const struct user_regset *regset, unsigned int pos, -			  unsigned int count, void *kbuf, void __user *ubuf) +			  const struct user_regset *regset, +			  struct membuf to)  { -	compat_ulong_t tls = (compat_ulong_t)target->thread.uw.tp_value; -	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &tls, 0, -1); +	return membuf_store(&to, (compat_ulong_t)target->thread.uw.tp_value);  }  static int compat_tls_set(struct task_struct *target, @@ -1449,7 +1335,7 @@ static const struct user_regset aarch32_regsets[] = {  		.n = COMPAT_ELF_NGREG,  		.size = sizeof(compat_elf_greg_t),  		.align = sizeof(compat_elf_greg_t), -		.get = compat_gpr_get, +		.regset_get = compat_gpr_get,  		.set = compat_gpr_set  	},  	[REGSET_COMPAT_VFP] = { @@ -1458,7 +1344,7 @@ static const struct user_regset aarch32_regsets[] = {  		.size = sizeof(compat_ulong_t),  		.align = sizeof(compat_ulong_t),  		.active = fpr_active, -		.get = compat_vfp_get, +		.regset_get = compat_vfp_get,  		.set = compat_vfp_set  	},  }; @@ -1474,7 +1360,7 @@ static const struct user_regset aarch32_ptrace_regsets[] = {  		.n = COMPAT_ELF_NGREG,  		.size = sizeof(compat_elf_greg_t),  		.align = sizeof(compat_elf_greg_t), -		.get = compat_gpr_get, +		.regset_get = compat_gpr_get,  		.set = compat_gpr_set  	},  	[REGSET_FPR] = { @@ -1482,7 +1368,7 @@ static const struct user_regset aarch32_ptrace_regsets[] = {  		.n = VFP_STATE_SIZE / sizeof(compat_ulong_t),  		.size = sizeof(compat_ulong_t),  		.align = sizeof(compat_ulong_t), -		.get = compat_vfp_get, +		.regset_get = compat_vfp_get,  		.set = compat_vfp_set  	},  	[REGSET_TLS] = { @@ -1490,7 +1376,7 @@ static const struct user_regset aarch32_ptrace_regsets[] = {  		.n = 1,  		.size = sizeof(compat_ulong_t),  		.align = sizeof(compat_ulong_t), -		.get = compat_tls_get, +		.regset_get = compat_tls_get,  		.set = compat_tls_set,  	},  #ifdef CONFIG_HAVE_HW_BREAKPOINT @@ -1499,7 +1385,7 @@ static const struct user_regset aarch32_ptrace_regsets[] = {  		.n = sizeof(struct user_hwdebug_state) / sizeof(u32),  		.size = sizeof(u32),  		.align = sizeof(u32), -		.get = hw_break_get, +		.regset_get = hw_break_get,  		.set = hw_break_set,  	},  	[REGSET_HW_WATCH] = { @@ -1507,7 +1393,7 @@ static const struct user_regset aarch32_ptrace_regsets[] = {  		.n = sizeof(struct user_hwdebug_state) / sizeof(u32),  		.size = sizeof(u32),  		.align = sizeof(u32), -		.get = hw_break_get, +		.regset_get = hw_break_get,  		.set = hw_break_set,  	},  #endif @@ -1516,7 +1402,7 @@ static const struct user_regset aarch32_ptrace_regsets[] = {  		.n = 1,  		.size = sizeof(int),  		.align = sizeof(int), -		.get = system_call_get, +		.regset_get = system_call_get,  		.set = system_call_set,  	},  }; @@ -1541,9 +1427,7 @@ static int compat_ptrace_read_user(struct task_struct *tsk, compat_ulong_t off,  	else if (off == COMPAT_PT_TEXT_END_ADDR)  		tmp = tsk->mm->end_code;  	else if (off < sizeof(compat_elf_gregset_t)) -		return copy_regset_to_user(tsk, &user_aarch32_view, -					   REGSET_COMPAT_GPR, off, -					   sizeof(compat_ulong_t), ret); +		tmp = compat_get_user_reg(tsk, off >> 2);  	else if (off >= COMPAT_USER_SZ)  		return -EIO;  	else @@ -1555,8 +1439,8 @@ static int compat_ptrace_read_user(struct task_struct *tsk, compat_ulong_t off,  static int compat_ptrace_write_user(struct task_struct *tsk, compat_ulong_t off,  				    compat_ulong_t val)  { -	int ret; -	mm_segment_t old_fs = get_fs(); +	struct pt_regs newregs = *task_pt_regs(tsk); +	unsigned int idx = off / 4;  	if (off & 3 || off >= COMPAT_USER_SZ)  		return -EIO; @@ -1564,14 +1448,25 @@ static int compat_ptrace_write_user(struct task_struct *tsk, compat_ulong_t off,  	if (off >= sizeof(compat_elf_gregset_t))  		return 0; -	set_fs(KERNEL_DS); -	ret = copy_regset_from_user(tsk, &user_aarch32_view, -				    REGSET_COMPAT_GPR, off, -				    sizeof(compat_ulong_t), -				    &val); -	set_fs(old_fs); +	switch (idx) { +	case 15: +		newregs.pc = val; +		break; +	case 16: +		newregs.pstate = compat_psr_to_pstate(val); +		break; +	case 17: +		newregs.orig_x0 = val; +		break; +	default: +		newregs.regs[idx] = val; +	} -	return ret; +	if (!valid_user_regs(&newregs.user_regs, tsk)) +		return -EINVAL; + +	*task_pt_regs(tsk) = newregs; +	return 0;  }  #ifdef CONFIG_HAVE_HW_BREAKPOINT diff --git a/arch/c6x/kernel/ptrace.c b/arch/c6x/kernel/ptrace.c index 67af1562da86..3cdaa8cf0ed6 100644 --- a/arch/c6x/kernel/ptrace.c +++ b/arch/c6x/kernel/ptrace.c @@ -57,14 +57,9 @@ static inline int put_reg(struct task_struct *task,  static int gpr_get(struct task_struct *target,  		   const struct user_regset *regset, -		   unsigned int pos, unsigned int count, -		   void *kbuf, void __user *ubuf) +		   struct membuf to)  { -	struct pt_regs *regs = task_pt_regs(target); - -	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, -				   regs, -				   0, sizeof(*regs)); +	return membuf_write(&to, task_pt_regs(target), sizeof(struct pt_regs));  }  enum c6x_regset { @@ -77,7 +72,7 @@ static const struct user_regset c6x_regsets[] = {  		.n = ELF_NGREG,  		.size = sizeof(u32),  		.align = sizeof(u32), -		.get = gpr_get, +		.regset_get = gpr_get,  	},  }; diff --git a/arch/csky/kernel/ptrace.c b/arch/csky/kernel/ptrace.c index b06612c408c4..d822144906ac 100644 --- a/arch/csky/kernel/ptrace.c +++ b/arch/csky/kernel/ptrace.c @@ -76,17 +76,14 @@ enum csky_regset {  static int gpr_get(struct task_struct *target,  		   const struct user_regset *regset, -		   unsigned int pos, unsigned int count, -		   void *kbuf, void __user *ubuf) +		   struct membuf to)  { -	struct pt_regs *regs; - -	regs = task_pt_regs(target); +	struct pt_regs *regs = task_pt_regs(target);  	/* Abiv1 regs->tls is fake and we need sync here. */  	regs->tls = task_thread_info(target)->tp_value; -	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, regs, 0, -1); +	return membuf_write(&to, regs, sizeof(regs));  }  static int gpr_set(struct task_struct *target, @@ -114,8 +111,7 @@ static int gpr_set(struct task_struct *target,  static int fpr_get(struct task_struct *target,  		   const struct user_regset *regset, -		   unsigned int pos, unsigned int count, -		   void *kbuf, void __user *ubuf) +		   struct membuf to)  {  	struct user_fp *regs = (struct user_fp *)&target->thread.user_fp; @@ -131,9 +127,9 @@ static int fpr_get(struct task_struct *target,  	for (i = 0; i < 32; i++)  		tmp.vr[64 + i] = regs->vr[32 + i]; -	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &tmp, 0, -1); +	return membuf_write(&to, &tmp, sizeof(tmp));  #else -	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, regs, 0, -1); +	return membuf_write(&to, regs, sizeof(*regs));  #endif  } @@ -173,16 +169,16 @@ static const struct user_regset csky_regsets[] = {  		.n = sizeof(struct pt_regs) / sizeof(u32),  		.size = sizeof(u32),  		.align = sizeof(u32), -		.get = &gpr_get, -		.set = &gpr_set, +		.regset_get = gpr_get, +		.set = gpr_set,  	},  	[REGSET_FPR] = {  		.core_note_type = NT_PRFPREG,  		.n = sizeof(struct user_fp) / sizeof(u32),  		.size = sizeof(u32),  		.align = sizeof(u32), -		.get = &fpr_get, -		.set = &fpr_set, +		.regset_get = fpr_get, +		.set = fpr_set,  	},  }; diff --git a/arch/h8300/kernel/ptrace.c b/arch/h8300/kernel/ptrace.c index 0dc1c8f622bc..a11db009d0ea 100644 --- a/arch/h8300/kernel/ptrace.c +++ b/arch/h8300/kernel/ptrace.c @@ -87,20 +87,15 @@ int h8300_put_reg(struct task_struct *task, int regno, unsigned long data)  static int regs_get(struct task_struct *target,  		    const struct user_regset *regset, -		    unsigned int pos, unsigned int count, -		    void *kbuf, void __user *ubuf) +		    struct membuf to)  {  	int r; -	struct user_regs_struct regs; -	long *reg = (long *)®s; -	/* build user regs in buffer */ -	BUILD_BUG_ON(sizeof(regs) % sizeof(long) != 0); -	for (r = 0; r < sizeof(regs) / sizeof(long); r++) -		*reg++ = h8300_get_reg(target, r); +	BUILD_BUG_ON(sizeof(struct user_regs_struct) % sizeof(long) != 0); +	for (r = 0; r < ELF_NGREG; r++) +		membuf_store(&to, h8300_get_reg(target, r)); -	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, -				   ®s, 0, sizeof(regs)); +	return 0;  }  static int regs_set(struct task_struct *target, @@ -139,7 +134,7 @@ static const struct user_regset h8300_regsets[] = {  		.n		= ELF_NGREG,  		.size		= sizeof(long),  		.align		= sizeof(long), -		.get		= regs_get, +		.regset_get		= regs_get,  		.set		= regs_set,  	},  }; diff --git a/arch/hexagon/kernel/ptrace.c b/arch/hexagon/kernel/ptrace.c index dcbf7ea960cc..a5a89e944257 100644 --- a/arch/hexagon/kernel/ptrace.c +++ b/arch/hexagon/kernel/ptrace.c @@ -35,58 +35,38 @@ void user_disable_single_step(struct task_struct *child)  static int genregs_get(struct task_struct *target,  		   const struct user_regset *regset, -		   unsigned int pos, unsigned int count, -		   void *kbuf, void __user *ubuf) +		   srtuct membuf to)  { -	int ret; -	unsigned int dummy;  	struct pt_regs *regs = task_pt_regs(target); - -	if (!regs) -		return -EIO; -  	/* The general idea here is that the copyout must happen in  	 * exactly the same order in which the userspace expects these  	 * regs. Now, the sequence in userspace does not match the  	 * sequence in the kernel, so everything past the 32 gprs  	 * happens one at a time.  	 */ -	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, -				  ®s->r00, 0, 32*sizeof(unsigned long)); - -#define ONEXT(KPT_REG, USR_REG) \ -	if (!ret) \ -		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, \ -			KPT_REG, offsetof(struct user_regs_struct, USR_REG), \ -			offsetof(struct user_regs_struct, USR_REG) + \ -				 sizeof(unsigned long)); - +	membuf_write(&to, ®s->r00, 32*sizeof(unsigned long));  	/* Must be exactly same sequence as struct user_regs_struct */ -	ONEXT(®s->sa0, sa0); -	ONEXT(®s->lc0, lc0); -	ONEXT(®s->sa1, sa1); -	ONEXT(®s->lc1, lc1); -	ONEXT(®s->m0, m0); -	ONEXT(®s->m1, m1); -	ONEXT(®s->usr, usr); -	ONEXT(®s->preds, p3_0); -	ONEXT(®s->gp, gp); -	ONEXT(®s->ugp, ugp); -	ONEXT(&pt_elr(regs), pc); -	dummy = pt_cause(regs); -	ONEXT(&dummy, cause); -	ONEXT(&pt_badva(regs), badva); +	membuf_store(&to, regs->sa0); +	membuf_store(&to, regs->lc0); +	membuf_store(&to, regs->sa1); +	membuf_store(&to, regs->lc1); +	membuf_store(&to, regs->m0); +	membuf_store(&to, regs->m1); +	membuf_store(&to, regs->usr); +	membuf_store(&to, regs->p3_0); +	membuf_store(&to, regs->gp); +	membuf_store(&to, regs->ugp); +	membuf_store(&to, pt_elr(regs)); // pc +	membuf_store(&to, (unsigned long)pt_cause(regs)); // cause +	membuf_store(&to, pt_badva(regs)); // badva  #if CONFIG_HEXAGON_ARCH_VERSION >=4 -	ONEXT(®s->cs0, cs0); -	ONEXT(®s->cs1, cs1); +	membuf_store(&to, regs->cs0); +	membuf_store(&to, regs->cs1); +	return membuf_zero(&to, sizeof(unsigned long)); +#else +	return membuf_zero(&to, 3 * sizeof(unsigned long));  #endif - -	/* Pad the rest with zeros, if needed */ -	if (!ret) -		ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, -					offsetof(struct user_regs_struct, pad1), -1); -	return ret;  }  static int genregs_set(struct task_struct *target, @@ -159,7 +139,7 @@ static const struct user_regset hexagon_regsets[] = {  		.n = ELF_NGREG,  		.size = sizeof(unsigned long),  		.align = sizeof(unsigned long), -		.get = genregs_get, +		.regset_get = genregs_get,  		.set = genregs_set,  	},  }; diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c index 82aaacf64583..33ca9fa0fbf5 100644 --- a/arch/ia64/kernel/ptrace.c +++ b/arch/ia64/kernel/ptrace.c @@ -1273,52 +1273,43 @@ struct regset_getset {  	int ret;  }; +static const ptrdiff_t pt_offsets[32] = +{ +#define R(n) offsetof(struct pt_regs, r##n) +	[0] = -1, R(1), R(2), R(3), +	[4] = -1, [5] = -1, [6] = -1, [7] = -1, +	R(8), R(9), R(10), R(11), R(12), R(13), R(14), R(15), +	R(16), R(17), R(18), R(19), R(20), R(21), R(22), R(23), +	R(24), R(25), R(26), R(27), R(28), R(29), R(30), R(31), +#undef R +}; +  static int  access_elf_gpreg(struct task_struct *target, struct unw_frame_info *info,  		unsigned long addr, unsigned long *data, int write_access)  { -	struct pt_regs *pt; -	unsigned long *ptr = NULL; -	int ret; -	char nat = 0; +	struct pt_regs *pt = task_pt_regs(target); +	unsigned reg = addr / sizeof(unsigned long); +	ptrdiff_t d = pt_offsets[reg]; -	pt = task_pt_regs(target); -	switch (addr) { -	case ELF_GR_OFFSET(1): -		ptr = &pt->r1; -		break; -	case ELF_GR_OFFSET(2): -	case ELF_GR_OFFSET(3): -		ptr = (void *)&pt->r2 + (addr - ELF_GR_OFFSET(2)); -		break; -	case ELF_GR_OFFSET(4) ... ELF_GR_OFFSET(7): +	if (d >= 0) { +		unsigned long *ptr = (void *)pt + d; +		if (write_access) +			*ptr = *data; +		else +			*data = *ptr; +		return 0; +	} else { +		char nat = 0;  		if (write_access) {  			/* read NaT bit first: */  			unsigned long dummy; - -			ret = unw_get_gr(info, addr/8, &dummy, &nat); +			int ret = unw_get_gr(info, reg, &dummy, &nat);  			if (ret < 0)  				return ret;  		} -		return unw_access_gr(info, addr/8, data, &nat, write_access); -	case ELF_GR_OFFSET(8) ... ELF_GR_OFFSET(11): -		ptr = (void *)&pt->r8 + addr - ELF_GR_OFFSET(8); -		break; -	case ELF_GR_OFFSET(12): -	case ELF_GR_OFFSET(13): -		ptr = (void *)&pt->r12 + addr - ELF_GR_OFFSET(12); -		break; -	case ELF_GR_OFFSET(14): -		ptr = &pt->r14; -		break; -	case ELF_GR_OFFSET(15): -		ptr = &pt->r15; +		return unw_access_gr(info, reg, data, &nat, write_access);  	} -	if (write_access) -		*ptr = *data; -	else -		*data = *ptr; -	return 0;  }  static int @@ -1490,7 +1481,7 @@ static int  access_elf_reg(struct task_struct *target, struct unw_frame_info *info,  		unsigned long addr, unsigned long *data, int write_access)  { -	if (addr >= ELF_GR_OFFSET(1) && addr <= ELF_GR_OFFSET(15)) +	if (addr >= ELF_GR_OFFSET(1) && addr <= ELF_GR_OFFSET(31))  		return access_elf_gpreg(target, info, addr, data, write_access);  	else if (addr >= ELF_BR_OFFSET(0) && addr <= ELF_BR_OFFSET(7))  		return access_elf_breg(target, info, addr, data, write_access); @@ -1498,12 +1489,17 @@ access_elf_reg(struct task_struct *target, struct unw_frame_info *info,  		return access_elf_areg(target, info, addr, data, write_access);  } +struct regset_membuf { +	struct membuf to; +	int ret; +}; +  void do_gpregs_get(struct unw_frame_info *info, void *arg)  { -	struct pt_regs *pt; -	struct regset_getset *dst = arg; -	elf_greg_t tmp[16]; -	unsigned int i, index, min_copy; +	struct regset_membuf *dst = arg; +	struct membuf to = dst->to; +	unsigned int n; +	elf_greg_t reg;  	if (unw_unwind_to_user(info) < 0)  		return; @@ -1521,165 +1517,53 @@ void do_gpregs_get(struct unw_frame_info *info, void *arg)  	/* Skip r0 */ -	if (dst->count > 0 && dst->pos < ELF_GR_OFFSET(1)) { -		dst->ret = user_regset_copyout_zero(&dst->pos, &dst->count, -						      &dst->u.get.kbuf, -						      &dst->u.get.ubuf, -						      0, ELF_GR_OFFSET(1)); -		if (dst->ret || dst->count == 0) +	membuf_zero(&to, 8); +	for (n = 8; to.left && n < ELF_AR_END_OFFSET; n += 8) { +		if (access_elf_reg(info->task, info, n, ®, 0) < 0) { +			dst->ret = -EIO;  			return; -	} - -	/* gr1 - gr15 */ -	if (dst->count > 0 && dst->pos < ELF_GR_OFFSET(16)) { -		index = (dst->pos - ELF_GR_OFFSET(1)) / sizeof(elf_greg_t); -		min_copy = ELF_GR_OFFSET(16) > (dst->pos + dst->count) ? -			 (dst->pos + dst->count) : ELF_GR_OFFSET(16); -		for (i = dst->pos; i < min_copy; i += sizeof(elf_greg_t), -				index++) -			if (access_elf_reg(dst->target, info, i, -						&tmp[index], 0) < 0) { -				dst->ret = -EIO; -				return; -			} -		dst->ret = user_regset_copyout(&dst->pos, &dst->count, -				&dst->u.get.kbuf, &dst->u.get.ubuf, tmp, -				ELF_GR_OFFSET(1), ELF_GR_OFFSET(16)); -		if (dst->ret || dst->count == 0) -			return; -	} - -	/* r16-r31 */ -	if (dst->count > 0 && dst->pos < ELF_NAT_OFFSET) { -		pt = task_pt_regs(dst->target); -		dst->ret = user_regset_copyout(&dst->pos, &dst->count, -				&dst->u.get.kbuf, &dst->u.get.ubuf, &pt->r16, -				ELF_GR_OFFSET(16), ELF_NAT_OFFSET); -		if (dst->ret || dst->count == 0) -			return; -	} - -	/* nat, pr, b0 - b7 */ -	if (dst->count > 0 && dst->pos < ELF_CR_IIP_OFFSET) { -		index = (dst->pos - ELF_NAT_OFFSET) / sizeof(elf_greg_t); -		min_copy = ELF_CR_IIP_OFFSET > (dst->pos + dst->count) ? -			 (dst->pos + dst->count) : ELF_CR_IIP_OFFSET; -		for (i = dst->pos; i < min_copy; i += sizeof(elf_greg_t), -				index++) -			if (access_elf_reg(dst->target, info, i, -						&tmp[index], 0) < 0) { -				dst->ret = -EIO; -				return; -			} -		dst->ret = user_regset_copyout(&dst->pos, &dst->count, -				&dst->u.get.kbuf, &dst->u.get.ubuf, tmp, -				ELF_NAT_OFFSET, ELF_CR_IIP_OFFSET); -		if (dst->ret || dst->count == 0) -			return; -	} - -	/* ip cfm psr ar.rsc ar.bsp ar.bspstore ar.rnat -	 * ar.ccv ar.unat ar.fpsr ar.pfs ar.lc ar.ec ar.csd ar.ssd -	 */ -	if (dst->count > 0 && dst->pos < (ELF_AR_END_OFFSET)) { -		index = (dst->pos - ELF_CR_IIP_OFFSET) / sizeof(elf_greg_t); -		min_copy = ELF_AR_END_OFFSET > (dst->pos + dst->count) ? -			 (dst->pos + dst->count) : ELF_AR_END_OFFSET; -		for (i = dst->pos; i < min_copy; i += sizeof(elf_greg_t), -				index++) -			if (access_elf_reg(dst->target, info, i, -						&tmp[index], 0) < 0) { -				dst->ret = -EIO; -				return; -			} -		dst->ret = user_regset_copyout(&dst->pos, &dst->count, -				&dst->u.get.kbuf, &dst->u.get.ubuf, tmp, -				ELF_CR_IIP_OFFSET, ELF_AR_END_OFFSET); +		} +		membuf_store(&to, reg);  	}  }  void do_gpregs_set(struct unw_frame_info *info, void *arg)  { -	struct pt_regs *pt;  	struct regset_getset *dst = arg; -	elf_greg_t tmp[16]; -	unsigned int i, index;  	if (unw_unwind_to_user(info) < 0)  		return; +	if (!dst->count) +		return;  	/* Skip r0 */ -	if (dst->count > 0 && dst->pos < ELF_GR_OFFSET(1)) { +	if (dst->pos < ELF_GR_OFFSET(1)) {  		dst->ret = user_regset_copyin_ignore(&dst->pos, &dst->count,  						       &dst->u.set.kbuf,  						       &dst->u.set.ubuf,  						       0, ELF_GR_OFFSET(1)); -		if (dst->ret || dst->count == 0) -			return; -	} - -	/* gr1-gr15 */ -	if (dst->count > 0 && dst->pos < ELF_GR_OFFSET(16)) { -		i = dst->pos; -		index = (dst->pos - ELF_GR_OFFSET(1)) / sizeof(elf_greg_t); -		dst->ret = user_regset_copyin(&dst->pos, &dst->count, -				&dst->u.set.kbuf, &dst->u.set.ubuf, tmp, -				ELF_GR_OFFSET(1), ELF_GR_OFFSET(16));  		if (dst->ret)  			return; -		for ( ; i < dst->pos; i += sizeof(elf_greg_t), index++) -			if (access_elf_reg(dst->target, info, i, -						&tmp[index], 1) < 0) { -				dst->ret = -EIO; -				return; -			} -		if (dst->count == 0) -			return; -	} - -	/* gr16-gr31 */ -	if (dst->count > 0 && dst->pos < ELF_NAT_OFFSET) { -		pt = task_pt_regs(dst->target); -		dst->ret = user_regset_copyin(&dst->pos, &dst->count, -				&dst->u.set.kbuf, &dst->u.set.ubuf, &pt->r16, -				ELF_GR_OFFSET(16), ELF_NAT_OFFSET); -		if (dst->ret || dst->count == 0) -			return;  	} -	/* nat, pr, b0 - b7 */ -	if (dst->count > 0 && dst->pos < ELF_CR_IIP_OFFSET) { -		i = dst->pos; -		index = (dst->pos - ELF_NAT_OFFSET) / sizeof(elf_greg_t); -		dst->ret = user_regset_copyin(&dst->pos, &dst->count, -				&dst->u.set.kbuf, &dst->u.set.ubuf, tmp, -				ELF_NAT_OFFSET, ELF_CR_IIP_OFFSET); -		if (dst->ret) -			return; -		for (; i < dst->pos; i += sizeof(elf_greg_t), index++) -			if (access_elf_reg(dst->target, info, i, -						&tmp[index], 1) < 0) { -				dst->ret = -EIO; -				return; -			} -		if (dst->count == 0) -			return; -	} +	while (dst->count && dst->pos < ELF_AR_END_OFFSET) { +		unsigned int n, from, to; +		elf_greg_t tmp[16]; -	/* ip cfm psr ar.rsc ar.bsp ar.bspstore ar.rnat -	 * ar.ccv ar.unat ar.fpsr ar.pfs ar.lc ar.ec ar.csd ar.ssd -	 */ -	if (dst->count > 0 && dst->pos < (ELF_AR_END_OFFSET)) { -		i = dst->pos; -		index = (dst->pos - ELF_CR_IIP_OFFSET) / sizeof(elf_greg_t); +		from = dst->pos; +		to = from + sizeof(tmp); +		if (to > ELF_AR_END_OFFSET) +			to = ELF_AR_END_OFFSET; +		/* get up to 16 values */  		dst->ret = user_regset_copyin(&dst->pos, &dst->count,  				&dst->u.set.kbuf, &dst->u.set.ubuf, tmp, -				ELF_CR_IIP_OFFSET, ELF_AR_END_OFFSET); +				from, to);  		if (dst->ret)  			return; -		for ( ; i < dst->pos; i += sizeof(elf_greg_t), index++) -			if (access_elf_reg(dst->target, info, i, -						&tmp[index], 1) < 0) { +		/* now copy them into registers */ +		for (n = 0; from < dst->pos; from += sizeof(elf_greg_t), n++) +			if (access_elf_reg(dst->target, info, from, +						&tmp[n], 1) < 0) {  				dst->ret = -EIO;  				return;  			} @@ -1690,60 +1574,36 @@ void do_gpregs_set(struct unw_frame_info *info, void *arg)  void do_fpregs_get(struct unw_frame_info *info, void *arg)  { -	struct regset_getset *dst = arg; -	struct task_struct *task = dst->target; -	elf_fpreg_t tmp[30]; -	int index, min_copy, i; +	struct task_struct *task = info->task; +	struct regset_membuf *dst = arg; +	struct membuf to = dst->to; +	elf_fpreg_t reg; +	unsigned int n;  	if (unw_unwind_to_user(info) < 0)  		return;  	/* Skip pos 0 and 1 */ -	if (dst->count > 0 && dst->pos < ELF_FP_OFFSET(2)) { -		dst->ret = user_regset_copyout_zero(&dst->pos, &dst->count, -						      &dst->u.get.kbuf, -						      &dst->u.get.ubuf, -						      0, ELF_FP_OFFSET(2)); -		if (dst->count == 0 || dst->ret) -			return; -	} +	membuf_zero(&to, 2 * sizeof(elf_fpreg_t));  	/* fr2-fr31 */ -	if (dst->count > 0 && dst->pos < ELF_FP_OFFSET(32)) { -		index = (dst->pos - ELF_FP_OFFSET(2)) / sizeof(elf_fpreg_t); - -		min_copy = min(((unsigned int)ELF_FP_OFFSET(32)), -				dst->pos + dst->count); -		for (i = dst->pos; i < min_copy; i += sizeof(elf_fpreg_t), -				index++) -			if (unw_get_fr(info, i / sizeof(elf_fpreg_t), -					 &tmp[index])) { -				dst->ret = -EIO; -				return; -			} -		dst->ret = user_regset_copyout(&dst->pos, &dst->count, -				&dst->u.get.kbuf, &dst->u.get.ubuf, tmp, -				ELF_FP_OFFSET(2), ELF_FP_OFFSET(32)); -		if (dst->count == 0 || dst->ret) +	for (n = 2; to.left && n < 32; n++) { +		if (unw_get_fr(info, n, ®)) { +			dst->ret = -EIO;  			return; +		} +		membuf_write(&to, ®, sizeof(reg));  	}  	/* fph */ -	if (dst->count > 0) { -		ia64_flush_fph(dst->target); -		if (task->thread.flags & IA64_THREAD_FPH_VALID) -			dst->ret = user_regset_copyout( -				&dst->pos, &dst->count, -				&dst->u.get.kbuf, &dst->u.get.ubuf, -				&dst->target->thread.fph, -				ELF_FP_OFFSET(32), -1); -		else -			/* Zero fill instead.  */ -			dst->ret = user_regset_copyout_zero( -				&dst->pos, &dst->count, -				&dst->u.get.kbuf, &dst->u.get.ubuf, -				ELF_FP_OFFSET(32), -1); -	} +	if (!to.left) +		return; + +	ia64_flush_fph(task); +	if (task->thread.flags & IA64_THREAD_FPH_VALID) +		membuf_write(&to, &task->thread.fph, 96 * sizeof(reg)); +	else +		membuf_zero(&to, 96 * sizeof(reg));  }  void do_fpregs_set(struct unw_frame_info *info, void *arg) @@ -1819,6 +1679,20 @@ void do_fpregs_set(struct unw_frame_info *info, void *arg)  	}  } +static void +unwind_and_call(void (*call)(struct unw_frame_info *, void *), +	       struct task_struct *target, void *data) +{ +	if (target == current) +		unw_init_running(call, data); +	else { +		struct unw_frame_info info; +		memset(&info, 0, sizeof(info)); +		unw_init_from_blocked_task(&info, target); +		(*call)(&info, data); +	} +} +  static int  do_regset_call(void (*call)(struct unw_frame_info *, void *),  	       struct task_struct *target, @@ -1830,27 +1704,18 @@ do_regset_call(void (*call)(struct unw_frame_info *, void *),  				 .pos = pos, .count = count,  				 .u.set = { .kbuf = kbuf, .ubuf = ubuf },  				 .ret = 0 }; - -	if (target == current) -		unw_init_running(call, &info); -	else { -		struct unw_frame_info ufi; -		memset(&ufi, 0, sizeof(ufi)); -		unw_init_from_blocked_task(&ufi, target); -		(*call)(&ufi, &info); -	} - +	unwind_and_call(call, target, &info);  	return info.ret;  }  static int  gpregs_get(struct task_struct *target,  	   const struct user_regset *regset, -	   unsigned int pos, unsigned int count, -	   void *kbuf, void __user *ubuf) +	   struct membuf to)  { -	return do_regset_call(do_gpregs_get, target, regset, pos, count, -		kbuf, ubuf); +	struct regset_membuf info = {.to = to}; +	unwind_and_call(do_gpregs_get, target, &info); +	return info.ret;  }  static int gpregs_set(struct task_struct *target, @@ -1892,11 +1757,11 @@ fpregs_active(struct task_struct *target, const struct user_regset *regset)  static int fpregs_get(struct task_struct *target,  		const struct user_regset *regset, -		unsigned int pos, unsigned int count, -		void *kbuf, void __user *ubuf) +		struct membuf to)  { -	return do_regset_call(do_fpregs_get, target, regset, pos, count, -		kbuf, ubuf); +	struct regset_membuf info = {.to = to}; +	unwind_and_call(do_fpregs_get, target, &info); +	return info.ret;  }  static int fpregs_set(struct task_struct *target, @@ -1913,7 +1778,6 @@ access_uarea(struct task_struct *child, unsigned long addr,  	      unsigned long *data, int write_access)  {  	unsigned int pos = -1; /* an invalid value */ -	int ret;  	unsigned long *ptr, regnum;  	if ((addr & 0x7) != 0) { @@ -1945,14 +1809,39 @@ access_uarea(struct task_struct *child, unsigned long addr,  	}  	if (pos != -1) { -		if (write_access) -			ret = fpregs_set(child, NULL, pos, -				sizeof(unsigned long), data, NULL); -		else -			ret = fpregs_get(child, NULL, pos, -				sizeof(unsigned long), data, NULL); -		if (ret != 0) -			return -1; +		unsigned reg = pos / sizeof(elf_fpreg_t); +		int which_half = (pos / sizeof(unsigned long)) & 1; + +		if (reg < 32) { /* fr2-fr31 */ +			struct unw_frame_info info; +			elf_fpreg_t fpreg; + +			memset(&info, 0, sizeof(info)); +			unw_init_from_blocked_task(&info, child); +			if (unw_unwind_to_user(&info) < 0) +				return 0; + +			if (unw_get_fr(&info, reg, &fpreg)) +				return -1; +			if (write_access) { +				fpreg.u.bits[which_half] = *data; +				if (unw_set_fr(&info, reg, fpreg)) +					return -1; +			} else { +				*data = fpreg.u.bits[which_half]; +			} +		} else { /* fph */ +			elf_fpreg_t *p = &child->thread.fph[reg - 32]; +			unsigned long *bits = &p->u.bits[which_half]; + +			ia64_sync_fph(child); +			if (write_access) +				*bits = *data; +			else if (child->thread.flags & IA64_THREAD_FPH_VALID) +				*data = *bits; +			else +				*data = 0; +		}  		return 0;  	} @@ -2038,15 +1927,14 @@ access_uarea(struct task_struct *child, unsigned long addr,  	}  	if (pos != -1) { -		if (write_access) -			ret = gpregs_set(child, NULL, pos, -				sizeof(unsigned long), data, NULL); -		else -			ret = gpregs_get(child, NULL, pos, -				sizeof(unsigned long), data, NULL); -		if (ret != 0) -			return -1; -		return 0; +		struct unw_frame_info info; + +		memset(&info, 0, sizeof(info)); +		unw_init_from_blocked_task(&info, child); +		if (unw_unwind_to_user(&info) < 0) +			return 0; + +		return access_elf_reg(child, &info, pos, data, write_access);  	}  	/* access debug registers */ @@ -2112,14 +2000,14 @@ static const struct user_regset native_regsets[] = {  		.core_note_type = NT_PRSTATUS,  		.n = ELF_NGREG,  		.size = sizeof(elf_greg_t), .align = sizeof(elf_greg_t), -		.get = gpregs_get, .set = gpregs_set, +		.regset_get = gpregs_get, .set = gpregs_set,  		.writeback = gpregs_writeback  	},  	{  		.core_note_type = NT_PRFPREG,  		.n = ELF_NFPREG,  		.size = sizeof(elf_fpreg_t), .align = sizeof(elf_fpreg_t), -		.get = fpregs_get, .set = fpregs_set, .active = fpregs_active +		.regset_get = fpregs_get, .set = fpregs_set, .active = fpregs_active  	},  }; diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index 2a61641c680b..db7c5be1d4a3 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -210,15 +210,13 @@ int ptrace_set_watch_regs(struct task_struct *child,  static int gpr32_get(struct task_struct *target,  		     const struct user_regset *regset, -		     unsigned int pos, unsigned int count, -		     void *kbuf, void __user *ubuf) +		     struct membuf to)  {  	struct pt_regs *regs = task_pt_regs(target);  	u32 uregs[ELF_NGREG] = {};  	mips_dump_regs32(uregs, regs); -	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0, -				   sizeof(uregs)); +	return membuf_write(&to, uregs, sizeof(uregs));  }  static int gpr32_set(struct task_struct *target, @@ -277,15 +275,13 @@ static int gpr32_set(struct task_struct *target,  static int gpr64_get(struct task_struct *target,  		     const struct user_regset *regset, -		     unsigned int pos, unsigned int count, -		     void *kbuf, void __user *ubuf) +		     struct membuf to)  {  	struct pt_regs *regs = task_pt_regs(target);  	u64 uregs[ELF_NGREG] = {};  	mips_dump_regs64(uregs, regs); -	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0, -				   sizeof(uregs)); +	return membuf_write(&to, uregs, sizeof(uregs));  }  static int gpr64_set(struct task_struct *target, @@ -408,13 +404,11 @@ int ptrace_setfpregs(struct task_struct *child, __u32 __user *data)   * !CONFIG_CPU_HAS_MSA variant.  FP context's general register slots   * correspond 1:1 to buffer slots.  Only general registers are copied.   */ -static int fpr_get_fpa(struct task_struct *target, -		       unsigned int *pos, unsigned int *count, -		       void **kbuf, void __user **ubuf) +static void fpr_get_fpa(struct task_struct *target, +		       struct membuf *to)  { -	return user_regset_copyout(pos, count, kbuf, ubuf, -				   &target->thread.fpu, -				   0, NUM_FPU_REGS * sizeof(elf_fpreg_t)); +	membuf_write(to, &target->thread.fpu, +			NUM_FPU_REGS * sizeof(elf_fpreg_t));  }  /* @@ -423,25 +417,13 @@ static int fpr_get_fpa(struct task_struct *target,   * general register slots are copied to buffer slots.  Only general   * registers are copied.   */ -static int fpr_get_msa(struct task_struct *target, -		       unsigned int *pos, unsigned int *count, -		       void **kbuf, void __user **ubuf) +static void fpr_get_msa(struct task_struct *target, struct membuf *to)  {  	unsigned int i; -	u64 fpr_val; -	int err; - -	BUILD_BUG_ON(sizeof(fpr_val) != sizeof(elf_fpreg_t)); -	for (i = 0; i < NUM_FPU_REGS; i++) { -		fpr_val = get_fpr64(&target->thread.fpu.fpr[i], 0); -		err = user_regset_copyout(pos, count, kbuf, ubuf, -					  &fpr_val, i * sizeof(elf_fpreg_t), -					  (i + 1) * sizeof(elf_fpreg_t)); -		if (err) -			return err; -	} -	return 0; +	BUILD_BUG_ON(sizeof(u64) != sizeof(elf_fpreg_t)); +	for (i = 0; i < NUM_FPU_REGS; i++) +		membuf_store(to, get_fpr64(&target->thread.fpu.fpr[i], 0));  }  /* @@ -451,31 +433,16 @@ static int fpr_get_msa(struct task_struct *target,   */  static int fpr_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 int fcr31_pos = NUM_FPU_REGS * sizeof(elf_fpreg_t); -	const int fir_pos = fcr31_pos + sizeof(u32); -	int err; -  	if (sizeof(target->thread.fpu.fpr[0]) == sizeof(elf_fpreg_t)) -		err = fpr_get_fpa(target, &pos, &count, &kbuf, &ubuf); +		fpr_get_fpa(target, &to);  	else -		err = fpr_get_msa(target, &pos, &count, &kbuf, &ubuf); -	if (err) -		return err; - -	err = user_regset_copyout(&pos, &count, &kbuf, &ubuf, -				  &target->thread.fpu.fcr31, -				  fcr31_pos, fcr31_pos + sizeof(u32)); -	if (err) -		return err; +		fpr_get_msa(target, &to); -	err = user_regset_copyout(&pos, &count, &kbuf, &ubuf, -				  &boot_cpu_data.fpu_id, -				  fir_pos, fir_pos + sizeof(u32)); - -	return err; +	membuf_write(&to, &target->thread.fpu.fcr31, sizeof(u32)); +	membuf_write(&to, &boot_cpu_data.fpu_id, sizeof(u32)); +	return 0;  }  /* @@ -576,14 +543,9 @@ static int fpr_set(struct task_struct *target,  /* Copy the FP mode setting to the supplied NT_MIPS_FP_MODE buffer.  */  static int fp_mode_get(struct task_struct *target,  		       const struct user_regset *regset, -		       unsigned int pos, unsigned int count, -		       void *kbuf, void __user *ubuf) +		       struct membuf to)  { -	int fp_mode; - -	fp_mode = mips_get_process_fp_mode(target); -	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &fp_mode, 0, -				   sizeof(fp_mode)); +	return membuf_store(&to, (int)mips_get_process_fp_mode(target));  }  /* @@ -630,13 +592,12 @@ struct msa_control_regs {  	unsigned int msacsr;  }; -static int copy_pad_fprs(struct task_struct *target, +static void copy_pad_fprs(struct task_struct *target,  			 const struct user_regset *regset, -			 unsigned int *ppos, unsigned int *pcount, -			 void **pkbuf, void __user **pubuf, +			 struct membuf *to,  			 unsigned int live_sz)  { -	int i, j, start, start_pad, err; +	int i, j;  	unsigned long long fill = ~0ull;  	unsigned int cp_sz, pad_sz; @@ -644,28 +605,16 @@ static int copy_pad_fprs(struct task_struct *target,  	pad_sz = regset->size - cp_sz;  	WARN_ON(pad_sz % sizeof(fill)); -	i = start = err = 0; -	for (; i < NUM_FPU_REGS; i++, start += regset->size) { -		err |= user_regset_copyout(ppos, pcount, pkbuf, pubuf, -					   &target->thread.fpu.fpr[i], -					   start, start + cp_sz); - -		start_pad = start + cp_sz; -		for (j = 0; j < (pad_sz / sizeof(fill)); j++) { -			err |= user_regset_copyout(ppos, pcount, pkbuf, pubuf, -						   &fill, start_pad, -						   start_pad + sizeof(fill)); -			start_pad += sizeof(fill); -		} +	for (i = 0; i < NUM_FPU_REGS; i++) { +		membuf_write(to, &target->thread.fpu.fpr[i], cp_sz); +		for (j = 0; j < (pad_sz / sizeof(fill)); j++) +			membuf_store(to, fill);  	} - -	return err;  }  static int msa_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 int wr_size = NUM_FPU_REGS * regset->size;  	const struct msa_control_regs ctrl_regs = { @@ -674,32 +623,23 @@ static int msa_get(struct task_struct *target,  		.msair = boot_cpu_data.msa_id,  		.msacsr = target->thread.fpu.msacsr,  	}; -	int err;  	if (!tsk_used_math(target)) {  		/* The task hasn't used FP or MSA, fill with 0xff */ -		err = copy_pad_fprs(target, regset, &pos, &count, -				    &kbuf, &ubuf, 0); +		copy_pad_fprs(target, regset, &to, 0);  	} else if (!test_tsk_thread_flag(target, TIF_MSA_CTX_LIVE)) {  		/* Copy scalar FP context, fill the rest with 0xff */ -		err = copy_pad_fprs(target, regset, &pos, &count, -				    &kbuf, &ubuf, 8); +		copy_pad_fprs(target, regset, &to, 8);  	} else if (sizeof(target->thread.fpu.fpr[0]) == regset->size) {  		/* Trivially copy the vector registers */ -		err = user_regset_copyout(&pos, &count, &kbuf, &ubuf, -					  &target->thread.fpu.fpr, -					  0, wr_size); +		membuf_write(&to, &target->thread.fpu.fpr, wr_size);  	} else {  		/* Copy as much context as possible, fill the rest with 0xff */ -		err = copy_pad_fprs(target, regset, &pos, &count, -				    &kbuf, &ubuf, -				    sizeof(target->thread.fpu.fpr[0])); +		copy_pad_fprs(target, regset, &to, +				sizeof(target->thread.fpu.fpr[0]));  	} -	err |= user_regset_copyout(&pos, &count, &kbuf, &ubuf, -				   &ctrl_regs, wr_size, -				   wr_size + sizeof(ctrl_regs)); -	return err; +	return membuf_write(&to, &ctrl_regs, sizeof(ctrl_regs));  }  static int msa_set(struct task_struct *target, @@ -752,34 +692,20 @@ static int msa_set(struct task_struct *target,   */  static int dsp32_get(struct task_struct *target,  		     const struct user_regset *regset, -		     unsigned int pos, unsigned int count, -		     void *kbuf, void __user *ubuf) +		     struct membuf to)  { -	unsigned int start, num_regs, i;  	u32 dspregs[NUM_DSP_REGS + 1]; +	unsigned int i; -	BUG_ON(count % sizeof(u32)); +	BUG_ON(to.left % sizeof(u32));  	if (!cpu_has_dsp)  		return -EIO; -	start = pos / sizeof(u32); -	num_regs = count / sizeof(u32); - -	if (start + num_regs > NUM_DSP_REGS + 1) -		return -EIO; - -	for (i = start; i < num_regs; i++) -		switch (i) { -		case 0 ... NUM_DSP_REGS - 1: -			dspregs[i] = target->thread.dsp.dspr[i]; -			break; -		case NUM_DSP_REGS: -			dspregs[i] = target->thread.dsp.dspcontrol; -			break; -		} -	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, dspregs, 0, -				   sizeof(dspregs)); +	for (i = 0; i < NUM_DSP_REGS; i++) +		dspregs[i] = target->thread.dsp.dspr[i]; +	dspregs[NUM_DSP_REGS] = target->thread.dsp.dspcontrol; +	return membuf_write(&to, dspregs, sizeof(dspregs));  }  /* @@ -832,34 +758,20 @@ static int dsp32_set(struct task_struct *target,   */  static int dsp64_get(struct task_struct *target,  		     const struct user_regset *regset, -		     unsigned int pos, unsigned int count, -		     void *kbuf, void __user *ubuf) +		     struct membuf to)  { -	unsigned int start, num_regs, i;  	u64 dspregs[NUM_DSP_REGS + 1]; +	unsigned int i; -	BUG_ON(count % sizeof(u64)); +	BUG_ON(to.left % sizeof(u64));  	if (!cpu_has_dsp)  		return -EIO; -	start = pos / sizeof(u64); -	num_regs = count / sizeof(u64); - -	if (start + num_regs > NUM_DSP_REGS + 1) -		return -EIO; - -	for (i = start; i < num_regs; i++) -		switch (i) { -		case 0 ... NUM_DSP_REGS - 1: -			dspregs[i] = target->thread.dsp.dspr[i]; -			break; -		case NUM_DSP_REGS: -			dspregs[i] = target->thread.dsp.dspcontrol; -			break; -		} -	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, dspregs, 0, -				   sizeof(dspregs)); +	for (i = 0; i < NUM_DSP_REGS; i++) +		dspregs[i] = target->thread.dsp.dspr[i]; +	dspregs[NUM_DSP_REGS] = target->thread.dsp.dspcontrol; +	return membuf_write(&to, dspregs, sizeof(dspregs));  }  /* @@ -1018,7 +930,7 @@ static const struct user_regset mips_regsets[] = {  		.n		= ELF_NGREG,  		.size		= sizeof(unsigned int),  		.align		= sizeof(unsigned int), -		.get		= gpr32_get, +		.regset_get		= gpr32_get,  		.set		= gpr32_set,  	},  	[REGSET_DSP] = { @@ -1026,7 +938,7 @@ static const struct user_regset mips_regsets[] = {  		.n		= NUM_DSP_REGS + 1,  		.size		= sizeof(u32),  		.align		= sizeof(u32), -		.get		= dsp32_get, +		.regset_get		= dsp32_get,  		.set		= dsp32_set,  		.active		= dsp_active,  	}, @@ -1036,7 +948,7 @@ static const struct user_regset mips_regsets[] = {  		.n		= ELF_NFPREG,  		.size		= sizeof(elf_fpreg_t),  		.align		= sizeof(elf_fpreg_t), -		.get		= fpr_get, +		.regset_get		= fpr_get,  		.set		= fpr_set,  	},  	[REGSET_FP_MODE] = { @@ -1044,7 +956,7 @@ static const struct user_regset mips_regsets[] = {  		.n		= 1,  		.size		= sizeof(int),  		.align		= sizeof(int), -		.get		= fp_mode_get, +		.regset_get		= fp_mode_get,  		.set		= fp_mode_set,  	},  #endif @@ -1054,7 +966,7 @@ static const struct user_regset mips_regsets[] = {  		.n		= NUM_FPU_REGS + 1,  		.size		= 16,  		.align		= 16, -		.get		= msa_get, +		.regset_get		= msa_get,  		.set		= msa_set,  	},  #endif @@ -1078,7 +990,7 @@ static const struct user_regset mips64_regsets[] = {  		.n		= ELF_NGREG,  		.size		= sizeof(unsigned long),  		.align		= sizeof(unsigned long), -		.get		= gpr64_get, +		.regset_get		= gpr64_get,  		.set		= gpr64_set,  	},  	[REGSET_DSP] = { @@ -1086,7 +998,7 @@ static const struct user_regset mips64_regsets[] = {  		.n		= NUM_DSP_REGS + 1,  		.size		= sizeof(u64),  		.align		= sizeof(u64), -		.get		= dsp64_get, +		.regset_get		= dsp64_get,  		.set		= dsp64_set,  		.active		= dsp_active,  	}, @@ -1096,7 +1008,7 @@ static const struct user_regset mips64_regsets[] = {  		.n		= 1,  		.size		= sizeof(int),  		.align		= sizeof(int), -		.get		= fp_mode_get, +		.regset_get		= fp_mode_get,  		.set		= fp_mode_set,  	},  	[REGSET_FPR] = { @@ -1104,7 +1016,7 @@ static const struct user_regset mips64_regsets[] = {  		.n		= ELF_NFPREG,  		.size		= sizeof(elf_fpreg_t),  		.align		= sizeof(elf_fpreg_t), -		.get		= fpr_get, +		.regset_get		= fpr_get,  		.set		= fpr_set,  	},  #endif @@ -1114,7 +1026,7 @@ static const struct user_regset mips64_regsets[] = {  		.n		= NUM_FPU_REGS + 1,  		.size		= 16,  		.align		= 16, -		.get		= msa_get, +		.regset_get		= msa_get,  		.set		= msa_set,  	},  #endif diff --git a/arch/nds32/kernel/ptrace.c b/arch/nds32/kernel/ptrace.c index eaaf7a999b20..d0eda870fbc2 100644 --- a/arch/nds32/kernel/ptrace.c +++ b/arch/nds32/kernel/ptrace.c @@ -13,11 +13,10 @@ enum nds32_regset {  static int gpr_get(struct task_struct *target,  		   const struct user_regset *regset, -		   unsigned int pos, unsigned int count, -		   void *kbuf, void __user * ubuf) +		   struct membuf to)  { -	struct user_pt_regs *uregs = &task_pt_regs(target)->user_regs; -	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0, -1); +	return membuf_write(&to, &task_pt_regs(target)->user_regs, +				sizeof(struct user_pt_regs));  }  static int gpr_set(struct task_struct *target, const struct user_regset *regset, @@ -41,7 +40,7 @@ static const struct user_regset nds32_regsets[] = {  			.n = sizeof(struct user_pt_regs) / sizeof(u32),  			.size = sizeof(elf_greg_t),  			.align = sizeof(elf_greg_t), -			.get = gpr_get, +			.regset_get = gpr_get,  			.set = gpr_set}  }; diff --git a/arch/nios2/kernel/ptrace.c b/arch/nios2/kernel/ptrace.c index de97bcb7dd44..a6ea9e1b4f61 100644 --- a/arch/nios2/kernel/ptrace.c +++ b/arch/nios2/kernel/ptrace.c @@ -21,45 +21,24 @@  static int genregs_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);  	const struct switch_stack *sw = (struct switch_stack *)regs - 1; -	int ret = 0; - -#define REG_O_ZERO_RANGE(START, END)		\ -	if (!ret)					\ -		ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, \ -			START * 4, (END * 4) + 4); - -#define REG_O_ONE(PTR, LOC)	\ -	if (!ret)			\ -		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, PTR, \ -			LOC * 4, (LOC * 4) + 4); -#define REG_O_RANGE(PTR, START, END)	\ -	if (!ret)				\ -		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, PTR, \ -			START * 4, (END * 4) + 4); - -	REG_O_ZERO_RANGE(PTR_R0, PTR_R0); -	REG_O_RANGE(®s->r1, PTR_R1, PTR_R7); -	REG_O_RANGE(®s->r8, PTR_R8, PTR_R15); -	REG_O_RANGE(sw, PTR_R16, PTR_R23); -	REG_O_ZERO_RANGE(PTR_R24, PTR_R25); /* et and bt */ -	REG_O_ONE(®s->gp, PTR_GP); -	REG_O_ONE(®s->sp, PTR_SP); -	REG_O_ONE(®s->fp, PTR_FP); -	REG_O_ONE(®s->ea, PTR_EA); -	REG_O_ZERO_RANGE(PTR_BA, PTR_BA); -	REG_O_ONE(®s->ra, PTR_RA); -	REG_O_ONE(®s->ea, PTR_PC); /* use ea for PC */ -	if (!ret) -		ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, -					 PTR_STATUS * 4, -1); - -	return ret; +	membuf_zero(&to, 4); // R0 +	membuf_write(&to, ®s->r1, 7 * 4); // R1..R7 +	membuf_write(&to, ®s->r8, 8 * 4); // R8..R15 +	membuf_write(&to, sw, 8 * 4); // R16..R23 +	membuf_zero(&to, 2 * 4); /* et and bt */ +	membuf_store(&to, regs->gp); +	membuf_store(&to, regs->sp); +	membuf_store(&to, regs->fp); +	membuf_store(&to, regs->ea); +	membuf_zero(&to, 4); // PTR_BA +	membuf_store(&to, regs->ra); +	membuf_store(&to, regs->ea); /* use ea for PC */ +	return membuf_zero(&to, (NUM_PTRACE_REG - PTR_PC) * 4);  }  /* @@ -121,7 +100,7 @@ static const struct user_regset nios2_regsets[] = {  		.n = NUM_PTRACE_REG,  		.size = sizeof(unsigned long),  		.align = sizeof(unsigned long), -		.get = genregs_get, +		.regset_get = genregs_get,  		.set = genregs_set,  	}  }; diff --git a/arch/openrisc/kernel/ptrace.c b/arch/openrisc/kernel/ptrace.c index c8f47a623754..4d60ae2a12fa 100644 --- a/arch/openrisc/kernel/ptrace.c +++ b/arch/openrisc/kernel/ptrace.c @@ -44,29 +44,15 @@   */  static int genregs_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;  	/* r0 */ -	ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, 0, 4); - -	if (!ret) -		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, -					  regs->gpr+1, 4, 4*32); -	if (!ret) -		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, -				  ®s->pc, 4*32, 4*33); -	if (!ret) -		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, -					  ®s->sr, 4*33, 4*34); -	if (!ret) -		ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, -					       4*34, -1); - -	return ret; +	membuf_zero(&to, 4); +	membuf_write(&to, regs->gpr + 1, 31 * 4); +	membuf_store(&to, regs->pc); +	return membuf_store(&to, regs->sr);  }  /* @@ -114,7 +100,7 @@ static const struct user_regset or1k_regsets[] = {  			    .n = ELF_NGREG,  			    .size = sizeof(long),  			    .align = sizeof(long), -			    .get = genregs_get, +			    .regset_get = genregs_get,  			    .set = genregs_set,  			    },  }; diff --git a/arch/parisc/kernel/ptrace.c b/arch/parisc/kernel/ptrace.c index b51418ad8655..2127974982df 100644 --- a/arch/parisc/kernel/ptrace.c +++ b/arch/parisc/kernel/ptrace.c @@ -391,31 +391,11 @@ void do_syscall_trace_exit(struct pt_regs *regs)  static int fpr_get(struct task_struct *target,  		     const struct user_regset *regset, -		     unsigned int pos, unsigned int count, -		     void *kbuf, void __user *ubuf) +		     struct membuf to)  {  	struct pt_regs *regs = task_regs(target); -	__u64 *k = kbuf; -	__u64 __user *u = ubuf; -	__u64 reg; - -	pos /= sizeof(reg); -	count /= sizeof(reg); - -	if (kbuf) -		for (; count > 0 && pos < ELF_NFPREG; --count) -			*k++ = regs->fr[pos++]; -	else -		for (; count > 0 && pos < ELF_NFPREG; --count) -			if (__put_user(regs->fr[pos++], u++)) -				return -EFAULT; -	kbuf = k; -	ubuf = u; -	pos *= sizeof(reg); -	count *= sizeof(reg); -	return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, -					ELF_NFPREG * sizeof(reg), -1); +	return membuf_write(&to, regs->fr, ELF_NFPREG * sizeof(__u64));  }  static int fpr_set(struct task_struct *target, @@ -527,30 +507,14 @@ static void set_reg(struct pt_regs *regs, int num, unsigned long val)  static int gpr_get(struct task_struct *target,  		     const struct user_regset *regset, -		     unsigned int pos, unsigned int count, -		     void *kbuf, void __user *ubuf) +		     struct membuf to)  {  	struct pt_regs *regs = task_regs(target); -	unsigned long *k = kbuf; -	unsigned long __user *u = ubuf; -	unsigned long reg; +	unsigned int pos; -	pos /= sizeof(reg); -	count /= sizeof(reg); - -	if (kbuf) -		for (; count > 0 && pos < ELF_NGREG; --count) -			*k++ = get_reg(regs, pos++); -	else -		for (; count > 0 && pos < ELF_NGREG; --count) -			if (__put_user(get_reg(regs, pos++), u++)) -				return -EFAULT; -	kbuf = k; -	ubuf = u; -	pos *= sizeof(reg); -	count *= sizeof(reg); -	return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, -					ELF_NGREG * sizeof(reg), -1); +	for (pos = 0; pos < ELF_NGREG; pos++) +		membuf_store(&to, get_reg(regs, pos)); +	return 0;  }  static int gpr_set(struct task_struct *target, @@ -588,12 +552,12 @@ static const struct user_regset native_regsets[] = {  	[REGSET_GENERAL] = {  		.core_note_type = NT_PRSTATUS, .n = ELF_NGREG,  		.size = sizeof(long), .align = sizeof(long), -		.get = gpr_get, .set = gpr_set +		.regset_get = gpr_get, .set = gpr_set  	},  	[REGSET_FP] = {  		.core_note_type = NT_PRFPREG, .n = ELF_NFPREG,  		.size = sizeof(__u64), .align = sizeof(__u64), -		.get = fpr_get, .set = fpr_set +		.regset_get = fpr_get, .set = fpr_set  	}  }; @@ -607,31 +571,15 @@ static const struct user_regset_view user_parisc_native_view = {  static int gpr32_get(struct task_struct *target,  		     const struct user_regset *regset, -		     unsigned int pos, unsigned int count, -		     void *kbuf, void __user *ubuf) +		     struct membuf to)  {  	struct pt_regs *regs = task_regs(target); -	compat_ulong_t *k = kbuf; -	compat_ulong_t __user *u = ubuf; -	compat_ulong_t reg; +	unsigned int pos; -	pos /= sizeof(reg); -	count /= sizeof(reg); +	for (pos = 0; pos < ELF_NGREG; pos++) +		membuf_store(&to, (compat_ulong_t)get_reg(regs, pos)); -	if (kbuf) -		for (; count > 0 && pos < ELF_NGREG; --count) -			*k++ = get_reg(regs, pos++); -	else -		for (; count > 0 && pos < ELF_NGREG; --count) -			if (__put_user((compat_ulong_t) get_reg(regs, pos++), u++)) -				return -EFAULT; - -	kbuf = k; -	ubuf = u; -	pos *= sizeof(reg); -	count *= sizeof(reg); -	return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, -					ELF_NGREG * sizeof(reg), -1); +	return 0;  }  static int gpr32_set(struct task_struct *target, @@ -672,12 +620,12 @@ static const struct user_regset compat_regsets[] = {  	[REGSET_GENERAL] = {  		.core_note_type = NT_PRSTATUS, .n = ELF_NGREG,  		.size = sizeof(compat_long_t), .align = sizeof(compat_long_t), -		.get = gpr32_get, .set = gpr32_set +		.regset_get = gpr32_get, .set = gpr32_set  	},  	[REGSET_FP] = {  		.core_note_type = NT_PRFPREG, .n = ELF_NFPREG,  		.size = sizeof(__u64), .align = sizeof(__u64), -		.get = fpr_get, .set = fpr_set +		.regset_get = fpr_get, .set = fpr_set  	}  }; diff --git a/arch/powerpc/kernel/ptrace/ptrace-altivec.c b/arch/powerpc/kernel/ptrace/ptrace-altivec.c index dd8b75dfbd06..0d9bc4bd4972 100644 --- a/arch/powerpc/kernel/ptrace/ptrace-altivec.c +++ b/arch/powerpc/kernel/ptrace/ptrace-altivec.c @@ -41,38 +41,25 @@ int vr_active(struct task_struct *target, const struct user_regset *regset)   * };   */  int vr_get(struct task_struct *target, const struct user_regset *regset, -	   unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) +	   struct membuf to)  { -	int ret; +	union { +		elf_vrreg_t reg; +		u32 word; +	} vrsave;  	flush_altivec_to_thread(target);  	BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) !=  		     offsetof(struct thread_vr_state, vr[32])); -	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, -				  &target->thread.vr_state, 0, -				  33 * sizeof(vector128)); -	if (!ret) { -		/* -		 * Copy out only the low-order word of vrsave. -		 */ -		int start, end; -		union { -			elf_vrreg_t reg; -			u32 word; -		} vrsave; -		memset(&vrsave, 0, sizeof(vrsave)); - -		vrsave.word = target->thread.vrsave; - -		start = 33 * sizeof(vector128); -		end = start + sizeof(vrsave); -		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &vrsave, -					  start, end); -	} - -	return ret; +	membuf_write(&to, &target->thread.vr_state, 33 * sizeof(vector128)); +	/* +	 * Copy out only the low-order word of vrsave. +	 */ +	memset(&vrsave, 0, sizeof(vrsave)); +	vrsave.word = target->thread.vrsave; +	return membuf_write(&to, &vrsave, sizeof(vrsave));  }  /* diff --git a/arch/powerpc/kernel/ptrace/ptrace-decl.h b/arch/powerpc/kernel/ptrace/ptrace-decl.h index 3c8a81999292..67447a6197eb 100644 --- a/arch/powerpc/kernel/ptrace/ptrace-decl.h +++ b/arch/powerpc/kernel/ptrace/ptrace-decl.h @@ -63,8 +63,7 @@ enum powerpc_regset {  /* ptrace-(no)vsx */ -int fpr_get(struct task_struct *target, const struct user_regset *regset, -	    unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf); +user_regset_get2_fn fpr_get;  int fpr_set(struct task_struct *target, const struct user_regset *regset,  	    unsigned int pos, unsigned int count,  	    const void *kbuf, const void __user *ubuf); @@ -72,8 +71,7 @@ int fpr_set(struct task_struct *target, const struct user_regset *regset,  /* ptrace-vsx */  int vsr_active(struct task_struct *target, const struct user_regset *regset); -int vsr_get(struct task_struct *target, const struct user_regset *regset, -	    unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf); +user_regset_get2_fn vsr_get;  int vsr_set(struct task_struct *target, const struct user_regset *regset,  	    unsigned int pos, unsigned int count,  	    const void *kbuf, const void __user *ubuf); @@ -81,8 +79,7 @@ int vsr_set(struct task_struct *target, const struct user_regset *regset,  /* ptrace-altivec */  int vr_active(struct task_struct *target, const struct user_regset *regset); -int vr_get(struct task_struct *target, const struct user_regset *regset, -	   unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf); +user_regset_get2_fn vr_get;  int vr_set(struct task_struct *target, const struct user_regset *regset,  	   unsigned int pos, unsigned int count,  	   const void *kbuf, const void __user *ubuf); @@ -90,8 +87,7 @@ int vr_set(struct task_struct *target, const struct user_regset *regset,  /* ptrace-spe */  int evr_active(struct task_struct *target, const struct user_regset *regset); -int evr_get(struct task_struct *target, const struct user_regset *regset, -	    unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf); +user_regset_get2_fn evr_get;  int evr_set(struct task_struct *target, const struct user_regset *regset,  	    unsigned int pos, unsigned int count,  	    const void *kbuf, const void __user *ubuf); @@ -100,9 +96,8 @@ int evr_set(struct task_struct *target, const struct user_regset *regset,  int gpr32_get_common(struct task_struct *target,  		     const struct user_regset *regset, -		     unsigned int pos, unsigned int count, -			    void *kbuf, void __user *ubuf, -			    unsigned long *regs); +		     struct membuf to, +		     unsigned long *regs);  int gpr32_set_common(struct task_struct *target,  		     const struct user_regset *regset,  		     unsigned int pos, unsigned int count, @@ -118,55 +113,46 @@ static inline void flush_tmregs_to_thread(struct task_struct *tsk) { }  #endif  int tm_cgpr_active(struct task_struct *target, const struct user_regset *regset); -int tm_cgpr_get(struct task_struct *target, const struct user_regset *regset, -		unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf); +user_regset_get2_fn tm_cgpr_get;  int tm_cgpr_set(struct task_struct *target, const struct user_regset *regset,  		unsigned int pos, unsigned int count,  		const void *kbuf, const void __user *ubuf);  int tm_cfpr_active(struct task_struct *target, const struct user_regset *regset); -int tm_cfpr_get(struct task_struct *target, const struct user_regset *regset, -		unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf); +user_regset_get2_fn tm_cfpr_get;  int tm_cfpr_set(struct task_struct *target, const struct user_regset *regset,  		unsigned int pos, unsigned int count,  		const void *kbuf, const void __user *ubuf);  int tm_cvmx_active(struct task_struct *target, const struct user_regset *regset); -int tm_cvmx_get(struct task_struct *target, const struct user_regset *regset, -		unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf); +user_regset_get2_fn tm_cvmx_get;  int tm_cvmx_set(struct task_struct *target, const struct user_regset *regset,  		unsigned int pos, unsigned int count,  		const void *kbuf, const void __user *ubuf);  int tm_cvsx_active(struct task_struct *target, const struct user_regset *regset); -int tm_cvsx_get(struct task_struct *target, const struct user_regset *regset, -		unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf); +user_regset_get2_fn tm_cvsx_get;  int tm_cvsx_set(struct task_struct *target, const struct user_regset *regset,  		unsigned int pos, unsigned int count,  		const void *kbuf, const void __user *ubuf);  int tm_spr_active(struct task_struct *target, const struct user_regset *regset); -int tm_spr_get(struct task_struct *target, const struct user_regset *regset, -	       unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf); +user_regset_get2_fn tm_spr_get;  int tm_spr_set(struct task_struct *target, const struct user_regset *regset,  	       unsigned int pos, unsigned int count,  	       const void *kbuf, const void __user *ubuf);  int tm_tar_active(struct task_struct *target, const struct user_regset *regset); -int tm_tar_get(struct task_struct *target, const struct user_regset *regset, -	       unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf); +user_regset_get2_fn tm_tar_get;  int tm_tar_set(struct task_struct *target, const struct user_regset *regset,  	       unsigned int pos, unsigned int count,  	       const void *kbuf, const void __user *ubuf);  int tm_ppr_active(struct task_struct *target, const struct user_regset *regset); -int tm_ppr_get(struct task_struct *target, const struct user_regset *regset, -	       unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf); +user_regset_get2_fn tm_ppr_get;  int tm_ppr_set(struct task_struct *target, const struct user_regset *regset,  	       unsigned int pos, unsigned int count,  	       const void *kbuf, const void __user *ubuf);  int tm_dscr_active(struct task_struct *target, const struct user_regset *regset); -int tm_dscr_get(struct task_struct *target, const struct user_regset *regset, -		unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf); +user_regset_get2_fn tm_dscr_get;  int tm_dscr_set(struct task_struct *target, const struct user_regset *regset,  		unsigned int pos, unsigned int count,  		const void *kbuf, const void __user *ubuf); -int tm_cgpr32_get(struct task_struct *target, const struct user_regset *regset, -		  unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf); +user_regset_get2_fn tm_cgpr32_get;  int tm_cgpr32_set(struct task_struct *target, const struct user_regset *regset,  		  unsigned int pos, unsigned int count,  		  const void *kbuf, const void __user *ubuf); diff --git a/arch/powerpc/kernel/ptrace/ptrace-novsx.c b/arch/powerpc/kernel/ptrace/ptrace-novsx.c index b2dc4e92d11a..b3b36835658a 100644 --- a/arch/powerpc/kernel/ptrace/ptrace-novsx.c +++ b/arch/powerpc/kernel/ptrace/ptrace-novsx.c @@ -19,15 +19,14 @@   * };   */  int fpr_get(struct task_struct *target, const struct user_regset *regset, -	    unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) +	    struct membuf to)  {  	BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=  		     offsetof(struct thread_fp_state, fpr[32]));  	flush_fp_to_thread(target); -	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, -				   &target->thread.fp_state, 0, -1); +	return membuf_write(&to, &target->thread.fp_state, 33 * sizeof(u64));  }  /* diff --git a/arch/powerpc/kernel/ptrace/ptrace-spe.c b/arch/powerpc/kernel/ptrace/ptrace-spe.c index 68b86b4a4be4..47034d069045 100644 --- a/arch/powerpc/kernel/ptrace/ptrace-spe.c +++ b/arch/powerpc/kernel/ptrace/ptrace-spe.c @@ -23,25 +23,17 @@ int evr_active(struct task_struct *target, const struct user_regset *regset)  }  int evr_get(struct task_struct *target, const struct user_regset *regset, -	    unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) +	    struct membuf to)  { -	int ret; -  	flush_spe_to_thread(target); -	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, -				  &target->thread.evr, -				  0, sizeof(target->thread.evr)); +	membuf_write(&to, &target->thread.evr, sizeof(target->thread.evr));  	BUILD_BUG_ON(offsetof(struct thread_struct, acc) + sizeof(u64) !=  		     offsetof(struct thread_struct, spefscr)); -	if (!ret) -		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, -					  &target->thread.acc, -					  sizeof(target->thread.evr), -1); - -	return ret; +	return membuf_write(&to, &target->thread.acc, +				sizeof(u64) + sizeof(u32));  }  int evr_set(struct task_struct *target, const struct user_regset *regset, diff --git a/arch/powerpc/kernel/ptrace/ptrace-tm.c b/arch/powerpc/kernel/ptrace/ptrace-tm.c index 32d62c606681..54f2d076206f 100644 --- a/arch/powerpc/kernel/ptrace/ptrace-tm.c +++ b/arch/powerpc/kernel/ptrace/ptrace-tm.c @@ -70,10 +70,7 @@ int tm_cgpr_active(struct task_struct *target, const struct user_regset *regset)   * tm_cgpr_get - get CGPR registers   * @target:	The target task.   * @regset:	The user regset structure. - * @pos:	The buffer position. - * @count:	Number of bytes to copy. - * @kbuf:	Kernel buffer to copy from. - * @ubuf:	User buffer to copy into. + * @to:		Destination of copy.   *   * This function gets transaction checkpointed GPR registers.   * @@ -87,10 +84,8 @@ int tm_cgpr_active(struct task_struct *target, const struct user_regset *regset)   * };   */  int tm_cgpr_get(struct task_struct *target, const struct user_regset *regset, -		unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) +		struct membuf to)  { -	int ret; -  	if (!cpu_has_feature(CPU_FTR_TM))  		return -ENODEV; @@ -101,31 +96,18 @@ int tm_cgpr_get(struct task_struct *target, const struct user_regset *regset,  	flush_fp_to_thread(target);  	flush_altivec_to_thread(target); -	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, -				  &target->thread.ckpt_regs, -				  0, offsetof(struct pt_regs, msr)); -	if (!ret) { -		unsigned long msr = get_user_ckpt_msr(target); - -		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &msr, -					  offsetof(struct pt_regs, msr), -					  offsetof(struct pt_regs, msr) + -					  sizeof(msr)); -	} +	membuf_write(&to, &target->thread.ckpt_regs, +			offsetof(struct pt_regs, msr)); +	membuf_store(&to, get_user_ckpt_msr(target));  	BUILD_BUG_ON(offsetof(struct pt_regs, orig_gpr3) !=  		     offsetof(struct pt_regs, msr) + sizeof(long)); -	if (!ret) -		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, -					  &target->thread.ckpt_regs.orig_gpr3, -					  offsetof(struct pt_regs, orig_gpr3), -					  sizeof(struct user_pt_regs)); -	if (!ret) -		ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, -					       sizeof(struct user_pt_regs), -1); - -	return ret; +	membuf_write(&to, &target->thread.ckpt_regs.orig_gpr3, +			sizeof(struct user_pt_regs) - +			offsetof(struct pt_regs, orig_gpr3)); +	return membuf_zero(&to, ELF_NGREG * sizeof(unsigned long) - +			sizeof(struct user_pt_regs));  }  /* @@ -229,10 +211,7 @@ int tm_cfpr_active(struct task_struct *target, const struct user_regset *regset)   * tm_cfpr_get - get CFPR registers   * @target:	The target task.   * @regset:	The user regset structure. - * @pos:	The buffer position. - * @count:	Number of bytes to copy. - * @kbuf:	Kernel buffer to copy from. - * @ubuf:	User buffer to copy into. + * @to:		Destination of copy.   *   * This function gets in transaction checkpointed FPR registers.   * @@ -247,7 +226,7 @@ int tm_cfpr_active(struct task_struct *target, const struct user_regset *regset)   *};   */  int tm_cfpr_get(struct task_struct *target, const struct user_regset *regset, -		unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) +		struct membuf to)  {  	u64 buf[33];  	int i; @@ -266,7 +245,7 @@ int tm_cfpr_get(struct task_struct *target, const struct user_regset *regset,  	for (i = 0; i < 32 ; i++)  		buf[i] = target->thread.TS_CKFPR(i);  	buf[32] = target->thread.ckfp_state.fpscr; -	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, buf, 0, -1); +	return membuf_write(&to, buf, sizeof(buf));  }  /** @@ -344,10 +323,7 @@ int tm_cvmx_active(struct task_struct *target, const struct user_regset *regset)   * tm_cvmx_get - get CMVX registers   * @target:	The target task.   * @regset:	The user regset structure. - * @pos:	The buffer position. - * @count:	Number of bytes to copy. - * @kbuf:	Kernel buffer to copy from. - * @ubuf:	User buffer to copy into. + * @to:		Destination of copy.   *   * This function gets in transaction checkpointed VMX registers.   * @@ -363,10 +339,12 @@ int tm_cvmx_active(struct task_struct *target, const struct user_regset *regset)   *};   */  int tm_cvmx_get(struct task_struct *target, const struct user_regset *regset, -		unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) +		struct membuf to)  { -	int ret; - +	union { +		elf_vrreg_t reg; +		u32 word; +	} vrsave;  	BUILD_BUG_ON(TVSO(vscr) != TVSO(vr[32]));  	if (!cpu_has_feature(CPU_FTR_TM)) @@ -380,23 +358,13 @@ int tm_cvmx_get(struct task_struct *target, const struct user_regset *regset,  	flush_fp_to_thread(target);  	flush_altivec_to_thread(target); -	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &target->thread.ckvr_state, -				  0, 33 * sizeof(vector128)); -	if (!ret) { -		/* -		 * Copy out only the low-order word of vrsave. -		 */ -		union { -			elf_vrreg_t reg; -			u32 word; -		} vrsave; -		memset(&vrsave, 0, sizeof(vrsave)); -		vrsave.word = target->thread.ckvrsave; -		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &vrsave, -					  33 * sizeof(vector128), -1); -	} - -	return ret; +	membuf_write(&to, &target->thread.ckvr_state, 33 * sizeof(vector128)); +	/* +	 * Copy out only the low-order word of vrsave. +	 */ +	memset(&vrsave, 0, sizeof(vrsave)); +	vrsave.word = target->thread.ckvrsave; +	return membuf_write(&to, &vrsave, sizeof(vrsave));  }  /** @@ -484,10 +452,7 @@ int tm_cvsx_active(struct task_struct *target, const struct user_regset *regset)   * tm_cvsx_get - get CVSX registers   * @target:	The target task.   * @regset:	The user regset structure. - * @pos:	The buffer position. - * @count:	Number of bytes to copy. - * @kbuf:	Kernel buffer to copy from. - * @ubuf:	User buffer to copy into. + * @to:		Destination of copy.   *   * This function gets in transaction checkpointed VSX registers.   * @@ -501,10 +466,10 @@ int tm_cvsx_active(struct task_struct *target, const struct user_regset *regset)   *};   */  int tm_cvsx_get(struct task_struct *target, const struct user_regset *regset, -		unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) +		struct membuf to)  {  	u64 buf[32]; -	int ret, i; +	int i;  	if (!cpu_has_feature(CPU_FTR_TM))  		return -ENODEV; @@ -520,10 +485,7 @@ int tm_cvsx_get(struct task_struct *target, const struct user_regset *regset,  	for (i = 0; i < 32 ; i++)  		buf[i] = target->thread.ckfp_state.fpr[i][TS_VSRLOWOFFSET]; -	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, -				  buf, 0, 32 * sizeof(double)); - -	return ret; +	return membuf_write(&to, buf, 32 * sizeof(double));  }  /** @@ -597,10 +559,7 @@ int tm_spr_active(struct task_struct *target, const struct user_regset *regset)   * tm_spr_get - get the TM related SPR registers   * @target:	The target task.   * @regset:	The user regset structure. - * @pos:	The buffer position. - * @count:	Number of bytes to copy. - * @kbuf:	Kernel buffer to copy from. - * @ubuf:	User buffer to copy into. + * @to:		Destination of copy.   *   * This function gets transactional memory related SPR registers.   * The userspace interface buffer layout is as follows. @@ -612,10 +571,8 @@ int tm_spr_active(struct task_struct *target, const struct user_regset *regset)   * };   */  int tm_spr_get(struct task_struct *target, const struct user_regset *regset, -	       unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) +	       struct membuf to)  { -	int ret; -  	/* Build tests */  	BUILD_BUG_ON(TSO(tm_tfhar) + sizeof(u64) != TSO(tm_texasr));  	BUILD_BUG_ON(TSO(tm_texasr) + sizeof(u64) != TSO(tm_tfiar)); @@ -630,21 +587,11 @@ int tm_spr_get(struct task_struct *target, const struct user_regset *regset,  	flush_altivec_to_thread(target);  	/* TFHAR register */ -	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, -				  &target->thread.tm_tfhar, 0, sizeof(u64)); - +	membuf_write(&to, &target->thread.tm_tfhar, sizeof(u64));  	/* TEXASR register */ -	if (!ret) -		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, -					  &target->thread.tm_texasr, sizeof(u64), -					  2 * sizeof(u64)); - +	membuf_write(&to, &target->thread.tm_texasr, sizeof(u64));  	/* TFIAR register */ -	if (!ret) -		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, -					  &target->thread.tm_tfiar, -					  2 * sizeof(u64), 3 * sizeof(u64)); -	return ret; +	return membuf_write(&to, &target->thread.tm_tfiar, sizeof(u64));  }  /** @@ -714,19 +661,15 @@ int tm_tar_active(struct task_struct *target, const struct user_regset *regset)  }  int tm_tar_get(struct task_struct *target, const struct user_regset *regset, -	       unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) +	       struct membuf to)  { -	int ret; -  	if (!cpu_has_feature(CPU_FTR_TM))  		return -ENODEV;  	if (!MSR_TM_ACTIVE(target->thread.regs->msr))  		return -ENODATA; -	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, -				  &target->thread.tm_tar, 0, sizeof(u64)); -	return ret; +	return membuf_write(&to, &target->thread.tm_tar, sizeof(u64));  }  int tm_tar_set(struct task_struct *target, const struct user_regset *regset, @@ -759,19 +702,15 @@ int tm_ppr_active(struct task_struct *target, const struct user_regset *regset)  int tm_ppr_get(struct task_struct *target, const struct user_regset *regset, -	       unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) +	       struct membuf to)  { -	int ret; -  	if (!cpu_has_feature(CPU_FTR_TM))  		return -ENODEV;  	if (!MSR_TM_ACTIVE(target->thread.regs->msr))  		return -ENODATA; -	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, -				  &target->thread.tm_ppr, 0, sizeof(u64)); -	return ret; +	return membuf_write(&to, &target->thread.tm_ppr, sizeof(u64));  }  int tm_ppr_set(struct task_struct *target, const struct user_regset *regset, @@ -803,19 +742,15 @@ int tm_dscr_active(struct task_struct *target, const struct user_regset *regset)  }  int tm_dscr_get(struct task_struct *target, const struct user_regset *regset, -		unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) +		struct membuf to)  { -	int ret; -  	if (!cpu_has_feature(CPU_FTR_TM))  		return -ENODEV;  	if (!MSR_TM_ACTIVE(target->thread.regs->msr))  		return -ENODATA; -	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, -				  &target->thread.tm_dscr, 0, sizeof(u64)); -	return ret; +	return membuf_write(&to, &target->thread.tm_dscr, sizeof(u64));  }  int tm_dscr_set(struct task_struct *target, const struct user_regset *regset, @@ -836,10 +771,11 @@ int tm_dscr_set(struct task_struct *target, const struct user_regset *regset,  }  int tm_cgpr32_get(struct task_struct *target, const struct user_regset *regset, -		  unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) +		  struct membuf to)  { -	return gpr32_get_common(target, regset, pos, count, kbuf, ubuf, +	gpr32_get_common(target, regset, to,  				&target->thread.ckpt_regs.gpr[0]); +	return membuf_zero(&to, ELF_NGREG * sizeof(u32));  }  int tm_cgpr32_set(struct task_struct *target, const struct user_regset *regset, diff --git a/arch/powerpc/kernel/ptrace/ptrace-view.c b/arch/powerpc/kernel/ptrace/ptrace-view.c index caeb5822a8f4..13208a9a02ca 100644 --- a/arch/powerpc/kernel/ptrace/ptrace-view.c +++ b/arch/powerpc/kernel/ptrace/ptrace-view.c @@ -215,9 +215,9 @@ int ptrace_put_reg(struct task_struct *task, int regno, unsigned long data)  }  static int gpr_get(struct task_struct *target, const struct user_regset *regset, -		   unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) +		   struct membuf to)  { -	int i, ret; +	int i;  	if (target->thread.regs == NULL)  		return -EIO; @@ -228,30 +228,17 @@ static int gpr_get(struct task_struct *target, const struct user_regset *regset,  			target->thread.regs->gpr[i] = NV_REG_POISON;  	} -	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, -				  target->thread.regs, -				  0, offsetof(struct pt_regs, msr)); -	if (!ret) { -		unsigned long msr = get_user_msr(target); -		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &msr, -					  offsetof(struct pt_regs, msr), -					  offsetof(struct pt_regs, msr) + -					  sizeof(msr)); -	} +	membuf_write(&to, target->thread.regs, offsetof(struct pt_regs, msr)); +	membuf_store(&to, get_user_msr(target));  	BUILD_BUG_ON(offsetof(struct pt_regs, orig_gpr3) !=  		     offsetof(struct pt_regs, msr) + sizeof(long)); -	if (!ret) -		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, -					  &target->thread.regs->orig_gpr3, -					  offsetof(struct pt_regs, orig_gpr3), -					  sizeof(struct user_pt_regs)); -	if (!ret) -		ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, -					       sizeof(struct user_pt_regs), -1); - -	return ret; +	membuf_write(&to, &target->thread.regs->orig_gpr3, +			sizeof(struct user_pt_regs) - +			offsetof(struct pt_regs, orig_gpr3)); +	return membuf_zero(&to, ELF_NGREG * sizeof(unsigned long) - +				 sizeof(struct user_pt_regs));  }  static int gpr_set(struct task_struct *target, const struct user_regset *regset, @@ -309,10 +296,9 @@ static int gpr_set(struct task_struct *target, const struct user_regset *regset,  #ifdef CONFIG_PPC64  static int ppr_get(struct task_struct *target, const struct user_regset *regset, -		   unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) +		   struct membuf to)  { -	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, -				   &target->thread.regs->ppr, 0, sizeof(u64)); +	return membuf_write(&to, &target->thread.regs->ppr, sizeof(u64));  }  static int ppr_set(struct task_struct *target, const struct user_regset *regset, @@ -324,10 +310,9 @@ static int ppr_set(struct task_struct *target, const struct user_regset *regset,  }  static int dscr_get(struct task_struct *target, const struct user_regset *regset, -		    unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) +		    struct membuf to)  { -	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, -				   &target->thread.dscr, 0, sizeof(u64)); +	return membuf_write(&to, &target->thread.dscr, sizeof(u64));  }  static int dscr_set(struct task_struct *target, const struct user_regset *regset,  		    unsigned int pos, unsigned int count, const void *kbuf, @@ -339,10 +324,9 @@ static int dscr_set(struct task_struct *target, const struct user_regset *regset  #endif  #ifdef CONFIG_PPC_BOOK3S_64  static int tar_get(struct task_struct *target, const struct user_regset *regset, -		   unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) +		   struct membuf to)  { -	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, -				   &target->thread.tar, 0, sizeof(u64)); +	return membuf_write(&to, &target->thread.tar, sizeof(u64));  }  static int tar_set(struct task_struct *target, const struct user_regset *regset,  		   unsigned int pos, unsigned int count, const void *kbuf, @@ -364,7 +348,7 @@ static int ebb_active(struct task_struct *target, const struct user_regset *regs  }  static int ebb_get(struct task_struct *target, const struct user_regset *regset, -		   unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) +		   struct membuf to)  {  	/* Build tests */  	BUILD_BUG_ON(TSO(ebbrr) + sizeof(unsigned long) != TSO(ebbhr)); @@ -376,8 +360,7 @@ static int ebb_get(struct task_struct *target, const struct user_regset *regset,  	if (!target->thread.used_ebb)  		return -ENODATA; -	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &target->thread.ebbrr, -				   0, 3 * sizeof(unsigned long)); +	return membuf_write(&to, &target->thread.ebbrr, 3 * sizeof(unsigned long));  }  static int ebb_set(struct task_struct *target, const struct user_regset *regset, @@ -420,7 +403,7 @@ static int pmu_active(struct task_struct *target, const struct user_regset *regs  }  static int pmu_get(struct task_struct *target, const struct user_regset *regset, -		   unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) +		   struct membuf to)  {  	/* Build tests */  	BUILD_BUG_ON(TSO(siar) + sizeof(unsigned long) != TSO(sdar)); @@ -431,8 +414,7 @@ static int pmu_get(struct task_struct *target, const struct user_regset *regset,  	if (!cpu_has_feature(CPU_FTR_ARCH_207S))  		return -ENODEV; -	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &target->thread.siar, -				   0, 5 * sizeof(unsigned long)); +	return membuf_write(&to, &target->thread.siar, 5 * sizeof(unsigned long));  }  static int pmu_set(struct task_struct *target, const struct user_regset *regset, @@ -486,7 +468,7 @@ static int pkey_active(struct task_struct *target, const struct user_regset *reg  }  static int pkey_get(struct task_struct *target, const struct user_regset *regset, -		    unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) +		    struct membuf to)  {  	BUILD_BUG_ON(TSO(amr) + sizeof(unsigned long) != TSO(iamr));  	BUILD_BUG_ON(TSO(iamr) + sizeof(unsigned long) != TSO(uamor)); @@ -494,8 +476,7 @@ static int pkey_get(struct task_struct *target, const struct user_regset *regset  	if (!arch_pkeys_enabled())  		return -ENODEV; -	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &target->thread.amr, -				   0, ELF_NPKEY * sizeof(unsigned long)); +	return membuf_write(&to, &target->thread.amr, ELF_NPKEY * sizeof(unsigned long));  }  static int pkey_set(struct task_struct *target, const struct user_regset *regset, @@ -529,110 +510,110 @@ static const struct user_regset native_regsets[] = {  	[REGSET_GPR] = {  		.core_note_type = NT_PRSTATUS, .n = ELF_NGREG,  		.size = sizeof(long), .align = sizeof(long), -		.get = gpr_get, .set = gpr_set +		.regset_get = gpr_get, .set = gpr_set  	},  	[REGSET_FPR] = {  		.core_note_type = NT_PRFPREG, .n = ELF_NFPREG,  		.size = sizeof(double), .align = sizeof(double), -		.get = fpr_get, .set = fpr_set +		.regset_get = fpr_get, .set = fpr_set  	},  #ifdef CONFIG_ALTIVEC  	[REGSET_VMX] = {  		.core_note_type = NT_PPC_VMX, .n = 34,  		.size = sizeof(vector128), .align = sizeof(vector128), -		.active = vr_active, .get = vr_get, .set = vr_set +		.active = vr_active, .regset_get = vr_get, .set = vr_set  	},  #endif  #ifdef CONFIG_VSX  	[REGSET_VSX] = {  		.core_note_type = NT_PPC_VSX, .n = 32,  		.size = sizeof(double), .align = sizeof(double), -		.active = vsr_active, .get = vsr_get, .set = vsr_set +		.active = vsr_active, .regset_get = vsr_get, .set = vsr_set  	},  #endif  #ifdef CONFIG_SPE  	[REGSET_SPE] = {  		.core_note_type = NT_PPC_SPE, .n = 35,  		.size = sizeof(u32), .align = sizeof(u32), -		.active = evr_active, .get = evr_get, .set = evr_set +		.active = evr_active, .regset_get = evr_get, .set = evr_set  	},  #endif  #ifdef CONFIG_PPC_TRANSACTIONAL_MEM  	[REGSET_TM_CGPR] = {  		.core_note_type = NT_PPC_TM_CGPR, .n = ELF_NGREG,  		.size = sizeof(long), .align = sizeof(long), -		.active = tm_cgpr_active, .get = tm_cgpr_get, .set = tm_cgpr_set +		.active = tm_cgpr_active, .regset_get = tm_cgpr_get, .set = tm_cgpr_set  	},  	[REGSET_TM_CFPR] = {  		.core_note_type = NT_PPC_TM_CFPR, .n = ELF_NFPREG,  		.size = sizeof(double), .align = sizeof(double), -		.active = tm_cfpr_active, .get = tm_cfpr_get, .set = tm_cfpr_set +		.active = tm_cfpr_active, .regset_get = tm_cfpr_get, .set = tm_cfpr_set  	},  	[REGSET_TM_CVMX] = {  		.core_note_type = NT_PPC_TM_CVMX, .n = ELF_NVMX,  		.size = sizeof(vector128), .align = sizeof(vector128), -		.active = tm_cvmx_active, .get = tm_cvmx_get, .set = tm_cvmx_set +		.active = tm_cvmx_active, .regset_get = tm_cvmx_get, .set = tm_cvmx_set  	},  	[REGSET_TM_CVSX] = {  		.core_note_type = NT_PPC_TM_CVSX, .n = ELF_NVSX,  		.size = sizeof(double), .align = sizeof(double), -		.active = tm_cvsx_active, .get = tm_cvsx_get, .set = tm_cvsx_set +		.active = tm_cvsx_active, .regset_get = tm_cvsx_get, .set = tm_cvsx_set  	},  	[REGSET_TM_SPR] = {  		.core_note_type = NT_PPC_TM_SPR, .n = ELF_NTMSPRREG,  		.size = sizeof(u64), .align = sizeof(u64), -		.active = tm_spr_active, .get = tm_spr_get, .set = tm_spr_set +		.active = tm_spr_active, .regset_get = tm_spr_get, .set = tm_spr_set  	},  	[REGSET_TM_CTAR] = {  		.core_note_type = NT_PPC_TM_CTAR, .n = 1,  		.size = sizeof(u64), .align = sizeof(u64), -		.active = tm_tar_active, .get = tm_tar_get, .set = tm_tar_set +		.active = tm_tar_active, .regset_get = tm_tar_get, .set = tm_tar_set  	},  	[REGSET_TM_CPPR] = {  		.core_note_type = NT_PPC_TM_CPPR, .n = 1,  		.size = sizeof(u64), .align = sizeof(u64), -		.active = tm_ppr_active, .get = tm_ppr_get, .set = tm_ppr_set +		.active = tm_ppr_active, .regset_get = tm_ppr_get, .set = tm_ppr_set  	},  	[REGSET_TM_CDSCR] = {  		.core_note_type = NT_PPC_TM_CDSCR, .n = 1,  		.size = sizeof(u64), .align = sizeof(u64), -		.active = tm_dscr_active, .get = tm_dscr_get, .set = tm_dscr_set +		.active = tm_dscr_active, .regset_get = tm_dscr_get, .set = tm_dscr_set  	},  #endif  #ifdef CONFIG_PPC64  	[REGSET_PPR] = {  		.core_note_type = NT_PPC_PPR, .n = 1,  		.size = sizeof(u64), .align = sizeof(u64), -		.get = ppr_get, .set = ppr_set +		.regset_get = ppr_get, .set = ppr_set  	},  	[REGSET_DSCR] = {  		.core_note_type = NT_PPC_DSCR, .n = 1,  		.size = sizeof(u64), .align = sizeof(u64), -		.get = dscr_get, .set = dscr_set +		.regset_get = dscr_get, .set = dscr_set  	},  #endif  #ifdef CONFIG_PPC_BOOK3S_64  	[REGSET_TAR] = {  		.core_note_type = NT_PPC_TAR, .n = 1,  		.size = sizeof(u64), .align = sizeof(u64), -		.get = tar_get, .set = tar_set +		.regset_get = tar_get, .set = tar_set  	},  	[REGSET_EBB] = {  		.core_note_type = NT_PPC_EBB, .n = ELF_NEBB,  		.size = sizeof(u64), .align = sizeof(u64), -		.active = ebb_active, .get = ebb_get, .set = ebb_set +		.active = ebb_active, .regset_get = ebb_get, .set = ebb_set  	},  	[REGSET_PMR] = {  		.core_note_type = NT_PPC_PMU, .n = ELF_NPMU,  		.size = sizeof(u64), .align = sizeof(u64), -		.active = pmu_active, .get = pmu_get, .set = pmu_set +		.active = pmu_active, .regset_get = pmu_get, .set = pmu_set  	},  #endif  #ifdef CONFIG_PPC_MEM_KEYS  	[REGSET_PKEY] = {  		.core_note_type = NT_PPC_PKEY, .n = ELF_NPKEY,  		.size = sizeof(u64), .align = sizeof(u64), -		.active = pkey_active, .get = pkey_get, .set = pkey_set +		.active = pkey_active, .regset_get = pkey_get, .set = pkey_set  	},  #endif  }; @@ -646,49 +627,16 @@ const struct user_regset_view user_ppc_native_view = {  int gpr32_get_common(struct task_struct *target,  		     const struct user_regset *regset, -		     unsigned int pos, unsigned int count, -			    void *kbuf, void __user *ubuf, -			    unsigned long *regs) +		     struct membuf to, unsigned long *regs)  { -	compat_ulong_t *k = kbuf; -	compat_ulong_t __user *u = ubuf; -	compat_ulong_t reg; - -	pos /= sizeof(reg); -	count /= sizeof(reg); - -	if (kbuf) -		for (; count > 0 && pos < PT_MSR; --count) -			*k++ = regs[pos++]; -	else -		for (; count > 0 && pos < PT_MSR; --count) -			if (__put_user((compat_ulong_t)regs[pos++], u++)) -				return -EFAULT; - -	if (count > 0 && pos == PT_MSR) { -		reg = get_user_msr(target); -		if (kbuf) -			*k++ = reg; -		else if (__put_user(reg, u++)) -			return -EFAULT; -		++pos; -		--count; -	} - -	if (kbuf) -		for (; count > 0 && pos < PT_REGS_COUNT; --count) -			*k++ = regs[pos++]; -	else -		for (; count > 0 && pos < PT_REGS_COUNT; --count) -			if (__put_user((compat_ulong_t)regs[pos++], u++)) -				return -EFAULT; +	int i; -	kbuf = k; -	ubuf = u; -	pos *= sizeof(reg); -	count *= sizeof(reg); -	return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, -					PT_REGS_COUNT * sizeof(reg), -1); +	for (i = 0; i < PT_MSR; i++) +		membuf_store(&to, (u32)regs[i]); +	membuf_store(&to, (u32)get_user_msr(target)); +	for (i++ ; i < PT_REGS_COUNT; i++) +		membuf_store(&to, (u32)regs[i]); +	return membuf_zero(&to, (ELF_NGREG - PT_REGS_COUNT) * sizeof(u32));  }  int gpr32_set_common(struct task_struct *target, @@ -761,8 +709,7 @@ int gpr32_set_common(struct task_struct *target,  static int gpr32_get(struct task_struct *target,  		     const struct user_regset *regset, -		     unsigned int pos, unsigned int count, -		     void *kbuf, void __user *ubuf) +		     struct membuf to)  {  	int i; @@ -777,7 +724,7 @@ static int gpr32_get(struct task_struct *target,  		for (i = 14; i < 32; i++)  			target->thread.regs->gpr[i] = NV_REG_POISON;  	} -	return gpr32_get_common(target, regset, pos, count, kbuf, ubuf, +	return gpr32_get_common(target, regset, to,  			&target->thread.regs->gpr[0]);  } @@ -801,25 +748,25 @@ static const struct user_regset compat_regsets[] = {  	[REGSET_GPR] = {  		.core_note_type = NT_PRSTATUS, .n = ELF_NGREG,  		.size = sizeof(compat_long_t), .align = sizeof(compat_long_t), -		.get = gpr32_get, .set = gpr32_set +		.regset_get = gpr32_get, .set = gpr32_set  	},  	[REGSET_FPR] = {  		.core_note_type = NT_PRFPREG, .n = ELF_NFPREG,  		.size = sizeof(double), .align = sizeof(double), -		.get = fpr_get, .set = fpr_set +		.regset_get = fpr_get, .set = fpr_set  	},  #ifdef CONFIG_ALTIVEC  	[REGSET_VMX] = {  		.core_note_type = NT_PPC_VMX, .n = 34,  		.size = sizeof(vector128), .align = sizeof(vector128), -		.active = vr_active, .get = vr_get, .set = vr_set +		.active = vr_active, .regset_get = vr_get, .set = vr_set  	},  #endif  #ifdef CONFIG_SPE  	[REGSET_SPE] = {  		.core_note_type = NT_PPC_SPE, .n = 35,  		.size = sizeof(u32), .align = sizeof(u32), -		.active = evr_active, .get = evr_get, .set = evr_set +		.active = evr_active, .regset_get = evr_get, .set = evr_set  	},  #endif  #ifdef CONFIG_PPC_TRANSACTIONAL_MEM @@ -827,66 +774,66 @@ static const struct user_regset compat_regsets[] = {  		.core_note_type = NT_PPC_TM_CGPR, .n = ELF_NGREG,  		.size = sizeof(long), .align = sizeof(long),  		.active = tm_cgpr_active, -		.get = tm_cgpr32_get, .set = tm_cgpr32_set +		.regset_get = tm_cgpr32_get, .set = tm_cgpr32_set  	},  	[REGSET_TM_CFPR] = {  		.core_note_type = NT_PPC_TM_CFPR, .n = ELF_NFPREG,  		.size = sizeof(double), .align = sizeof(double), -		.active = tm_cfpr_active, .get = tm_cfpr_get, .set = tm_cfpr_set +		.active = tm_cfpr_active, .regset_get = tm_cfpr_get, .set = tm_cfpr_set  	},  	[REGSET_TM_CVMX] = {  		.core_note_type = NT_PPC_TM_CVMX, .n = ELF_NVMX,  		.size = sizeof(vector128), .align = sizeof(vector128), -		.active = tm_cvmx_active, .get = tm_cvmx_get, .set = tm_cvmx_set +		.active = tm_cvmx_active, .regset_get = tm_cvmx_get, .set = tm_cvmx_set  	},  	[REGSET_TM_CVSX] = {  		.core_note_type = NT_PPC_TM_CVSX, .n = ELF_NVSX,  		.size = sizeof(double), .align = sizeof(double), -		.active = tm_cvsx_active, .get = tm_cvsx_get, .set = tm_cvsx_set +		.active = tm_cvsx_active, .regset_get = tm_cvsx_get, .set = tm_cvsx_set  	},  	[REGSET_TM_SPR] = {  		.core_note_type = NT_PPC_TM_SPR, .n = ELF_NTMSPRREG,  		.size = sizeof(u64), .align = sizeof(u64), -		.active = tm_spr_active, .get = tm_spr_get, .set = tm_spr_set +		.active = tm_spr_active, .regset_get = tm_spr_get, .set = tm_spr_set  	},  	[REGSET_TM_CTAR] = {  		.core_note_type = NT_PPC_TM_CTAR, .n = 1,  		.size = sizeof(u64), .align = sizeof(u64), -		.active = tm_tar_active, .get = tm_tar_get, .set = tm_tar_set +		.active = tm_tar_active, .regset_get = tm_tar_get, .set = tm_tar_set  	},  	[REGSET_TM_CPPR] = {  		.core_note_type = NT_PPC_TM_CPPR, .n = 1,  		.size = sizeof(u64), .align = sizeof(u64), -		.active = tm_ppr_active, .get = tm_ppr_get, .set = tm_ppr_set +		.active = tm_ppr_active, .regset_get = tm_ppr_get, .set = tm_ppr_set  	},  	[REGSET_TM_CDSCR] = {  		.core_note_type = NT_PPC_TM_CDSCR, .n = 1,  		.size = sizeof(u64), .align = sizeof(u64), -		.active = tm_dscr_active, .get = tm_dscr_get, .set = tm_dscr_set +		.active = tm_dscr_active, .regset_get = tm_dscr_get, .set = tm_dscr_set  	},  #endif  #ifdef CONFIG_PPC64  	[REGSET_PPR] = {  		.core_note_type = NT_PPC_PPR, .n = 1,  		.size = sizeof(u64), .align = sizeof(u64), -		.get = ppr_get, .set = ppr_set +		.regset_get = ppr_get, .set = ppr_set  	},  	[REGSET_DSCR] = {  		.core_note_type = NT_PPC_DSCR, .n = 1,  		.size = sizeof(u64), .align = sizeof(u64), -		.get = dscr_get, .set = dscr_set +		.regset_get = dscr_get, .set = dscr_set  	},  #endif  #ifdef CONFIG_PPC_BOOK3S_64  	[REGSET_TAR] = {  		.core_note_type = NT_PPC_TAR, .n = 1,  		.size = sizeof(u64), .align = sizeof(u64), -		.get = tar_get, .set = tar_set +		.regset_get = tar_get, .set = tar_set  	},  	[REGSET_EBB] = {  		.core_note_type = NT_PPC_EBB, .n = ELF_NEBB,  		.size = sizeof(u64), .align = sizeof(u64), -		.active = ebb_active, .get = ebb_get, .set = ebb_set +		.active = ebb_active, .regset_get = ebb_get, .set = ebb_set  	},  #endif  }; diff --git a/arch/powerpc/kernel/ptrace/ptrace-vsx.c b/arch/powerpc/kernel/ptrace/ptrace-vsx.c index d53466d49cc0..1da4303128ef 100644 --- a/arch/powerpc/kernel/ptrace/ptrace-vsx.c +++ b/arch/powerpc/kernel/ptrace/ptrace-vsx.c @@ -19,7 +19,7 @@   * };   */  int fpr_get(struct task_struct *target, const struct user_regset *regset, -	    unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) +	    struct membuf to)  {  	u64 buf[33];  	int i; @@ -30,7 +30,7 @@ int fpr_get(struct task_struct *target, const struct user_regset *regset,  	for (i = 0; i < 32 ; i++)  		buf[i] = target->thread.TS_FPR(i);  	buf[32] = target->thread.fp_state.fpscr; -	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, buf, 0, -1); +	return membuf_write(&to, buf, 33 * sizeof(u64));  }  /* @@ -95,10 +95,10 @@ int vsr_active(struct task_struct *target, const struct user_regset *regset)   * };   */  int vsr_get(struct task_struct *target, const struct user_regset *regset, -	    unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) +	    struct membuf to)  {  	u64 buf[32]; -	int ret, i; +	int i;  	flush_tmregs_to_thread(target);  	flush_fp_to_thread(target); @@ -108,10 +108,7 @@ int vsr_get(struct task_struct *target, const struct user_regset *regset,  	for (i = 0; i < 32 ; i++)  		buf[i] = target->thread.fp_state.fpr[i][TS_VSRLOWOFFSET]; -	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, -				  buf, 0, 32 * sizeof(double)); - -	return ret; +	return membuf_write(&to, buf, 32 * sizeof(double));  }  /* diff --git a/arch/riscv/kernel/ptrace.c b/arch/riscv/kernel/ptrace.c index 444dc7b0fd78..2d6395f5ad54 100644 --- a/arch/riscv/kernel/ptrace.c +++ b/arch/riscv/kernel/ptrace.c @@ -30,13 +30,10 @@ enum riscv_regset {  static int riscv_gpr_get(struct task_struct *target,  			 const struct user_regset *regset, -			 unsigned int pos, unsigned int count, -			 void *kbuf, void __user *ubuf) +			 struct membuf to)  { -	struct pt_regs *regs; - -	regs = task_pt_regs(target); -	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, regs, 0, -1); +	return membuf_write(&to, task_pt_regs(target), +			    sizeof(struct user_regs_struct));  }  static int riscv_gpr_set(struct task_struct *target, @@ -55,21 +52,13 @@ static int riscv_gpr_set(struct task_struct *target,  #ifdef CONFIG_FPU  static int riscv_fpr_get(struct task_struct *target,  			 const struct user_regset *regset, -			 unsigned int pos, unsigned int count, -			 void *kbuf, void __user *ubuf) +			 struct membuf to)  { -	int ret;  	struct __riscv_d_ext_state *fstate = &target->thread.fstate; -	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, fstate, 0, -				  offsetof(struct __riscv_d_ext_state, fcsr)); -	if (!ret) { -		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, fstate, 0, -					  offsetof(struct __riscv_d_ext_state, fcsr) + -					  sizeof(fstate->fcsr)); -	} - -	return ret; +	membuf_write(&to, fstate, offsetof(struct __riscv_d_ext_state, fcsr)); +	membuf_store(&to, fstate->fcsr); +	return membuf_zero(&to, 4);	// explicitly pad  }  static int riscv_fpr_set(struct task_struct *target, @@ -98,8 +87,8 @@ static const struct user_regset riscv_user_regset[] = {  		.n = ELF_NGREG,  		.size = sizeof(elf_greg_t),  		.align = sizeof(elf_greg_t), -		.get = &riscv_gpr_get, -		.set = &riscv_gpr_set, +		.regset_get = riscv_gpr_get, +		.set = riscv_gpr_set,  	},  #ifdef CONFIG_FPU  	[REGSET_F] = { @@ -107,8 +96,8 @@ static const struct user_regset riscv_user_regset[] = {  		.n = ELF_NFPREG,  		.size = sizeof(elf_fpreg_t),  		.align = sizeof(elf_fpreg_t), -		.get = &riscv_fpr_get, -		.set = &riscv_fpr_set, +		.regset_get = riscv_fpr_get, +		.set = riscv_fpr_set,  	},  #endif  }; diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index 3cc15c066298..a09b9e98936c 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c @@ -945,28 +945,14 @@ asmlinkage void do_syscall_trace_exit(struct pt_regs *regs)  static int s390_regs_get(struct task_struct *target,  			 const struct user_regset *regset, -			 unsigned int pos, unsigned int count, -			 void *kbuf, void __user *ubuf) +			 struct membuf to)  { +	unsigned pos;  	if (target == current)  		save_access_regs(target->thread.acrs); -	if (kbuf) { -		unsigned long *k = kbuf; -		while (count > 0) { -			*k++ = __peek_user(target, pos); -			count -= sizeof(*k); -			pos += sizeof(*k); -		} -	} else { -		unsigned long __user *u = ubuf; -		while (count > 0) { -			if (__put_user(__peek_user(target, pos), u++)) -				return -EFAULT; -			count -= sizeof(*u); -			pos += sizeof(*u); -		} -	} +	for (pos = 0; pos < sizeof(s390_regs); pos += sizeof(long)) +		membuf_store(&to, __peek_user(target, pos));  	return 0;  } @@ -1007,8 +993,8 @@ static int s390_regs_set(struct task_struct *target,  }  static int s390_fpregs_get(struct task_struct *target, -			   const struct user_regset *regset, unsigned int pos, -			   unsigned int count, void *kbuf, void __user *ubuf) +			   const struct user_regset *regset, +			   struct membuf to)  {  	_s390_fp_regs fp_regs; @@ -1018,8 +1004,7 @@ static int s390_fpregs_get(struct task_struct *target,  	fp_regs.fpc = target->thread.fpu.fpc;  	fpregs_store(&fp_regs, &target->thread.fpu); -	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, -				   &fp_regs, 0, -1); +	return membuf_write(&to, &fp_regs, sizeof(fp_regs));  }  static int s390_fpregs_set(struct task_struct *target, @@ -1066,20 +1051,9 @@ static int s390_fpregs_set(struct task_struct *target,  static int s390_last_break_get(struct task_struct *target,  			       const struct user_regset *regset, -			       unsigned int pos, unsigned int count, -			       void *kbuf, void __user *ubuf) +			       struct membuf to)  { -	if (count > 0) { -		if (kbuf) { -			unsigned long *k = kbuf; -			*k = target->thread.last_break; -		} else { -			unsigned long  __user *u = ubuf; -			if (__put_user(target->thread.last_break, u)) -				return -EFAULT; -		} -	} -	return 0; +	return membuf_store(&to, target->thread.last_break);  }  static int s390_last_break_set(struct task_struct *target, @@ -1092,16 +1066,13 @@ static int s390_last_break_set(struct task_struct *target,  static int s390_tdb_get(struct task_struct *target,  			const struct user_regset *regset, -			unsigned int pos, unsigned int count, -			void *kbuf, void __user *ubuf) +			struct membuf to)  {  	struct pt_regs *regs = task_pt_regs(target); -	unsigned char *data;  	if (!(regs->int_code & 0x200))  		return -ENODATA; -	data = target->thread.trap_tdb; -	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, data, 0, 256); +	return membuf_write(&to, target->thread.trap_tdb, 256);  }  static int s390_tdb_set(struct task_struct *target, @@ -1114,8 +1085,7 @@ static int s390_tdb_set(struct task_struct *target,  static int s390_vxrs_low_get(struct task_struct *target,  			     const struct user_regset *regset, -			     unsigned int pos, unsigned int count, -			     void *kbuf, void __user *ubuf) +			     struct membuf to)  {  	__u64 vxrs[__NUM_VXRS_LOW];  	int i; @@ -1126,7 +1096,7 @@ static int s390_vxrs_low_get(struct task_struct *target,  		save_fpu_regs();  	for (i = 0; i < __NUM_VXRS_LOW; i++)  		vxrs[i] = *((__u64 *)(target->thread.fpu.vxrs + i) + 1); -	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, vxrs, 0, -1); +	return membuf_write(&to, vxrs, sizeof(vxrs));  }  static int s390_vxrs_low_set(struct task_struct *target, @@ -1155,18 +1125,14 @@ static int s390_vxrs_low_set(struct task_struct *target,  static int s390_vxrs_high_get(struct task_struct *target,  			      const struct user_regset *regset, -			      unsigned int pos, unsigned int count, -			      void *kbuf, void __user *ubuf) +			      struct membuf to)  { -	__vector128 vxrs[__NUM_VXRS_HIGH]; -  	if (!MACHINE_HAS_VX)  		return -ENODEV;  	if (target == current)  		save_fpu_regs(); -	memcpy(vxrs, target->thread.fpu.vxrs + __NUM_VXRS_LOW, sizeof(vxrs)); - -	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, vxrs, 0, -1); +	return membuf_write(&to, target->thread.fpu.vxrs + __NUM_VXRS_LOW, +			    __NUM_VXRS_HIGH * sizeof(__vector128));  }  static int s390_vxrs_high_set(struct task_struct *target, @@ -1188,12 +1154,9 @@ static int s390_vxrs_high_set(struct task_struct *target,  static int s390_system_call_get(struct task_struct *target,  				const struct user_regset *regset, -				unsigned int pos, unsigned int count, -				void *kbuf, void __user *ubuf) +				struct membuf to)  { -	unsigned int *data = &target->thread.system_call; -	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, -				   data, 0, sizeof(unsigned int)); +	return membuf_store(&to, target->thread.system_call);  }  static int s390_system_call_set(struct task_struct *target, @@ -1208,8 +1171,7 @@ static int s390_system_call_set(struct task_struct *target,  static int s390_gs_cb_get(struct task_struct *target,  			  const struct user_regset *regset, -			  unsigned int pos, unsigned int count, -			  void *kbuf, void __user *ubuf) +			  struct membuf to)  {  	struct gs_cb *data = target->thread.gs_cb; @@ -1219,8 +1181,7 @@ static int s390_gs_cb_get(struct task_struct *target,  		return -ENODATA;  	if (target == current)  		save_gs_cb(data); -	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, -				   data, 0, sizeof(struct gs_cb)); +	return membuf_write(&to, data, sizeof(struct gs_cb));  }  static int s390_gs_cb_set(struct task_struct *target, @@ -1264,8 +1225,7 @@ static int s390_gs_cb_set(struct task_struct *target,  static int s390_gs_bc_get(struct task_struct *target,  			  const struct user_regset *regset, -			  unsigned int pos, unsigned int count, -			  void *kbuf, void __user *ubuf) +			  struct membuf to)  {  	struct gs_cb *data = target->thread.gs_bc_cb; @@ -1273,8 +1233,7 @@ static int s390_gs_bc_get(struct task_struct *target,  		return -ENODEV;  	if (!data)  		return -ENODATA; -	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, -				   data, 0, sizeof(struct gs_cb)); +	return membuf_write(&to, data, sizeof(struct gs_cb));  }  static int s390_gs_bc_set(struct task_struct *target, @@ -1325,8 +1284,7 @@ static bool is_ri_cb_valid(struct runtime_instr_cb *cb)  static int s390_runtime_instr_get(struct task_struct *target,  				const struct user_regset *regset, -				unsigned int pos, unsigned int count, -				void *kbuf, void __user *ubuf) +				struct membuf to)  {  	struct runtime_instr_cb *data = target->thread.ri_cb; @@ -1335,8 +1293,7 @@ static int s390_runtime_instr_get(struct task_struct *target,  	if (!data)  		return -ENODATA; -	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, -				   data, 0, sizeof(struct runtime_instr_cb)); +	return membuf_write(&to, data, sizeof(struct runtime_instr_cb));  }  static int s390_runtime_instr_set(struct task_struct *target, @@ -1392,7 +1349,7 @@ static const struct user_regset s390_regsets[] = {  		.n = sizeof(s390_regs) / sizeof(long),  		.size = sizeof(long),  		.align = sizeof(long), -		.get = s390_regs_get, +		.regset_get = s390_regs_get,  		.set = s390_regs_set,  	},  	{ @@ -1400,7 +1357,7 @@ static const struct user_regset s390_regsets[] = {  		.n = sizeof(s390_fp_regs) / sizeof(long),  		.size = sizeof(long),  		.align = sizeof(long), -		.get = s390_fpregs_get, +		.regset_get = s390_fpregs_get,  		.set = s390_fpregs_set,  	},  	{ @@ -1408,7 +1365,7 @@ static const struct user_regset s390_regsets[] = {  		.n = 1,  		.size = sizeof(unsigned int),  		.align = sizeof(unsigned int), -		.get = s390_system_call_get, +		.regset_get = s390_system_call_get,  		.set = s390_system_call_set,  	},  	{ @@ -1416,7 +1373,7 @@ static const struct user_regset s390_regsets[] = {  		.n = 1,  		.size = sizeof(long),  		.align = sizeof(long), -		.get = s390_last_break_get, +		.regset_get = s390_last_break_get,  		.set = s390_last_break_set,  	},  	{ @@ -1424,7 +1381,7 @@ static const struct user_regset s390_regsets[] = {  		.n = 1,  		.size = 256,  		.align = 1, -		.get = s390_tdb_get, +		.regset_get = s390_tdb_get,  		.set = s390_tdb_set,  	},  	{ @@ -1432,7 +1389,7 @@ static const struct user_regset s390_regsets[] = {  		.n = __NUM_VXRS_LOW,  		.size = sizeof(__u64),  		.align = sizeof(__u64), -		.get = s390_vxrs_low_get, +		.regset_get = s390_vxrs_low_get,  		.set = s390_vxrs_low_set,  	},  	{ @@ -1440,7 +1397,7 @@ static const struct user_regset s390_regsets[] = {  		.n = __NUM_VXRS_HIGH,  		.size = sizeof(__vector128),  		.align = sizeof(__vector128), -		.get = s390_vxrs_high_get, +		.regset_get = s390_vxrs_high_get,  		.set = s390_vxrs_high_set,  	},  	{ @@ -1448,7 +1405,7 @@ static const struct user_regset s390_regsets[] = {  		.n = sizeof(struct gs_cb) / sizeof(__u64),  		.size = sizeof(__u64),  		.align = sizeof(__u64), -		.get = s390_gs_cb_get, +		.regset_get = s390_gs_cb_get,  		.set = s390_gs_cb_set,  	},  	{ @@ -1456,7 +1413,7 @@ static const struct user_regset s390_regsets[] = {  		.n = sizeof(struct gs_cb) / sizeof(__u64),  		.size = sizeof(__u64),  		.align = sizeof(__u64), -		.get = s390_gs_bc_get, +		.regset_get = s390_gs_bc_get,  		.set = s390_gs_bc_set,  	},  	{ @@ -1464,7 +1421,7 @@ static const struct user_regset s390_regsets[] = {  		.n = sizeof(struct runtime_instr_cb) / sizeof(__u64),  		.size = sizeof(__u64),  		.align = sizeof(__u64), -		.get = s390_runtime_instr_get, +		.regset_get = s390_runtime_instr_get,  		.set = s390_runtime_instr_set,  	},  }; @@ -1479,28 +1436,15 @@ static const struct user_regset_view user_s390_view = {  #ifdef CONFIG_COMPAT  static int s390_compat_regs_get(struct task_struct *target,  				const struct user_regset *regset, -				unsigned int pos, unsigned int count, -				void *kbuf, void __user *ubuf) +				struct membuf to)  { +	unsigned n; +  	if (target == current)  		save_access_regs(target->thread.acrs); -	if (kbuf) { -		compat_ulong_t *k = kbuf; -		while (count > 0) { -			*k++ = __peek_user_compat(target, pos); -			count -= sizeof(*k); -			pos += sizeof(*k); -		} -	} else { -		compat_ulong_t __user *u = ubuf; -		while (count > 0) { -			if (__put_user(__peek_user_compat(target, pos), u++)) -				return -EFAULT; -			count -= sizeof(*u); -			pos += sizeof(*u); -		} -	} +	for (n = 0; n < sizeof(s390_compat_regs); n += sizeof(compat_ulong_t)) +		membuf_store(&to, __peek_user_compat(target, n));  	return 0;  } @@ -1542,29 +1486,14 @@ static int s390_compat_regs_set(struct task_struct *target,  static int s390_compat_regs_high_get(struct task_struct *target,  				     const struct user_regset *regset, -				     unsigned int pos, unsigned int count, -				     void *kbuf, void __user *ubuf) +				     struct membuf to)  {  	compat_ulong_t *gprs_high; +	int i; -	gprs_high = (compat_ulong_t *) -		&task_pt_regs(target)->gprs[pos / sizeof(compat_ulong_t)]; -	if (kbuf) { -		compat_ulong_t *k = kbuf; -		while (count > 0) { -			*k++ = *gprs_high; -			gprs_high += 2; -			count -= sizeof(*k); -		} -	} else { -		compat_ulong_t __user *u = ubuf; -		while (count > 0) { -			if (__put_user(*gprs_high, u++)) -				return -EFAULT; -			gprs_high += 2; -			count -= sizeof(*u); -		} -	} +	gprs_high = (compat_ulong_t *)task_pt_regs(target)->gprs; +	for (i = 0; i < NUM_GPRS; i++, gprs_high += 2) +		membuf_store(&to, *gprs_high);  	return 0;  } @@ -1603,23 +1532,11 @@ static int s390_compat_regs_high_set(struct task_struct *target,  static int s390_compat_last_break_get(struct task_struct *target,  				      const struct user_regset *regset, -				      unsigned int pos, unsigned int count, -				      void *kbuf, void __user *ubuf) +				      struct membuf to)  { -	compat_ulong_t last_break; +	compat_ulong_t last_break = target->thread.last_break; -	if (count > 0) { -		last_break = target->thread.last_break; -		if (kbuf) { -			unsigned long *k = kbuf; -			*k = last_break; -		} else { -			unsigned long  __user *u = ubuf; -			if (__put_user(last_break, u)) -				return -EFAULT; -		} -	} -	return 0; +	return membuf_store(&to, (unsigned long)last_break);  }  static int s390_compat_last_break_set(struct task_struct *target, @@ -1636,7 +1553,7 @@ static const struct user_regset s390_compat_regsets[] = {  		.n = sizeof(s390_compat_regs) / sizeof(compat_long_t),  		.size = sizeof(compat_long_t),  		.align = sizeof(compat_long_t), -		.get = s390_compat_regs_get, +		.regset_get = s390_compat_regs_get,  		.set = s390_compat_regs_set,  	},  	{ @@ -1644,7 +1561,7 @@ static const struct user_regset s390_compat_regsets[] = {  		.n = sizeof(s390_fp_regs) / sizeof(compat_long_t),  		.size = sizeof(compat_long_t),  		.align = sizeof(compat_long_t), -		.get = s390_fpregs_get, +		.regset_get = s390_fpregs_get,  		.set = s390_fpregs_set,  	},  	{ @@ -1652,7 +1569,7 @@ static const struct user_regset s390_compat_regsets[] = {  		.n = 1,  		.size = sizeof(compat_uint_t),  		.align = sizeof(compat_uint_t), -		.get = s390_system_call_get, +		.regset_get = s390_system_call_get,  		.set = s390_system_call_set,  	},  	{ @@ -1660,7 +1577,7 @@ static const struct user_regset s390_compat_regsets[] = {  		.n = 1,  		.size = sizeof(long),  		.align = sizeof(long), -		.get = s390_compat_last_break_get, +		.regset_get = s390_compat_last_break_get,  		.set = s390_compat_last_break_set,  	},  	{ @@ -1668,7 +1585,7 @@ static const struct user_regset s390_compat_regsets[] = {  		.n = 1,  		.size = 256,  		.align = 1, -		.get = s390_tdb_get, +		.regset_get = s390_tdb_get,  		.set = s390_tdb_set,  	},  	{ @@ -1676,7 +1593,7 @@ static const struct user_regset s390_compat_regsets[] = {  		.n = __NUM_VXRS_LOW,  		.size = sizeof(__u64),  		.align = sizeof(__u64), -		.get = s390_vxrs_low_get, +		.regset_get = s390_vxrs_low_get,  		.set = s390_vxrs_low_set,  	},  	{ @@ -1684,7 +1601,7 @@ static const struct user_regset s390_compat_regsets[] = {  		.n = __NUM_VXRS_HIGH,  		.size = sizeof(__vector128),  		.align = sizeof(__vector128), -		.get = s390_vxrs_high_get, +		.regset_get = s390_vxrs_high_get,  		.set = s390_vxrs_high_set,  	},  	{ @@ -1692,7 +1609,7 @@ static const struct user_regset s390_compat_regsets[] = {  		.n = sizeof(s390_compat_regs_high) / sizeof(compat_long_t),  		.size = sizeof(compat_long_t),  		.align = sizeof(compat_long_t), -		.get = s390_compat_regs_high_get, +		.regset_get = s390_compat_regs_high_get,  		.set = s390_compat_regs_high_set,  	},  	{ @@ -1700,7 +1617,7 @@ static const struct user_regset s390_compat_regsets[] = {  		.n = sizeof(struct gs_cb) / sizeof(__u64),  		.size = sizeof(__u64),  		.align = sizeof(__u64), -		.get = s390_gs_cb_get, +		.regset_get = s390_gs_cb_get,  		.set = s390_gs_cb_set,  	},  	{ @@ -1708,7 +1625,7 @@ static const struct user_regset s390_compat_regsets[] = {  		.n = sizeof(struct gs_cb) / sizeof(__u64),  		.size = sizeof(__u64),  		.align = sizeof(__u64), -		.get = s390_gs_bc_get, +		.regset_get = s390_gs_bc_get,  		.set = s390_gs_bc_set,  	},  	{ @@ -1716,7 +1633,7 @@ static const struct user_regset s390_compat_regsets[] = {  		.n = sizeof(struct runtime_instr_cb) / sizeof(__u64),  		.size = sizeof(__u64),  		.align = sizeof(__u64), -		.get = s390_runtime_instr_get, +		.regset_get = s390_runtime_instr_get,  		.set = s390_runtime_instr_set,  	},  }; diff --git a/arch/sh/kernel/process_32.c b/arch/sh/kernel/process_32.c index b0fefd8f53a6..cde0a66116d2 100644 --- a/arch/sh/kernel/process_32.c +++ b/arch/sh/kernel/process_32.c @@ -103,9 +103,8 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)  	fpvalid = !!tsk_used_math(tsk);  	if (fpvalid) -		fpvalid = !fpregs_get(tsk, NULL, 0, -				      sizeof(struct user_fpu_struct), -				      fpu, NULL); +		fpvalid = !fpregs_get(tsk, NULL, +				      (struct membuf){fpu, sizeof(*fpu)});  #endif  	return fpvalid; diff --git a/arch/sh/kernel/ptrace_32.c b/arch/sh/kernel/ptrace_32.c index 64bfb714943e..5c93bdb6c41a 100644 --- a/arch/sh/kernel/ptrace_32.c +++ b/arch/sh/kernel/ptrace_32.c @@ -134,26 +134,11 @@ void ptrace_disable(struct task_struct *child)  static int genregs_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; -	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, -				  regs->regs, -				  0, 16 * sizeof(unsigned long)); -	if (!ret) -		/* PC, PR, SR, GBR, MACH, MACL, TRA */ -		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, -					  ®s->pc, -					  offsetof(struct pt_regs, pc), -					  sizeof(struct pt_regs)); -	if (!ret) -		ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, -					       sizeof(struct pt_regs), -1); - -	return ret; +	return membuf_write(&to, regs, sizeof(struct pt_regs));  }  static int genregs_set(struct task_struct *target, @@ -182,8 +167,7 @@ static int genregs_set(struct task_struct *target,  #ifdef CONFIG_SH_FPU  int fpregs_get(struct task_struct *target,  	       const struct user_regset *regset, -	       unsigned int pos, unsigned int count, -	       void *kbuf, void __user *ubuf) +	       struct membuf to)  {  	int ret; @@ -191,12 +175,8 @@ int fpregs_get(struct task_struct *target,  	if (ret)  		return ret; -	if ((boot_cpu_data.flags & CPU_HAS_FPU)) -		return user_regset_copyout(&pos, &count, &kbuf, &ubuf, -					   &target->thread.xstate->hardfpu, 0, -1); - -	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, -				   &target->thread.xstate->softfpu, 0, -1); +	return membuf_write(&to, target->thread.xstate, +			    sizeof(struct user_fpu_struct));  }  static int fpregs_set(struct task_struct *target, @@ -230,20 +210,12 @@ static int fpregs_active(struct task_struct *target,  #ifdef CONFIG_SH_DSP  static int dspregs_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_dspregs *regs =  		(struct pt_dspregs *)&target->thread.dsp_status.dsp_regs; -	int ret; -	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, regs, -				  0, sizeof(struct pt_dspregs)); -	if (!ret) -		ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, -					       sizeof(struct pt_dspregs), -1); - -	return ret; +	return membuf_write(&to, regs, sizeof(struct pt_dspregs));  }  static int dspregs_set(struct task_struct *target, @@ -324,7 +296,7 @@ static const struct user_regset sh_regsets[] = {  		.n		= ELF_NGREG,  		.size		= sizeof(long),  		.align		= sizeof(long), -		.get		= genregs_get, +		.regset_get		= genregs_get,  		.set		= genregs_set,  	}, @@ -334,7 +306,7 @@ static const struct user_regset sh_regsets[] = {  		.n		= sizeof(struct user_fpu_struct) / sizeof(long),  		.size		= sizeof(long),  		.align		= sizeof(long), -		.get		= fpregs_get, +		.regset_get		= fpregs_get,  		.set		= fpregs_set,  		.active		= fpregs_active,  	}, @@ -345,7 +317,7 @@ static const struct user_regset sh_regsets[] = {  		.n		= sizeof(struct pt_dspregs) / sizeof(long),  		.size		= sizeof(long),  		.align		= sizeof(long), -		.get		= dspregs_get, +		.regset_get		= dspregs_get,  		.set		= dspregs_set,  		.active		= dspregs_active,  	}, 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/x86/include/asm/fpu/internal.h b/arch/x86/include/asm/fpu/internal.h index 6b10cdaa7c96..0a460f2a3f90 100644 --- a/arch/x86/include/asm/fpu/internal.h +++ b/arch/x86/include/asm/fpu/internal.h @@ -34,7 +34,6 @@ extern int  fpu__copy(struct task_struct *dst, struct task_struct *src);  extern void fpu__clear_user_states(struct fpu *fpu);  extern void fpu__clear_all(struct fpu *fpu);  extern int  fpu__exception_code(struct fpu *fpu, int trap_nr); -extern int  dump_fpu(struct pt_regs *ptregs, struct user_i387_struct *fpstate);  /*   * Boot time FPU initialization functions: diff --git a/arch/x86/include/asm/fpu/regset.h b/arch/x86/include/asm/fpu/regset.h index d5bdffb9d27f..4f928d6a367b 100644 --- a/arch/x86/include/asm/fpu/regset.h +++ b/arch/x86/include/asm/fpu/regset.h @@ -8,8 +8,8 @@  #include <linux/regset.h>  extern user_regset_active_fn regset_fpregs_active, regset_xregset_fpregs_active; -extern user_regset_get_fn fpregs_get, xfpregs_get, fpregs_soft_get, -				xstateregs_get; +extern user_regset_get2_fn fpregs_get, xfpregs_get, fpregs_soft_get, +				 xstateregs_get;  extern user_regset_set_fn fpregs_set, xfpregs_set, fpregs_soft_set,  				 xstateregs_set; diff --git a/arch/x86/include/asm/fpu/xstate.h b/arch/x86/include/asm/fpu/xstate.h index 1559554af931..14ab815132d4 100644 --- a/arch/x86/include/asm/fpu/xstate.h +++ b/arch/x86/include/asm/fpu/xstate.h @@ -104,8 +104,8 @@ void *get_xsave_addr(struct xregs_state *xsave, int xfeature_nr);  const void *get_xsave_field_ptr(int xfeature_nr);  int using_compacted_format(void);  int xfeature_size(int xfeature_nr); -int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int offset, unsigned int size); -int copy_xstate_to_user(void __user *ubuf, struct xregs_state *xsave, unsigned int offset, unsigned int size); +struct membuf; +void copy_xstate_to_kernel(struct membuf to, struct xregs_state *xsave);  int copy_kernel_to_xstate(struct xregs_state *xsave, const void *kbuf);  int copy_user_to_xstate(struct xregs_state *xsave, const void __user *ubuf);  void copy_supervisor_to_kernel(struct xregs_state *xsave); diff --git a/arch/x86/kernel/fpu/regset.c b/arch/x86/kernel/fpu/regset.c index bd1d0649f8ce..c413756ba89f 100644 --- a/arch/x86/kernel/fpu/regset.c +++ b/arch/x86/kernel/fpu/regset.c @@ -27,8 +27,7 @@ int regset_xregset_fpregs_active(struct task_struct *target, const struct user_r  }  int xfpregs_get(struct task_struct *target, const struct user_regset *regset, -		unsigned int pos, unsigned int count, -		void *kbuf, void __user *ubuf) +		struct membuf to)  {  	struct fpu *fpu = &target->thread.fpu; @@ -38,8 +37,7 @@ int xfpregs_get(struct task_struct *target, const struct user_regset *regset,  	fpu__prepare_read(fpu);  	fpstate_sanitize_xstate(fpu); -	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, -				   &fpu->state.fxsave, 0, -1); +	return membuf_write(&to, &fpu->state.fxsave, sizeof(struct fxregs_state));  }  int xfpregs_set(struct task_struct *target, const struct user_regset *regset, @@ -74,12 +72,10 @@ int xfpregs_set(struct task_struct *target, const struct user_regset *regset,  }  int xstateregs_get(struct task_struct *target, const struct user_regset *regset, -		unsigned int pos, unsigned int count, -		void *kbuf, void __user *ubuf) +		struct membuf to)  {  	struct fpu *fpu = &target->thread.fpu;  	struct xregs_state *xsave; -	int ret;  	if (!boot_cpu_has(X86_FEATURE_XSAVE))  		return -ENODEV; @@ -89,10 +85,8 @@ int xstateregs_get(struct task_struct *target, const struct user_regset *regset,  	fpu__prepare_read(fpu);  	if (using_compacted_format()) { -		if (kbuf) -			ret = copy_xstate_to_kernel(kbuf, xsave, pos, count); -		else -			ret = copy_xstate_to_user(ubuf, xsave, pos, count); +		copy_xstate_to_kernel(to, xsave); +		return 0;  	} else {  		fpstate_sanitize_xstate(fpu);  		/* @@ -105,9 +99,8 @@ int xstateregs_get(struct task_struct *target, const struct user_regset *regset,  		/*  		 * Copy the xstate memory layout.  		 */ -		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, xsave, 0, -1); +		return membuf_write(&to, xsave, fpu_user_xstate_size);  	} -	return ret;  }  int xstateregs_set(struct task_struct *target, const struct user_regset *regset, @@ -293,8 +286,7 @@ void convert_to_fxsr(struct fxregs_state *fxsave,  }  int fpregs_get(struct task_struct *target, const struct user_regset *regset, -	       unsigned int pos, unsigned int count, -	       void *kbuf, void __user *ubuf) +	       struct membuf to)  {  	struct fpu *fpu = &target->thread.fpu;  	struct user_i387_ia32_struct env; @@ -302,23 +294,22 @@ int fpregs_get(struct task_struct *target, const struct user_regset *regset,  	fpu__prepare_read(fpu);  	if (!boot_cpu_has(X86_FEATURE_FPU)) -		return fpregs_soft_get(target, regset, pos, count, kbuf, ubuf); +		return fpregs_soft_get(target, regset, to); -	if (!boot_cpu_has(X86_FEATURE_FXSR)) -		return user_regset_copyout(&pos, &count, &kbuf, &ubuf, -					   &fpu->state.fsave, 0, -					   -1); +	if (!boot_cpu_has(X86_FEATURE_FXSR)) { +		return membuf_write(&to, &fpu->state.fsave, +				    sizeof(struct fregs_state)); +	}  	fpstate_sanitize_xstate(fpu); -	if (kbuf && pos == 0 && count == sizeof(env)) { -		convert_from_fxsr(kbuf, target); +	if (to.left == sizeof(env)) { +		convert_from_fxsr(to.p, target);  		return 0;  	}  	convert_from_fxsr(&env, target); - -	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &env, 0, -1); +	return membuf_write(&to, &env, sizeof(env));  }  int fpregs_set(struct task_struct *target, const struct user_regset *regset, @@ -356,20 +347,4 @@ int fpregs_set(struct task_struct *target, const struct user_regset *regset,  	return ret;  } -/* - * FPU state for core dumps. - * This is only used for a.out dumps now. - * It is declared generically using elf_fpregset_t (which is - * struct user_i387_struct) but is in fact only used for 32-bit - * dumps, so on 64-bit it is really struct user_i387_ia32_struct. - */ -int dump_fpu(struct pt_regs *regs, struct user_i387_struct *ufpu) -{ -	struct task_struct *tsk = current; - -	return !fpregs_get(tsk, NULL, 0, sizeof(struct user_i387_ia32_struct), -			   ufpu, NULL); -} -EXPORT_SYMBOL(dump_fpu); -  #endif	/* CONFIG_X86_32 || CONFIG_IA32_EMULATION */ diff --git a/arch/x86/kernel/fpu/signal.c b/arch/x86/kernel/fpu/signal.c index 9393a445d73c..a4ec65317a7f 100644 --- a/arch/x86/kernel/fpu/signal.c +++ b/arch/x86/kernel/fpu/signal.c @@ -170,14 +170,15 @@ int copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size)  	ia32_fxstate &= (IS_ENABLED(CONFIG_X86_32) ||  			 IS_ENABLED(CONFIG_IA32_EMULATION)); +	if (!static_cpu_has(X86_FEATURE_FPU)) { +		struct user_i387_ia32_struct fp; +		fpregs_soft_get(current, NULL, (struct membuf){.p = &fp, +						.left = sizeof(fp)}); +		return copy_to_user(buf, &fp, sizeof(fp)) ? -EFAULT : 0; +	} +  	if (!access_ok(buf, size))  		return -EACCES; - -	if (!static_cpu_has(X86_FEATURE_FPU)) -		return fpregs_soft_get(current, NULL, 0, -			sizeof(struct user_i387_ia32_struct), NULL, -			(struct _fpstate_32 __user *) buf) ? -1 : 1; -  retry:  	/*  	 * Load the FPU registers if they are not valid for the current task. diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c index be2a68a09d19..7a2bf884fede 100644 --- a/arch/x86/kernel/fpu/xstate.c +++ b/arch/x86/kernel/fpu/xstate.c @@ -1014,32 +1014,20 @@ static inline bool xfeatures_mxcsr_quirk(u64 xfeatures)  	return true;  } -static void fill_gap(unsigned to, void **kbuf, unsigned *pos, unsigned *count) +static void fill_gap(struct membuf *to, unsigned *last, unsigned offset)  { -	if (*pos < to) { -		unsigned size = to - *pos; - -		if (size > *count) -			size = *count; -		memcpy(*kbuf, (void *)&init_fpstate.xsave + *pos, size); -		*kbuf += size; -		*pos += size; -		*count -= size; -	} +	if (*last >= offset) +		return; +	membuf_write(to, (void *)&init_fpstate.xsave + *last, offset - *last); +	*last = offset;  } -static void copy_part(unsigned offset, unsigned size, void *from, -			void **kbuf, unsigned *pos, unsigned *count) +static void copy_part(struct membuf *to, unsigned *last, unsigned offset, +		      unsigned size, void *from)  { -	fill_gap(offset, kbuf, pos, count); -	if (size > *count) -		size = *count; -	if (size) { -		memcpy(*kbuf, from, size); -		*kbuf += size; -		*pos += size; -		*count -= size; -	} +	fill_gap(to, last, offset); +	membuf_write(to, from, size); +	*last = offset + size;  }  /* @@ -1049,20 +1037,15 @@ static void copy_part(unsigned offset, unsigned size, void *from,   * It supports partial copy but pos always starts from zero. This is called   * from xstateregs_get() and there we check the CPU has XSAVES.   */ -int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int offset_start, unsigned int size_total) +void copy_xstate_to_kernel(struct membuf to, struct xregs_state *xsave)  {  	struct xstate_header header;  	const unsigned off_mxcsr = offsetof(struct fxregs_state, mxcsr); -	unsigned count = size_total; +	unsigned size = to.left; +	unsigned last = 0;  	int i;  	/* -	 * Currently copy_regset_to_user() starts from pos 0: -	 */ -	if (unlikely(offset_start != 0)) -		return -EFAULT; - -	/*  	 * The destination is a ptrace buffer; we put in only user xstates:  	 */  	memset(&header, 0, sizeof(header)); @@ -1070,27 +1053,26 @@ int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int of  	header.xfeatures &= xfeatures_mask_user();  	if (header.xfeatures & XFEATURE_MASK_FP) -		copy_part(0, off_mxcsr, -			  &xsave->i387, &kbuf, &offset_start, &count); +		copy_part(&to, &last, 0, off_mxcsr, &xsave->i387);  	if (header.xfeatures & (XFEATURE_MASK_SSE | XFEATURE_MASK_YMM)) -		copy_part(off_mxcsr, MXCSR_AND_FLAGS_SIZE, -			  &xsave->i387.mxcsr, &kbuf, &offset_start, &count); +		copy_part(&to, &last, off_mxcsr, +			  MXCSR_AND_FLAGS_SIZE, &xsave->i387.mxcsr);  	if (header.xfeatures & XFEATURE_MASK_FP) -		copy_part(offsetof(struct fxregs_state, st_space), 128, -			  &xsave->i387.st_space, &kbuf, &offset_start, &count); +		copy_part(&to, &last, offsetof(struct fxregs_state, st_space), +			  128, &xsave->i387.st_space);  	if (header.xfeatures & XFEATURE_MASK_SSE) -		copy_part(xstate_offsets[XFEATURE_SSE], 256, -			  &xsave->i387.xmm_space, &kbuf, &offset_start, &count); +		copy_part(&to, &last, xstate_offsets[XFEATURE_SSE], +			  256, &xsave->i387.xmm_space);  	/*  	 * Fill xsave->i387.sw_reserved value for ptrace frame:  	 */ -	copy_part(offsetof(struct fxregs_state, sw_reserved), 48, -		  xstate_fx_sw_bytes, &kbuf, &offset_start, &count); +	copy_part(&to, &last, offsetof(struct fxregs_state, sw_reserved), +		  48, xstate_fx_sw_bytes);  	/*  	 * Copy xregs_state->header:  	 */ -	copy_part(offsetof(struct xregs_state, header), sizeof(header), -		  &header, &kbuf, &offset_start, &count); +	copy_part(&to, &last, offsetof(struct xregs_state, header), +		  sizeof(header), &header);  	for (i = FIRST_EXTENDED_XFEATURE; i < XFEATURE_MAX; i++) {  		/* @@ -1099,104 +1081,12 @@ int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int of  		if ((header.xfeatures >> i) & 1) {  			void *src = __raw_xsave_addr(xsave, i); -			copy_part(xstate_offsets[i], xstate_sizes[i], -				  src, &kbuf, &offset_start, &count); +			copy_part(&to, &last, xstate_offsets[i], +				  xstate_sizes[i], src);  		}  	} -	fill_gap(size_total, &kbuf, &offset_start, &count); - -	return 0; -} - -static inline int -__copy_xstate_to_user(void __user *ubuf, const void *data, unsigned int offset, unsigned int size, unsigned int size_total) -{ -	if (!size) -		return 0; - -	if (offset < size_total) { -		unsigned int copy = min(size, size_total - offset); - -		if (__copy_to_user(ubuf + offset, data, copy)) -			return -EFAULT; -	} -	return 0; -} - -/* - * Convert from kernel XSAVES compacted format to standard format and copy - * to a user-space buffer. It supports partial copy but pos always starts from - * zero. This is called from xstateregs_get() and there we check the CPU - * has XSAVES. - */ -int copy_xstate_to_user(void __user *ubuf, struct xregs_state *xsave, unsigned int offset_start, unsigned int size_total) -{ -	unsigned int offset, size; -	int ret, i; -	struct xstate_header header; - -	/* -	 * Currently copy_regset_to_user() starts from pos 0: -	 */ -	if (unlikely(offset_start != 0)) -		return -EFAULT; - -	/* -	 * The destination is a ptrace buffer; we put in only user xstates: -	 */ -	memset(&header, 0, sizeof(header)); -	header.xfeatures = xsave->header.xfeatures; -	header.xfeatures &= xfeatures_mask_user(); - -	/* -	 * Copy xregs_state->header: -	 */ -	offset = offsetof(struct xregs_state, header); -	size = sizeof(header); - -	ret = __copy_xstate_to_user(ubuf, &header, offset, size, size_total); -	if (ret) -		return ret; - -	for (i = 0; i < XFEATURE_MAX; i++) { -		/* -		 * Copy only in-use xstates: -		 */ -		if ((header.xfeatures >> i) & 1) { -			void *src = __raw_xsave_addr(xsave, i); - -			offset = xstate_offsets[i]; -			size = xstate_sizes[i]; - -			/* The next component has to fit fully into the output buffer: */ -			if (offset + size > size_total) -				break; - -			ret = __copy_xstate_to_user(ubuf, src, offset, size, size_total); -			if (ret) -				return ret; -		} - -	} - -	if (xfeatures_mxcsr_quirk(header.xfeatures)) { -		offset = offsetof(struct fxregs_state, mxcsr); -		size = MXCSR_AND_FLAGS_SIZE; -		__copy_xstate_to_user(ubuf, &xsave->i387.mxcsr, offset, size, size_total); -	} - -	/* -	 * Fill xsave->i387.sw_reserved value for ptrace frame: -	 */ -	offset = offsetof(struct fxregs_state, sw_reserved); -	size = sizeof(xstate_fx_sw_bytes); - -	ret = __copy_xstate_to_user(ubuf, xstate_fx_sw_bytes, offset, size, size_total); -	if (ret) -		return ret; - -	return 0; +	fill_gap(&to, &last, size);  }  /* diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index 3f006489087f..5679aa3fdcb8 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c @@ -412,26 +412,12 @@ static unsigned long getreg(struct task_struct *task, unsigned long offset)  static int genregs_get(struct task_struct *target,  		       const struct user_regset *regset, -		       unsigned int pos, unsigned int count, -		       void *kbuf, void __user *ubuf) +		       struct membuf to)  { -	if (kbuf) { -		unsigned long *k = kbuf; -		while (count >= sizeof(*k)) { -			*k++ = getreg(target, pos); -			count -= sizeof(*k); -			pos += sizeof(*k); -		} -	} else { -		unsigned long __user *u = ubuf; -		while (count >= sizeof(*u)) { -			if (__put_user(getreg(target, pos), u++)) -				return -EFAULT; -			count -= sizeof(*u); -			pos += sizeof(*u); -		} -	} +	int reg; +	for (reg = 0; to.left; reg++) +		membuf_store(&to, getreg(target, reg * sizeof(unsigned long)));  	return 0;  } @@ -695,16 +681,14 @@ static int ioperm_active(struct task_struct *target,  static int ioperm_get(struct task_struct *target,  		      const struct user_regset *regset, -		      unsigned int pos, unsigned int count, -		      void *kbuf, void __user *ubuf) +		      struct membuf to)  {  	struct io_bitmap *iobm = target->thread.io_bitmap;  	if (!iobm)  		return -ENXIO; -	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, -				   iobm->bitmap, 0, IO_BITMAP_BYTES); +	return membuf_write(&to, iobm->bitmap, IO_BITMAP_BYTES);  }  /* @@ -1007,28 +991,15 @@ static int getreg32(struct task_struct *child, unsigned regno, u32 *val)  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)  { -	if (kbuf) { -		compat_ulong_t *k = kbuf; -		while (count >= sizeof(*k)) { -			getreg32(target, pos, k++); -			count -= sizeof(*k); -			pos += sizeof(*k); -		} -	} else { -		compat_ulong_t __user *u = ubuf; -		while (count >= sizeof(*u)) { -			compat_ulong_t word; -			getreg32(target, pos, &word); -			if (__put_user(word, u++)) -				return -EFAULT; -			count -= sizeof(*u); -			pos += sizeof(*u); -		} -	} +	int reg; +	for (reg = 0; to.left; reg++) { +		u32 val; +		getreg32(target, reg * 4, &val); +		membuf_store(&to, val); +	}  	return 0;  } @@ -1238,25 +1209,25 @@ static struct user_regset x86_64_regsets[] __ro_after_init = {  		.core_note_type = NT_PRSTATUS,  		.n = sizeof(struct user_regs_struct) / sizeof(long),  		.size = sizeof(long), .align = sizeof(long), -		.get = genregs_get, .set = genregs_set +		.regset_get = genregs_get, .set = genregs_set  	},  	[REGSET_FP] = {  		.core_note_type = NT_PRFPREG,  		.n = sizeof(struct user_i387_struct) / sizeof(long),  		.size = sizeof(long), .align = sizeof(long), -		.active = regset_xregset_fpregs_active, .get = xfpregs_get, .set = xfpregs_set +		.active = regset_xregset_fpregs_active, .regset_get = xfpregs_get, .set = xfpregs_set  	},  	[REGSET_XSTATE] = {  		.core_note_type = NT_X86_XSTATE,  		.size = sizeof(u64), .align = sizeof(u64), -		.active = xstateregs_active, .get = xstateregs_get, +		.active = xstateregs_active, .regset_get = xstateregs_get,  		.set = xstateregs_set  	},  	[REGSET_IOPERM64] = {  		.core_note_type = NT_386_IOPERM,  		.n = IO_BITMAP_LONGS,  		.size = sizeof(long), .align = sizeof(long), -		.active = ioperm_active, .get = ioperm_get +		.active = ioperm_active, .regset_get = ioperm_get  	},  }; @@ -1279,24 +1250,24 @@ static struct user_regset x86_32_regsets[] __ro_after_init = {  		.core_note_type = NT_PRSTATUS,  		.n = sizeof(struct user_regs_struct32) / sizeof(u32),  		.size = sizeof(u32), .align = sizeof(u32), -		.get = genregs32_get, .set = genregs32_set +		.regset_get = genregs32_get, .set = genregs32_set  	},  	[REGSET_FP] = {  		.core_note_type = NT_PRFPREG,  		.n = sizeof(struct user_i387_ia32_struct) / sizeof(u32),  		.size = sizeof(u32), .align = sizeof(u32), -		.active = regset_fpregs_active, .get = fpregs_get, .set = fpregs_set +		.active = regset_fpregs_active, .regset_get = fpregs_get, .set = fpregs_set  	},  	[REGSET_XFP] = {  		.core_note_type = NT_PRXFPREG,  		.n = sizeof(struct user32_fxsr_struct) / sizeof(u32),  		.size = sizeof(u32), .align = sizeof(u32), -		.active = regset_xregset_fpregs_active, .get = xfpregs_get, .set = xfpregs_set +		.active = regset_xregset_fpregs_active, .regset_get = xfpregs_get, .set = xfpregs_set  	},  	[REGSET_XSTATE] = {  		.core_note_type = NT_X86_XSTATE,  		.size = sizeof(u64), .align = sizeof(u64), -		.active = xstateregs_active, .get = xstateregs_get, +		.active = xstateregs_active, .regset_get = xstateregs_get,  		.set = xstateregs_set  	},  	[REGSET_TLS] = { @@ -1305,13 +1276,13 @@ static struct user_regset x86_32_regsets[] __ro_after_init = {  		.size = sizeof(struct user_desc),  		.align = sizeof(struct user_desc),  		.active = regset_tls_active, -		.get = regset_tls_get, .set = regset_tls_set +		.regset_get = regset_tls_get, .set = regset_tls_set  	},  	[REGSET_IOPERM32] = {  		.core_note_type = NT_386_IOPERM,  		.n = IO_BITMAP_BYTES / sizeof(u32),  		.size = sizeof(u32), .align = sizeof(u32), -		.active = ioperm_active, .get = ioperm_get +		.active = ioperm_active, .regset_get = ioperm_get  	},  }; diff --git a/arch/x86/kernel/tls.c b/arch/x86/kernel/tls.c index 71d3fef1edc9..64a496a0687f 100644 --- a/arch/x86/kernel/tls.c +++ b/arch/x86/kernel/tls.c @@ -256,36 +256,16 @@ int regset_tls_active(struct task_struct *target,  }  int regset_tls_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 desc_struct *tls; +	struct user_desc v; +	int pos; -	if (pos >= GDT_ENTRY_TLS_ENTRIES * sizeof(struct user_desc) || -	    (pos % sizeof(struct user_desc)) != 0 || -	    (count % sizeof(struct user_desc)) != 0) -		return -EINVAL; - -	pos /= sizeof(struct user_desc); -	count /= sizeof(struct user_desc); - -	tls = &target->thread.tls_array[pos]; - -	if (kbuf) { -		struct user_desc *info = kbuf; -		while (count-- > 0) -			fill_user_desc(info++, GDT_ENTRY_TLS_MIN + pos++, -				       tls++); -	} else { -		struct user_desc __user *u_info = ubuf; -		while (count-- > 0) { -			struct user_desc info; -			fill_user_desc(&info, GDT_ENTRY_TLS_MIN + pos++, tls++); -			if (__copy_to_user(u_info++, &info, sizeof(info))) -				return -EFAULT; -		} +	for (pos = 0, tls = target->thread.tls_array; to.left; pos++, tls++) { +		fill_user_desc(&v, GDT_ENTRY_TLS_MIN + pos, tls); +		membuf_write(&to, &v, sizeof(v));  	} -  	return 0;  } diff --git a/arch/x86/kernel/tls.h b/arch/x86/kernel/tls.h index 3a76e1d3535e..fc39447a0c1a 100644 --- a/arch/x86/kernel/tls.h +++ b/arch/x86/kernel/tls.h @@ -12,7 +12,7 @@  #include <linux/regset.h>  extern user_regset_active_fn regset_tls_active; -extern user_regset_get_fn regset_tls_get; +extern user_regset_get2_fn regset_tls_get;  extern user_regset_set_fn regset_tls_set;  #endif	/* _ARCH_X86_KERNEL_TLS_H */ diff --git a/arch/x86/math-emu/fpu_entry.c b/arch/x86/math-emu/fpu_entry.c index a873da6b46d6..8679a9d6c47f 100644 --- a/arch/x86/math-emu/fpu_entry.c +++ b/arch/x86/math-emu/fpu_entry.c @@ -689,12 +689,10 @@ int fpregs_soft_set(struct task_struct *target,  int fpregs_soft_get(struct task_struct *target,  		    const struct user_regset *regset, -		    unsigned int pos, unsigned int count, -		    void *kbuf, void __user *ubuf) +		    struct membuf to)  {  	struct swregs_state *s387 = &target->thread.fpu.state.soft;  	const void *space = s387->st_space; -	int ret;  	int offset = (S387->ftop & 7) * 10, other = 80 - offset;  	RE_ENTRANT_CHECK_OFF; @@ -709,18 +707,11 @@ int fpregs_soft_get(struct task_struct *target,  	S387->fos |= 0xffff0000;  #endif /* PECULIAR_486 */ -	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, s387, 0, -				  offsetof(struct swregs_state, st_space)); - -	/* Copy all registers in stack order. */ -	if (!ret) -		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, -					  space + offset, 0, other); -	if (!ret) -		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, -					  space, 0, offset); +	membuf_write(&to, s387, offsetof(struct swregs_state, st_space)); +	membuf_write(&to, space + offset, other); +	membuf_write(&to, space, offset);  	RE_ENTRANT_CHECK_ON; -	return ret; +	return 0;  } diff --git a/arch/xtensa/kernel/ptrace.c b/arch/xtensa/kernel/ptrace.c index ce4a32bd2294..bb3f4797d212 100644 --- a/arch/xtensa/kernel/ptrace.c +++ b/arch/xtensa/kernel/ptrace.c @@ -39,8 +39,7 @@  static int gpr_get(struct task_struct *target,  		   const struct user_regset *regset, -		   unsigned int pos, unsigned int count, -		   void *kbuf, void __user *ubuf) +		   struct membuf to)  {  	struct pt_regs *regs = task_pt_regs(target);  	struct user_pt_regs newregs = { @@ -63,8 +62,7 @@ static int gpr_get(struct task_struct *target,  	       regs->areg,  	       (WSBITS - regs->windowbase) * 16); -	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, -				   &newregs, 0, -1); +	return membuf_write(&to, &newregs, sizeof(newregs));  }  static int gpr_set(struct task_struct *target, @@ -121,8 +119,7 @@ static int gpr_set(struct task_struct *target,  static int tie_get(struct task_struct *target,  		   const struct user_regset *regset, -		   unsigned int pos, unsigned int count, -		   void *kbuf, void __user *ubuf) +		   struct membuf to)  {  	int ret;  	struct pt_regs *regs = task_pt_regs(target); @@ -147,8 +144,7 @@ static int tie_get(struct task_struct *target,  	newregs->cp6 = ti->xtregs_cp.cp6;  	newregs->cp7 = ti->xtregs_cp.cp7;  #endif -	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, -				  newregs, 0, -1); +	ret = membuf_write(&to, newregs, sizeof(*newregs));  	kfree(newregs);  	return ret;  } @@ -203,7 +199,7 @@ static const struct user_regset xtensa_regsets[] = {  		.n = sizeof(struct user_pt_regs) / sizeof(u32),  		.size = sizeof(u32),  		.align = sizeof(u32), -		.get = gpr_get, +		.regset_get = gpr_get,  		.set = gpr_set,  	},  	[REGSET_TIE] = { @@ -211,7 +207,7 @@ static const struct user_regset xtensa_regsets[] = {  		.n = sizeof(elf_xtregs_t) / sizeof(u32),  		.size = sizeof(u32),  		.align = sizeof(u32), -		.get = tie_get, +		.regset_get = tie_get,  		.set = tie_set,  	},  }; diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 9fe3b51c116a..e922a6abdca8 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -1821,7 +1821,7 @@ static int fill_thread_core_info(struct elf_thread_core_info *t,  				 long signr, size_t *total)  {  	unsigned int i; -	unsigned int regset0_size = regset_size(t->task, &view->regsets[0]); +	int regset0_size;  	/*  	 * NT_PRSTATUS is the one special case, because the regset data @@ -1830,8 +1830,10 @@ static int fill_thread_core_info(struct elf_thread_core_info *t,  	 * We assume that regset 0 is NT_PRSTATUS.  	 */  	fill_prstatus(&t->prstatus, t->task, signr); -	(void) view->regsets[0].get(t->task, &view->regsets[0], 0, regset0_size, -				    &t->prstatus.pr_reg, NULL); +	regset0_size = regset_get(t->task, &view->regsets[0], +		   sizeof(t->prstatus.pr_reg), &t->prstatus.pr_reg); +	if (regset0_size < 0) +		return 0;  	fill_note(&t->notes[0], "CORE", NT_PRSTATUS,  		  PRSTATUS_SIZE(t->prstatus, regset0_size), &t->prstatus); @@ -1846,32 +1848,28 @@ static int fill_thread_core_info(struct elf_thread_core_info *t,  	 */  	for (i = 1; i < view->n; ++i) {  		const struct user_regset *regset = &view->regsets[i]; +		int note_type = regset->core_note_type; +		bool is_fpreg = note_type == NT_PRFPREG; +		void *data; +		int ret; +  		do_thread_regset_writeback(t->task, regset); -		if (regset->core_note_type && regset->get && -		    (!regset->active || regset->active(t->task, regset) > 0)) { -			int ret; -			size_t size = regset_size(t->task, regset); -			void *data = kzalloc(size, GFP_KERNEL); -			if (unlikely(!data)) -				return 0; -			ret = regset->get(t->task, regset, -					  0, size, data, NULL); -			if (unlikely(ret)) -				kfree(data); -			else { -				if (regset->core_note_type != NT_PRFPREG) -					fill_note(&t->notes[i], "LINUX", -						  regset->core_note_type, -						  size, data); -				else { -					SET_PR_FPVALID(&t->prstatus, -							1, regset0_size); -					fill_note(&t->notes[i], "CORE", -						  NT_PRFPREG, size, data); -				} -				*total += notesize(&t->notes[i]); -			} -		} +		if (!note_type) // not for coredumps +			continue; +		if (regset->active && regset->active(t->task, regset) <= 0) +			continue; + +		ret = regset_get_alloc(t->task, regset, ~0U, &data); +		if (ret < 0) +			continue; + +		if (is_fpreg) +			SET_PR_FPVALID(&t->prstatus, 1, regset0_size); + +		fill_note(&t->notes[i], is_fpreg ? "CORE" : "LINUX", +			  note_type, ret, data); + +		*total += notesize(&t->notes[i]);  	}  	return 1; diff --git a/include/linux/regset.h b/include/linux/regset.h index 46d6ae68c455..c3403f328257 100644 --- a/include/linux/regset.h +++ b/include/linux/regset.h @@ -17,6 +17,52 @@  struct task_struct;  struct user_regset; +struct membuf { +	void *p; +	size_t left; +}; + +static inline int membuf_zero(struct membuf *s, size_t size) +{ +	if (s->left) { +		if (size > s->left) +			size = s->left; +		memset(s->p, 0, size); +		s->p += size; +		s->left -= size; +	} +	return s->left; +} + +static inline int membuf_write(struct membuf *s, const void *v, size_t size) +{ +	if (s->left) { +		if (size > s->left) +			size = s->left; +		memcpy(s->p, v, size); +		s->p += size; +		s->left -= size; +	} +	return s->left; +} + +/* current s->p must be aligned for v; v must be a scalar */ +#define membuf_store(s, v)				\ +({							\ +	struct membuf *__s = (s);			\ +        if (__s->left) {				\ +		typeof(v) __v = (v);			\ +		size_t __size = sizeof(__v);		\ +		if (unlikely(__size > __s->left)) {	\ +			__size = __s->left;		\ +			memcpy(__s->p, &__v, __size);	\ +		} else {				\ +			*(typeof(__v + 0) *)__s->p = __v;	\ +		}					\ +		__s->p += __size;			\ +		__s->left -= __size;			\ +	}						\ +	__s->left;})  /**   * user_regset_active_fn - type of @active function in &struct user_regset @@ -36,26 +82,9 @@ struct user_regset;  typedef int user_regset_active_fn(struct task_struct *target,  				  const struct user_regset *regset); -/** - * user_regset_get_fn - type of @get function in &struct user_regset - * @target:	thread being examined - * @regset:	regset being examined - * @pos:	offset into the regset data to access, in bytes - * @count:	amount of data to copy, in bytes - * @kbuf:	if not %NULL, a kernel-space pointer to copy into - * @ubuf:	if @kbuf is %NULL, a user-space pointer to copy into - * - * Fetch register values.  Return %0 on success; -%EIO or -%ENODEV - * are usual failure returns.  The @pos and @count values are in - * bytes, but must be properly aligned.  If @kbuf is non-null, that - * buffer is used and @ubuf is ignored.  If @kbuf is %NULL, then - * ubuf gives a userland pointer to access directly, and an -%EFAULT - * return value is possible. - */ -typedef int user_regset_get_fn(struct task_struct *target, +typedef int user_regset_get2_fn(struct task_struct *target,  			       const struct user_regset *regset, -			       unsigned int pos, unsigned int count, -			       void *kbuf, void __user *ubuf); +			       struct membuf to);  /**   * user_regset_set_fn - type of @set function in &struct user_regset @@ -104,28 +133,6 @@ typedef int user_regset_writeback_fn(struct task_struct *target,  				     int immediate);  /** - * user_regset_get_size_fn - type of @get_size function in &struct user_regset - * @target:	thread being examined - * @regset:	regset being examined - * - * This call is optional; usually the pointer is %NULL. - * - * When provided, this function must return the current size of regset - * data, as observed by the @get function in &struct user_regset.  The - * value returned must be a multiple of @size.  The returned size is - * required to be valid only until the next time (if any) @regset is - * modified for @target. - * - * This function is intended for dynamically sized regsets.  A regset - * that is statically sized does not need to implement it. - * - * This function should not be called directly: instead, callers should - * call regset_size() to determine the current size of a regset. - */ -typedef unsigned int user_regset_get_size_fn(struct task_struct *target, -					     const struct user_regset *regset); - -/**   * struct user_regset - accessible thread CPU state   * @n:			Number of slots (registers).   * @size:		Size in bytes of a slot (register). @@ -136,7 +143,6 @@ typedef unsigned int user_regset_get_size_fn(struct task_struct *target,   * @set:		Function to store values.   * @active:		Function to report if regset is active, or %NULL.   * @writeback:		Function to write data back to user memory, or %NULL. - * @get_size:		Function to return the regset's size, or %NULL.   *   * This data structure describes a machine resource we call a register set.   * This is part of the state of an individual thread, not necessarily @@ -144,12 +150,7 @@ typedef unsigned int user_regset_get_size_fn(struct task_struct *target,   * similar slots, given by @n.  Each slot is @size bytes, and aligned to   * @align bytes (which is at least @size).  For dynamically-sized   * regsets, @n must contain the maximum possible number of slots for the - * regset, and @get_size must point to a function that returns the - * current regset size. - * - * Callers that need to know only the current size of the regset and do - * not care about its internal structure should call regset_size() - * instead of inspecting @n or calling @get_size. + * regset.   *   * For backward compatibility, the @get and @set methods must pad to, or   * accept, @n * @size bytes, even if the current regset size is smaller. @@ -185,11 +186,10 @@ typedef unsigned int user_regset_get_size_fn(struct task_struct *target,   * omitted when there is an @active function and it returns zero.   */  struct user_regset { -	user_regset_get_fn		*get; +	user_regset_get2_fn		*regset_get;  	user_regset_set_fn		*set;  	user_regset_active_fn		*active;  	user_regset_writeback_fn	*writeback; -	user_regset_get_size_fn		*get_size;  	unsigned int			n;  	unsigned int 			size;  	unsigned int 			align; @@ -238,44 +238,6 @@ struct user_regset_view {   */  const struct user_regset_view *task_user_regset_view(struct task_struct *tsk); - -/* - * These are helpers for writing regset get/set functions in arch code. - * Because @start_pos and @end_pos are always compile-time constants, - * these are inlined into very little code though they look large. - * - * Use one or more calls sequentially for each chunk of regset data stored - * contiguously in memory.  Call with constants for @start_pos and @end_pos, - * giving the range of byte positions in the regset that data corresponds - * to; @end_pos can be -1 if this chunk is at the end of the regset layout. - * Each call updates the arguments to point past its chunk. - */ - -static inline int user_regset_copyout(unsigned int *pos, unsigned int *count, -				      void **kbuf, -				      void __user **ubuf, const void *data, -				      const int start_pos, const int end_pos) -{ -	if (*count == 0) -		return 0; -	BUG_ON(*pos < start_pos); -	if (end_pos < 0 || *pos < end_pos) { -		unsigned int copy = (end_pos < 0 ? *count -				     : min(*count, end_pos - *pos)); -		data += *pos - start_pos; -		if (*kbuf) { -			memcpy(*kbuf, data, copy); -			*kbuf += copy; -		} else if (__copy_to_user(*ubuf, data, copy)) -			return -EFAULT; -		else -			*ubuf += copy; -		*pos += copy; -		*count -= copy; -	} -	return 0; -} -  static inline int user_regset_copyin(unsigned int *pos, unsigned int *count,  				     const void **kbuf,  				     const void __user **ubuf, void *data, @@ -301,35 +263,6 @@ static inline int user_regset_copyin(unsigned int *pos, unsigned int *count,  	return 0;  } -/* - * These two parallel the two above, but for portions of a regset layout - * that always read as all-zero or for which writes are ignored. - */ -static inline int user_regset_copyout_zero(unsigned int *pos, -					   unsigned int *count, -					   void **kbuf, void __user **ubuf, -					   const int start_pos, -					   const int end_pos) -{ -	if (*count == 0) -		return 0; -	BUG_ON(*pos < start_pos); -	if (end_pos < 0 || *pos < end_pos) { -		unsigned int copy = (end_pos < 0 ? *count -				     : min(*count, end_pos - *pos)); -		if (*kbuf) { -			memset(*kbuf, 0, copy); -			*kbuf += copy; -		} else if (clear_user(*ubuf, copy)) -			return -EFAULT; -		else -			*ubuf += copy; -		*pos += copy; -		*count -= copy; -	} -	return 0; -} -  static inline int user_regset_copyin_ignore(unsigned int *pos,  					    unsigned int *count,  					    const void **kbuf, @@ -353,31 +286,19 @@ static inline int user_regset_copyin_ignore(unsigned int *pos,  	return 0;  } -/** - * copy_regset_to_user - fetch a thread's user_regset data into user memory - * @target:	thread to be examined - * @view:	&struct user_regset_view describing user thread machine state - * @setno:	index in @view->regsets - * @offset:	offset into the regset data, in bytes - * @size:	amount of data to copy, in bytes - * @data:	user-mode pointer to copy into - */ -static inline int copy_regset_to_user(struct task_struct *target, -				      const struct user_regset_view *view, -				      unsigned int setno, -				      unsigned int offset, unsigned int size, -				      void __user *data) -{ -	const struct user_regset *regset = &view->regsets[setno]; - -	if (!regset->get) -		return -EOPNOTSUPP; +extern int regset_get(struct task_struct *target, +		      const struct user_regset *regset, +		      unsigned int size, void *data); -	if (!access_ok(data, size)) -		return -EFAULT; +extern int regset_get_alloc(struct task_struct *target, +			    const struct user_regset *regset, +			    unsigned int size, +			    void **data); -	return regset->get(target, regset, offset, size, NULL, data); -} +extern int copy_regset_to_user(struct task_struct *target, +			       const struct user_regset_view *view, +			       unsigned int setno, unsigned int offset, +			       unsigned int size, void __user *data);  /**   * copy_regset_from_user - store into thread's user_regset data from user memory @@ -405,21 +326,4 @@ static inline int copy_regset_from_user(struct task_struct *target,  	return regset->set(target, regset, offset, size, NULL, data);  } -/** - * regset_size - determine the current size of a regset - * @target:	thread to be examined - * @regset:	regset to be examined - * - * Note that the returned size is valid only until the next time - * (if any) @regset is modified for @target. - */ -static inline unsigned int regset_size(struct task_struct *target, -				       const struct user_regset *regset) -{ -	if (!regset->get_size) -		return regset->n * regset->size; -	else -		return regset->get_size(target, regset); -} -  #endif	/* <linux/regset.h> */ diff --git a/kernel/Makefile b/kernel/Makefile index bdeb77e27042..5350fd292910 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -10,7 +10,7 @@ obj-y     = fork.o exec_domain.o panic.o \  	    extable.o params.o \  	    kthread.o sys_ni.o nsproxy.o \  	    notifier.o ksysfs.o cred.o reboot.o \ -	    async.o range.o smpboot.o ucount.o +	    async.o range.o smpboot.o ucount.o regset.o  obj-$(CONFIG_BPFILTER) += usermode_driver.o  obj-$(CONFIG_MODULES) += kmod.o diff --git a/kernel/regset.c b/kernel/regset.c new file mode 100644 index 000000000000..586823786f39 --- /dev/null +++ b/kernel/regset.c @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include <linux/export.h> +#include <linux/slab.h> +#include <linux/regset.h> + +static int __regset_get(struct task_struct *target, +			const struct user_regset *regset, +			unsigned int size, +			void **data) +{ +	void *p = *data, *to_free = NULL; +	int res; + +	if (!regset->regset_get) +		return -EOPNOTSUPP; +	if (size > regset->n * regset->size) +		size = regset->n * regset->size; +	if (!p) { +		to_free = p = kzalloc(size, GFP_KERNEL); +		if (!p) +			return -ENOMEM; +	} +	res = regset->regset_get(target, regset, +			   (struct membuf){.p = p, .left = size}); +	if (res < 0) { +		kfree(to_free); +		return res; +	} +	*data = p; +	return size - res; +} + +int regset_get(struct task_struct *target, +	       const struct user_regset *regset, +	       unsigned int size, +	       void *data) +{ +	return __regset_get(target, regset, size, &data); +} +EXPORT_SYMBOL(regset_get); + +int regset_get_alloc(struct task_struct *target, +		     const struct user_regset *regset, +		     unsigned int size, +		     void **data) +{ +	*data = NULL; +	return __regset_get(target, regset, size, data); +} +EXPORT_SYMBOL(regset_get_alloc); + +/** + * copy_regset_to_user - fetch a thread's user_regset data into user memory + * @target:	thread to be examined + * @view:	&struct user_regset_view describing user thread machine state + * @setno:	index in @view->regsets + * @offset:	offset into the regset data, in bytes + * @size:	amount of data to copy, in bytes + * @data:	user-mode pointer to copy into + */ +int copy_regset_to_user(struct task_struct *target, +			const struct user_regset_view *view, +			unsigned int setno, +			unsigned int offset, unsigned int size, +			void __user *data) +{ +	const struct user_regset *regset = &view->regsets[setno]; +	void *buf; +	int ret; + +	ret = regset_get_alloc(target, regset, size, &buf); +	if (ret > 0) +		ret = copy_to_user(data, buf, ret) ? -EFAULT : 0; +	kfree(buf); +	return ret; +} | 
