Commit b26b2b24 authored by Linus Torvalds's avatar Linus Torvalds

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
...@@ -94,14 +94,14 @@ int main(void) ...@@ -94,14 +94,14 @@ int main(void)
DEFINE(THREAD_SP, offsetof (struct task_struct, thread.sp)); DEFINE(THREAD_SP, offsetof (struct task_struct, thread.sp));
DEFINE(THREAD_CPENABLE, offsetof (struct thread_info, cpenable)); DEFINE(THREAD_CPENABLE, offsetof (struct thread_info, cpenable));
#if XTENSA_HAVE_COPROCESSORS #if XTENSA_HAVE_COPROCESSORS
DEFINE(THREAD_XTREGS_CP0, 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)); DEFINE(THREAD_XTREGS_CP1, offsetof(struct thread_info, xtregs_cp.cp1));
DEFINE(THREAD_XTREGS_CP2, offsetof (struct thread_info, xtregs_cp)); DEFINE(THREAD_XTREGS_CP2, offsetof(struct thread_info, xtregs_cp.cp2));
DEFINE(THREAD_XTREGS_CP3, offsetof (struct thread_info, xtregs_cp)); DEFINE(THREAD_XTREGS_CP3, offsetof(struct thread_info, xtregs_cp.cp3));
DEFINE(THREAD_XTREGS_CP4, offsetof (struct thread_info, xtregs_cp)); DEFINE(THREAD_XTREGS_CP4, offsetof(struct thread_info, xtregs_cp.cp4));
DEFINE(THREAD_XTREGS_CP5, offsetof (struct thread_info, xtregs_cp)); DEFINE(THREAD_XTREGS_CP5, offsetof(struct thread_info, xtregs_cp.cp5));
DEFINE(THREAD_XTREGS_CP6, offsetof (struct thread_info, xtregs_cp)); DEFINE(THREAD_XTREGS_CP6, offsetof(struct thread_info, xtregs_cp.cp6));
DEFINE(THREAD_XTREGS_CP7, offsetof (struct thread_info, xtregs_cp)); DEFINE(THREAD_XTREGS_CP7, offsetof(struct thread_info, xtregs_cp.cp7));
#endif #endif
DEFINE(THREAD_XTREGS_USER, offsetof (struct thread_info, xtregs_user)); DEFINE(THREAD_XTREGS_USER, offsetof (struct thread_info, xtregs_user));
DEFINE(XTREGS_USER_SIZE, sizeof(xtregs_user_t)); DEFINE(XTREGS_USER_SIZE, sizeof(xtregs_user_t));
......
...@@ -94,18 +94,21 @@ void coprocessor_release_all(struct thread_info *ti) ...@@ -94,18 +94,21 @@ void coprocessor_release_all(struct thread_info *ti)
void coprocessor_flush_all(struct thread_info *ti) void coprocessor_flush_all(struct thread_info *ti)
{ {
unsigned long cpenable; unsigned long cpenable, old_cpenable;
int i; int i;
preempt_disable(); preempt_disable();
RSR_CPENABLE(old_cpenable);
cpenable = ti->cpenable; cpenable = ti->cpenable;
WSR_CPENABLE(cpenable);
for (i = 0; i < XCHAL_CP_MAX; i++) { for (i = 0; i < XCHAL_CP_MAX; i++) {
if ((cpenable & 1) != 0 && coprocessor_owner[i] == ti) if ((cpenable & 1) != 0 && coprocessor_owner[i] == ti)
coprocessor_flush(ti, i); coprocessor_flush(ti, i);
cpenable >>= 1; cpenable >>= 1;
} }
WSR_CPENABLE(old_cpenable);
preempt_enable(); preempt_enable();
} }
......
...@@ -127,12 +127,37 @@ static int ptrace_setregs(struct task_struct *child, void __user *uregs) ...@@ -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) static int ptrace_getxregs(struct task_struct *child, void __user *uregs)
{ {
struct pt_regs *regs = task_pt_regs(child); struct pt_regs *regs = task_pt_regs(child);
struct thread_info *ti = task_thread_info(child); struct thread_info *ti = task_thread_info(child);
elf_xtregs_t __user *xtregs = uregs; elf_xtregs_t __user *xtregs = uregs;
int ret = 0; int ret = 0;
int i __maybe_unused;
if (!access_ok(VERIFY_WRITE, uregs, sizeof(elf_xtregs_t))) if (!access_ok(VERIFY_WRITE, uregs, sizeof(elf_xtregs_t)))
return -EIO; return -EIO;
...@@ -140,8 +165,13 @@ static int ptrace_getxregs(struct task_struct *child, void __user *uregs) ...@@ -140,8 +165,13 @@ static int ptrace_getxregs(struct task_struct *child, void __user *uregs)
#if XTENSA_HAVE_COPROCESSORS #if XTENSA_HAVE_COPROCESSORS
/* Flush all coprocessor registers to memory. */ /* Flush all coprocessor registers to memory. */
coprocessor_flush_all(ti); 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 #endif
ret |= __copy_to_user(&xtregs->opt, &regs->xtregs_opt, ret |= __copy_to_user(&xtregs->opt, &regs->xtregs_opt,
sizeof(xtregs->opt)); sizeof(xtregs->opt));
...@@ -157,6 +187,7 @@ static int ptrace_setxregs(struct task_struct *child, void __user *uregs) ...@@ -157,6 +187,7 @@ static int ptrace_setxregs(struct task_struct *child, void __user *uregs)
struct pt_regs *regs = task_pt_regs(child); struct pt_regs *regs = task_pt_regs(child);
elf_xtregs_t *xtregs = uregs; elf_xtregs_t *xtregs = uregs;
int ret = 0; int ret = 0;
int i __maybe_unused;
if (!access_ok(VERIFY_READ, uregs, sizeof(elf_xtregs_t))) if (!access_ok(VERIFY_READ, uregs, sizeof(elf_xtregs_t)))
return -EFAULT; return -EFAULT;
...@@ -166,8 +197,11 @@ static int ptrace_setxregs(struct task_struct *child, void __user *uregs) ...@@ -166,8 +197,11 @@ static int ptrace_setxregs(struct task_struct *child, void __user *uregs)
coprocessor_flush_all(ti); coprocessor_flush_all(ti);
coprocessor_release_all(ti); coprocessor_release_all(ti);
ret |= __copy_from_user(&ti->xtregs_cp, &xtregs->cp0, for (i = 0; i < ARRAY_SIZE(cp_offsets); ++i)
sizeof(xtregs_coprocessor_t)); 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 #endif
ret |= __copy_from_user(&regs->xtregs_opt, &xtregs->opt, ret |= __copy_from_user(&regs->xtregs_opt, &xtregs->opt,
sizeof(xtregs->opt)); sizeof(xtregs->opt));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment