static int genregs32_set()

in kernel/ptrace_64.c [561:676]


static int genregs32_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);
	compat_ulong_t __user *reg_window;
	const compat_ulong_t *k = kbuf;
	const compat_ulong_t __user *u = ubuf;
	compat_ulong_t reg;

	if (target == current)
		flushw_user();

	pos /= sizeof(reg);
	count /= sizeof(reg);

	if (kbuf) {
		for (; count > 0 && pos < 16; count--)
			regs->u_regs[pos++] = *k++;

		reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6];
		reg_window -= 16;
		if (target == current) {
			for (; count > 0 && pos < 32; count--) {
				if (put_user(*k++, &reg_window[pos++]))
					return -EFAULT;
			}
		} else {
			for (; count > 0 && pos < 32; count--) {
				if (access_process_vm(target,
						      (unsigned long)
						      &reg_window[pos],
						      (void *) k,
						      sizeof(*k),
						      FOLL_FORCE | FOLL_WRITE)
				    != sizeof(*k))
					return -EFAULT;
				k++;
				pos++;
			}
		}
	} else {
		for (; count > 0 && pos < 16; count--) {
			if (get_user(reg, u++))
				return -EFAULT;
			regs->u_regs[pos++] = reg;
		}

		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, u++) ||
				    put_user(reg, &reg_window[pos++]))
					return -EFAULT;
			}
		} else {
			for (; count > 0 && pos < 32; count--) {
				if (get_user(reg, u++))
					return -EFAULT;
				if (access_process_vm(target,
						      (unsigned long)
						      &reg_window[pos],
						      &reg, sizeof(reg),
						      FOLL_FORCE | FOLL_WRITE)
				    != sizeof(reg))
					return -EFAULT;
				pos++;
				u++;
			}
		}
	}
	while (count > 0) {
		unsigned long tstate;

		if (kbuf)
			reg = *k++;
		else if (get_user(reg, u++))
			return -EFAULT;

		switch (pos) {
		case 32: /* PSR */
			tstate = regs->tstate;
			tstate &= ~(TSTATE_ICC | TSTATE_XCC | TSTATE_SYSCALL);
			tstate |= psr_to_tstate_icc(reg);
			if (reg & PSR_SYSCALL)
				tstate |= TSTATE_SYSCALL;
			regs->tstate = tstate;
			break;
		case 33: /* PC */
			regs->tpc = reg;
			break;
		case 34: /* NPC */
			regs->tnpc = reg;
			break;
		case 35: /* Y */
			regs->y = reg;
			break;
		case 36: /* WIM */
		case 37: /* TBR */
			break;
		default:
			goto finish;
		}

		pos++;
		count--;
	}
finish:
	pos *= sizeof(reg);
	count *= sizeof(reg);

	return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
					 38 * sizeof(reg), -1);
}