Commit 6a9e25ff authored by Maciej W. Rozycki's avatar Maciej W. Rozycki Committed by Khalid Elmously

MIPS: ptrace: Expose FIR register through FP regset

BugLink: https://bugs.launchpad.net/bugs/1775771

commit 71e909c0 upstream.

Correct commit 7aeb753b ("MIPS: Implement task_user_regset_view.")
and expose the FIR register using the unused 4 bytes at the end of the
NT_PRFPREG regset.  Without that register included clients cannot use
the PTRACE_GETREGSET request to retrieve the complete FPU register set
and have to resort to one of the older interfaces, either PTRACE_PEEKUSR
or PTRACE_GETFPREGS, to retrieve the missing piece of data.  Also the
register is irreversibly missing from core dumps.

This register is architecturally hardwired and read-only so the write
path does not matter.  Ignore data supplied on writes then.

Fixes: 7aeb753b ("MIPS: Implement task_user_regset_view.")
Signed-off-by: default avatarJames Hogan <jhogan@kernel.org>
Signed-off-by: default avatarMaciej W. Rozycki <macro@mips.com>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: linux-mips@linux-mips.org
Cc: <stable@vger.kernel.org> # 3.13+
Patchwork: https://patchwork.linux-mips.org/patch/19273/Signed-off-by: default avatarJames Hogan <jhogan@kernel.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: default avatarJuerg Haefliger <juergh@canonical.com>
Signed-off-by: default avatarKhalid Elmously <khalid.elmously@canonical.com>
parent ae5d16c8
...@@ -483,7 +483,7 @@ static int fpr_get_msa(struct task_struct *target, ...@@ -483,7 +483,7 @@ static int fpr_get_msa(struct task_struct *target,
/* /*
* Copy the floating-point context to the supplied NT_PRFPREG buffer. * Copy the floating-point context to the supplied NT_PRFPREG buffer.
* Choose the appropriate helper for general registers, and then copy * Choose the appropriate helper for general registers, and then copy
* the FCSR register separately. * the FCSR and FIR registers separately.
*/ */
static int fpr_get(struct task_struct *target, static int fpr_get(struct task_struct *target,
const struct user_regset *regset, const struct user_regset *regset,
...@@ -491,6 +491,7 @@ static int fpr_get(struct task_struct *target, ...@@ -491,6 +491,7 @@ static int fpr_get(struct task_struct *target,
void *kbuf, void __user *ubuf) void *kbuf, void __user *ubuf)
{ {
const int fcr31_pos = NUM_FPU_REGS * sizeof(elf_fpreg_t); const int fcr31_pos = NUM_FPU_REGS * sizeof(elf_fpreg_t);
const int fir_pos = fcr31_pos + sizeof(u32);
int err; int err;
if (sizeof(target->thread.fpu.fpr[0]) == sizeof(elf_fpreg_t)) if (sizeof(target->thread.fpu.fpr[0]) == sizeof(elf_fpreg_t))
...@@ -503,6 +504,12 @@ static int fpr_get(struct task_struct *target, ...@@ -503,6 +504,12 @@ static int fpr_get(struct task_struct *target,
err = user_regset_copyout(&pos, &count, &kbuf, &ubuf, err = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
&target->thread.fpu.fcr31, &target->thread.fpu.fcr31,
fcr31_pos, fcr31_pos + sizeof(u32)); fcr31_pos, fcr31_pos + sizeof(u32));
if (err)
return err;
err = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
&boot_cpu_data.fpu_id,
fir_pos, fir_pos + sizeof(u32));
return err; return err;
} }
...@@ -551,7 +558,8 @@ static int fpr_set_msa(struct task_struct *target, ...@@ -551,7 +558,8 @@ static int fpr_set_msa(struct task_struct *target,
/* /*
* Copy the supplied NT_PRFPREG buffer to the floating-point context. * Copy the supplied NT_PRFPREG buffer to the floating-point context.
* Choose the appropriate helper for general registers, and then copy * Choose the appropriate helper for general registers, and then copy
* the FCSR register separately. * the FCSR register separately. Ignore the incoming FIR register
* contents though, as the register is read-only.
* *
* We optimize for the case where `count % sizeof(elf_fpreg_t) == 0', * We optimize for the case where `count % sizeof(elf_fpreg_t) == 0',
* which is supposed to have been guaranteed by the kernel before * which is supposed to have been guaranteed by the kernel before
...@@ -565,6 +573,7 @@ static int fpr_set(struct task_struct *target, ...@@ -565,6 +573,7 @@ static int fpr_set(struct task_struct *target,
const void *kbuf, const void __user *ubuf) const void *kbuf, const void __user *ubuf)
{ {
const int fcr31_pos = NUM_FPU_REGS * sizeof(elf_fpreg_t); const int fcr31_pos = NUM_FPU_REGS * sizeof(elf_fpreg_t);
const int fir_pos = fcr31_pos + sizeof(u32);
u32 fcr31; u32 fcr31;
int err; int err;
...@@ -592,6 +601,11 @@ static int fpr_set(struct task_struct *target, ...@@ -592,6 +601,11 @@ static int fpr_set(struct task_struct *target,
ptrace_setfcr31(target, fcr31); ptrace_setfcr31(target, fcr31);
} }
if (count > 0)
err = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
fir_pos,
fir_pos + sizeof(u32));
return err; return err;
} }
......
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