Commit 4ff8a356 authored by Al Viro's avatar Al Viro
Browse files

ia64: switch to ->regset_get()



Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 5a806e0a
Loading
Loading
Loading
Loading
+58 −91
Original line number Diff line number Diff line
@@ -1489,9 +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 regset_getset *dst = arg;
	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;
@@ -1509,35 +1517,13 @@ 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)
			return;
	}

	while (dst->count && dst->pos < ELF_AR_END_OFFSET) {
		unsigned int n, from, to;
		elf_greg_t tmp[16];

		from = dst->pos;
		to = from + min(dst->count, (unsigned)sizeof(tmp));
		if (to > ELF_AR_END_OFFSET)
			to = ELF_AR_END_OFFSET;
		for (n = 0; from < to; from += sizeof(elf_greg_t), n++) {
			if (access_elf_reg(dst->target, info, from,
						&tmp[n], 0) < 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, &reg, 0) < 0) {
			dst->ret = -EIO;
			return;
		}
		}
		dst->ret = user_regset_copyout(&dst->pos, &dst->count,
				&dst->u.get.kbuf, &dst->u.get.ubuf, tmp,
				dst->pos, to);
		if (dst->ret)
			return;
		membuf_store(&to, reg);
	}
}

@@ -1588,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])) {
	for (n = 2; to.left && n < 32; n++) {
		if (unw_get_fr(info, n, &reg)) {
			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)
			return;
		membuf_write(&to, &reg, sizeof(reg));
	}

	/* fph */
	if (dst->count > 0) {
		ia64_flush_fph(dst->target);
	if (!to.left)
		return;

	ia64_flush_fph(task);
	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);
		membuf_write(&to, &task->thread.fph, 96 * sizeof(reg));
	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);
	}
		membuf_zero(&to, 96 * sizeof(reg));
}

void do_fpregs_set(struct unw_frame_info *info, void *arg)
@@ -1717,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,
@@ -1728,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,
@@ -1790,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,
@@ -2033,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
	},
};