Commit b7e46c52 authored by Al Viro's avatar Al Viro
Browse files

sparc64: get rid of odd callers of copy_regset_from_user()



Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 98a7fbf3
Loading
Loading
Loading
Loading
+144 −33
Original line number Diff line number Diff line
@@ -541,6 +541,60 @@ static int getregs64_get(struct task_struct *target,
	return ret;
}

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,
				 &regs->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
@@ -549,7 +603,8 @@ static const struct user_regset ptrace64_regsets[] = {
	 *      TSTATE, TPC, TNPC, Y
	 */
	[REGSET_GENERAL] = {
		.n = 20, .size = sizeof(u64), .get = getregs64_get,
		.n = 20, .size = sizeof(u64),
		.get = getregs64_get, .set = setregs64_set,
	},
};

@@ -914,6 +969,40 @@ static int getregs_get(struct task_struct *target,
				   0, 19 * 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 = 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,
			unsigned int pos, unsigned int count,
@@ -948,12 +1037,52 @@ static int getfpregs_get(struct task_struct *target,
	return ret;
}

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), .get = getregs_get,
		.n = 19, .size = sizeof(u32),
		.get = getregs_get, .set = setregs_set,
	},
	[REGSET_FP] = {
		.n = 68, .size = sizeof(u32), .get = getfpregs_get,
		.n = 68, .size = sizeof(u32),
		.get = getfpregs_get, .set = setfpregs_set,
	},
};

@@ -992,7 +1121,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;
@@ -1017,15 +1145,10 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
		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:
@@ -1036,15 +1159,10 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
		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,
		ret = copy_regset_from_user(child, &ptrace32_view,
					  REGSET_FP, 0,
					  33 * sizeof(u32),
						    1 * sizeof(u32),
						    &fps->fsr);
					  fps);
		break;

	case PTRACE_READTEXT:
@@ -1110,17 +1228,10 @@ long arch_ptrace(struct task_struct *child, long request,
		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: