Пример #1
0
/*
 * Copy the thread state to a regset that can be interpreted by userspace.
 *
 * It doesn't matter what our internal pt_regs structure looks like.  The
 * important thing is that we export a consistent view of the thread state
 * to userspace.  As such, we need to make sure that the regset remains
 * ABI compatible as defined by the struct user_regs_struct:
 *
 * (Each item is a 32-bit word)
 * r0 = 0 (exported for clarity)
 * 31 GPRS r1-r31
 * PC (Program counter)
 * SR (Supervision register)
 */
static int genregs_get(struct task_struct *target,
		       const struct user_regset *regset,
		       unsigned int pos, unsigned int count,
		       void *kbuf, void __user * ubuf)
{
	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,
				  &regs->pc, 4*32, 4*33);
	if (!ret)
		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
					  &regs->sr, 4*33, 4*34);
	if (!ret)
		ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
					       4*34, -1);

	return ret;
}
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)
{
	unsigned int note_type = regset->core_note_type;
	int ret, idx = 0, offset, limit;
	u32 info, ctrl;
	u64 addr;

	/* Resource info */
	ret = ptrace_hbp_get_resource_info(note_type, &info);
	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;

	/* (address, ctrl) registers */
	offset = offsetof(struct user_hwdebug_state, dbg_regs);
	limit = regset->n * regset->size;
	while (count && offset < limit) {
		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;
		idx++;
	}

	return 0;
}
Пример #3
0
/*
 * VFP register get/set implementations.
 *
 * With respect to the kernel, struct user_fp is divided into three chunks:
 * 16 or 32 real VFP registers (d0-d15 or d0-31)
 *	These are transferred to/from the real registers in the task's
 *	vfp_hard_struct.  The number of registers depends on the kernel
 *	configuration.
 *
 * 16 or 0 fake VFP registers (d16-d31 or empty)
 *	i.e., the user_vfp structure has space for 32 registers even if
 *	the kernel doesn't have them all.
 *
 *	vfp_get() reads this chunk as zero where applicable
 *	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)
{
	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));
}
Пример #4
0
int metag_gp_regs_copyout(const struct pt_regs *regs,
			  unsigned int pos, unsigned int count,
			  void *kbuf, void __user *ubuf)
{
	const void *ptr;
	unsigned long data;
	int ret;

	/* D{0-1}.{0-7} */
	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
				  regs->ctx.DX, 0, 4*16);
	if (ret)
		goto out;
	/* A{0-1}.{0-1} */
	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
				  regs->ctx.AX, 4*16, 4*20);
	if (ret)
		goto out;
	/* A{0-1}.2 */
	if (regs->ctx.SaveMask & TBICTX_XEXT_BIT)
		ptr = regs->ctx.Ext.Ctx.pExt;
	else
		ptr = &regs->ctx.Ext.AX2;
	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
				  ptr, 4*20, 4*22);
	if (ret)
		goto out;
	/* A{0-1}.3 */
	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
				  &regs->ctx.AX3, 4*22, 4*24);
	if (ret)
		goto out;
	/* PC */
	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
				  &regs->ctx.CurrPC, 4*24, 4*25);
	if (ret)
		goto out;
	/* TXSTATUS */
	data = (unsigned long)regs->ctx.Flags;
	if (regs->ctx.SaveMask & TBICTX_CBUF_BIT)
		data |= USER_GP_REGS_STATUS_CATCH_BIT;
	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
				  &data, 4*25, 4*26);
	if (ret)
		goto out;
	/* TXRPT, TXBPOBITS, TXMODE */
	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
				  &regs->ctx.CurrRPT, 4*26, 4*29);
	if (ret)
		goto out;
	/* Padding */
	ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
				       4*29, 4*30);
out:
	return ret;
}
static int fpregs32_get(struct task_struct *target,
			const struct user_regset *regset,
			unsigned int pos, unsigned int count,
			void *kbuf, void __user *ubuf)
{
	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;
}
Пример #6
0
int metag_rp_state_copyout(const struct pt_regs *regs,
			   unsigned int pos, unsigned int count,
			   void *kbuf, void __user *ubuf)
{
	unsigned long mask;
	u64 *ptr;
	int ret, i;

	/* Empty read pipeline */
	if (!(regs->ctx.SaveMask & TBICTX_CBRP_BIT)) {
		ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
					       0, 4*13);
		goto out;
	}

	mask = (regs->ctx.CurrDIVTIME & TXDIVTIME_RPMASK_BITS) >>
		TXDIVTIME_RPMASK_S;

	/* Read pipeline entries */
	ptr = (void *)&regs->extcb0[1];
	for (i = 0; i < 6; ++i, ++ptr) {
		if (mask & (1 << i))
			ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
						  ptr, 8*i, 8*(i + 1));
		else
			ret = user_regset_copyout_zero(&pos, &count, &kbuf,
						       &ubuf, 8*i, 8*(i + 1));
		if (ret)
			goto out;
	}
	/* Mask of entries */
	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
				  &mask, 4*12, 4*13);
out:
	return ret;
}
Пример #7
0
int metag_cb_regs_copyout(const struct pt_regs *regs,
			  unsigned int pos, unsigned int count,
			  void *kbuf, void __user *ubuf)
{
	int ret;

	/* TXCATCH{0-3} */
	if (regs->ctx.SaveMask & TBICTX_XCBF_BIT)
		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
					  regs->extcb0, 0, 4*4);
	else
		ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
					       0, 4*4);
	return ret;
}
Пример #8
0
/*
 * retrieve the contents of MN10300 userspace FPU registers
 */
static int fpuregs_get(struct task_struct *target,
		       const struct user_regset *regset,
		       unsigned int pos, unsigned int count,
		       void *kbuf, void __user *ubuf)
{
	const struct fpu_state_struct *fpregs = &target->thread.fpu_state;
	int ret;

	unlazy_fpu(target);

	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
				  fpregs, 0, sizeof(*fpregs));
	if (ret < 0)
		return ret;

	return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
					sizeof(*fpregs), -1);
}
Пример #9
0
/*
 * retrieve the contents of Blackfin userspace general registers
 */
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 pt_regs *regs = task_pt_regs(target);
	int ret;

	/* This sucks ... */
	regs->usp = target->thread.usp;

	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
				  regs, 0, sizeof(*regs));
	if (ret < 0)
		return ret;

	return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
					sizeof(*regs), -1);
}
Пример #10
0
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 i;
	int err;
	u64 fpr_val;

	if (sizeof(target->thread.fpu.fpr[i]) == sizeof(elf_fpreg_t)) {
		err = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
					  &target->thread.fpu.fpr,
					  0, NUM_FPU_REGS * sizeof(elf_fpreg_t));
		if (err)
			return err;
	} else {
		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;
		}
	}

	err = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
			   &target->thread.fpu.fcr31,
			   NUM_FPU_REGS * sizeof(elf_fpreg_t),
			   (NUM_FPU_REGS * sizeof(elf_fpreg_t)) + sizeof(u32));
	if (err)
		return err;

	/* Zero fill the remaining 4 bytes. */
	return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
			    (NUM_FPU_REGS * sizeof(elf_fpreg_t)) + sizeof(u32),
			    sizeof(elf_fpregset_t));
}
Пример #11
0
/*
 * retrieve the contents of MN10300 userspace general registers
 */
static int genregs_get(struct task_struct *target,
		       const struct user_regset *regset,
		       unsigned int pos, unsigned int count,
		       void *kbuf, void __user *ubuf)
{
	const struct pt_regs *regs = task_pt_regs(target);
	int ret;

	/* we need to skip regs->next */
	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
				  regs, 0, PT_ORIG_D0 * sizeof(long));
	if (ret < 0)
		return ret;

	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
				  &regs->orig_d0, PT_ORIG_D0 * sizeof(long),
				  NR_PTREGS * sizeof(long));
	if (ret < 0)
		return ret;

	return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
					NR_PTREGS * sizeof(long), -1);
}
static int genregs32_get(struct task_struct *target,
			 const struct user_regset *regset,
			 unsigned int pos, unsigned int count,
			 void *kbuf, void __user *ubuf)
{
	const struct pt_regs *regs = target->thread.kregs;
	unsigned long __user *reg_window;
	unsigned long *k = kbuf;
	unsigned long __user *u = ubuf;
	unsigned long reg;

	if (target == current)
		flush_user_windows();

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

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

		reg_window = (unsigned long __user *) regs->u_regs[UREG_I6];
		reg_window -= 16;
		for (; count > 0 && pos < 32; count--) {
			if (get_user(*k++, &reg_window[pos++]))
				return -EFAULT;
		}
	} else {
		for (; count > 0 && pos < 16; count--) {
			if (put_user(regs->u_regs[pos++], u++))
				return -EFAULT;
		}

		reg_window = (unsigned long __user *) regs->u_regs[UREG_I6];
		reg_window -= 16;
		for (; count > 0 && pos < 32; count--) {
			if (get_user(reg, &reg_window[pos++]) ||
			    put_user(reg, u++))
				return -EFAULT;
		}
	}
	while (count > 0) {
		switch (pos) {
		case 32: /* PSR */
			reg = regs->psr;
			break;
		case 33: /* PC */
			reg = regs->pc;
			break;
		case 34: /* NPC */
			reg = regs->npc;
			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);
}