Commit b26b2b24 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'xtensa-20181128' of git://github.com/jcmvbkbc/linux-xtensa

Pull Xtensa fixes from Max Filippov:

 - fix kernel exception on userspace access to a currently disabled
   coprocessor

 - fix coprocessor data saving/restoring in configurations with multiple
   coprocessors

 - fix ptrace access to coprocessor data on configurations with multiple
   coprocessors with high alignment requirements

* tag 'xtensa-20181128' of git://github.com/jcmvbkbc/linux-xtensa:
  xtensa: fix coprocessor part of ptrace_{get,set}xregs
  xtensa: fix coprocessor context offset definitions
  xtensa: enable coprocessors that are being flushed
parents 121b018f 38a35a78
Loading
Loading
Loading
Loading
+8 −8
Original line number Diff line number Diff line
@@ -94,14 +94,14 @@ int main(void)
	DEFINE(THREAD_SP, offsetof (struct task_struct, thread.sp));
	DEFINE(THREAD_CPENABLE, offsetof (struct thread_info, cpenable));
#if XTENSA_HAVE_COPROCESSORS
	DEFINE(THREAD_XTREGS_CP0, offsetof (struct thread_info, xtregs_cp));
	DEFINE(THREAD_XTREGS_CP1, offsetof (struct thread_info, xtregs_cp));
	DEFINE(THREAD_XTREGS_CP2, offsetof (struct thread_info, xtregs_cp));
	DEFINE(THREAD_XTREGS_CP3, offsetof (struct thread_info, xtregs_cp));
	DEFINE(THREAD_XTREGS_CP4, offsetof (struct thread_info, xtregs_cp));
	DEFINE(THREAD_XTREGS_CP5, offsetof (struct thread_info, xtregs_cp));
	DEFINE(THREAD_XTREGS_CP6, offsetof (struct thread_info, xtregs_cp));
	DEFINE(THREAD_XTREGS_CP7, offsetof (struct thread_info, xtregs_cp));
	DEFINE(THREAD_XTREGS_CP0, offsetof(struct thread_info, xtregs_cp.cp0));
	DEFINE(THREAD_XTREGS_CP1, offsetof(struct thread_info, xtregs_cp.cp1));
	DEFINE(THREAD_XTREGS_CP2, offsetof(struct thread_info, xtregs_cp.cp2));
	DEFINE(THREAD_XTREGS_CP3, offsetof(struct thread_info, xtregs_cp.cp3));
	DEFINE(THREAD_XTREGS_CP4, offsetof(struct thread_info, xtregs_cp.cp4));
	DEFINE(THREAD_XTREGS_CP5, offsetof(struct thread_info, xtregs_cp.cp5));
	DEFINE(THREAD_XTREGS_CP6, offsetof(struct thread_info, xtregs_cp.cp6));
	DEFINE(THREAD_XTREGS_CP7, offsetof(struct thread_info, xtregs_cp.cp7));
#endif
	DEFINE(THREAD_XTREGS_USER, offsetof (struct thread_info, xtregs_user));
	DEFINE(XTREGS_USER_SIZE, sizeof(xtregs_user_t));
+4 −1
Original line number Diff line number Diff line
@@ -94,18 +94,21 @@ void coprocessor_release_all(struct thread_info *ti)

void coprocessor_flush_all(struct thread_info *ti)
{
	unsigned long cpenable;
	unsigned long cpenable, old_cpenable;
	int i;

	preempt_disable();

	RSR_CPENABLE(old_cpenable);
	cpenable = ti->cpenable;
	WSR_CPENABLE(cpenable);

	for (i = 0; i < XCHAL_CP_MAX; i++) {
		if ((cpenable & 1) != 0 && coprocessor_owner[i] == ti)
			coprocessor_flush(ti, i);
		cpenable >>= 1;
	}
	WSR_CPENABLE(old_cpenable);

	preempt_enable();
}
+38 −4
Original line number Diff line number Diff line
@@ -127,12 +127,37 @@ static int ptrace_setregs(struct task_struct *child, void __user *uregs)
}


#if XTENSA_HAVE_COPROCESSORS
#define CP_OFFSETS(cp) \
	{ \
		.elf_xtregs_offset = offsetof(elf_xtregs_t, cp), \
		.ti_offset = offsetof(struct thread_info, xtregs_cp.cp), \
		.sz = sizeof(xtregs_ ## cp ## _t), \
	}

static const struct {
	size_t elf_xtregs_offset;
	size_t ti_offset;
	size_t sz;
} cp_offsets[] = {
	CP_OFFSETS(cp0),
	CP_OFFSETS(cp1),
	CP_OFFSETS(cp2),
	CP_OFFSETS(cp3),
	CP_OFFSETS(cp4),
	CP_OFFSETS(cp5),
	CP_OFFSETS(cp6),
	CP_OFFSETS(cp7),
};
#endif

static int ptrace_getxregs(struct task_struct *child, void __user *uregs)
{
	struct pt_regs *regs = task_pt_regs(child);
	struct thread_info *ti = task_thread_info(child);
	elf_xtregs_t __user *xtregs = uregs;
	int ret = 0;
	int i __maybe_unused;

	if (!access_ok(VERIFY_WRITE, uregs, sizeof(elf_xtregs_t)))
		return -EIO;
@@ -140,8 +165,13 @@ static int ptrace_getxregs(struct task_struct *child, void __user *uregs)
#if XTENSA_HAVE_COPROCESSORS
	/* Flush all coprocessor registers to memory. */
	coprocessor_flush_all(ti);
	ret |= __copy_to_user(&xtregs->cp0, &ti->xtregs_cp,
			      sizeof(xtregs_coprocessor_t));

	for (i = 0; i < ARRAY_SIZE(cp_offsets); ++i)
		ret |= __copy_to_user((char __user *)xtregs +
				      cp_offsets[i].elf_xtregs_offset,
				      (const char *)ti +
				      cp_offsets[i].ti_offset,
				      cp_offsets[i].sz);
#endif
	ret |= __copy_to_user(&xtregs->opt, &regs->xtregs_opt,
			      sizeof(xtregs->opt));
@@ -157,6 +187,7 @@ static int ptrace_setxregs(struct task_struct *child, void __user *uregs)
	struct pt_regs *regs = task_pt_regs(child);
	elf_xtregs_t *xtregs = uregs;
	int ret = 0;
	int i __maybe_unused;

	if (!access_ok(VERIFY_READ, uregs, sizeof(elf_xtregs_t)))
		return -EFAULT;
@@ -166,8 +197,11 @@ static int ptrace_setxregs(struct task_struct *child, void __user *uregs)
	coprocessor_flush_all(ti);
	coprocessor_release_all(ti);

	ret |= __copy_from_user(&ti->xtregs_cp, &xtregs->cp0,
				sizeof(xtregs_coprocessor_t));
	for (i = 0; i < ARRAY_SIZE(cp_offsets); ++i)
		ret |= __copy_from_user((char *)ti + cp_offsets[i].ti_offset,
					(const char __user *)xtregs +
					cp_offsets[i].elf_xtregs_offset,
					cp_offsets[i].sz);
#endif
	ret |= __copy_from_user(&regs->xtregs_opt, &xtregs->opt,
				sizeof(xtregs->opt));