aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMaciej W. Rozycki <macro@mips.com>2017-12-11 17:54:33 -0500
committerRalf Baechle <ralf@linux-mips.org>2017-12-12 13:13:12 -0500
commitbe07a6a1188372b6d19a3307ec33211fc9c9439d (patch)
tree49c806ac83e7ea5b44f5f69dd23d35e0b276cd0e
parent80b3ffce0196ea50068885d085ff981e4b8396f4 (diff)
MIPS: Fix an FCSR access API regression with NT_PRFPREG and MSA
Fix a commit 72b22bbad1e7 ("MIPS: Don't assume 64-bit FP registers for FP regset") public API regression, then activated by commit 1db1af84d6df ("MIPS: Basic MSA context switching support"), that caused the FCSR register not to be read or written for CONFIG_CPU_HAS_MSA kernel configurations (regardless of actual presence or absence of the MSA feature in a given processor) with ptrace(2) PTRACE_GETREGSET and PTRACE_SETREGSET requests nor recorded in core dumps. This is because with !CONFIG_CPU_HAS_MSA configurations the whole of `elf_fpregset_t' array is bulk-copied as it is, which includes the FCSR in one half of the last, 33rd slot, whereas with CONFIG_CPU_HAS_MSA configurations array elements are copied individually, and then only the leading 32 FGR slots while the remaining slot is ignored. Correct the code then such that only FGR slots are copied in the respective !MSA and MSA helpers an then the FCSR slot is handled separately in common code. Use `ptrace_setfcr31' to update the FCSR too, so that the read-only mask is respected. Retrieving a correct value of FCSR is important in debugging not only for the human to be able to get the right interpretation of the situation, but for correct operation of GDB as well. This is because the condition code bits in FSCR are used by GDB to determine the location to place a breakpoint at when single-stepping through an FPU branch instruction. If such a breakpoint is placed incorrectly (i.e. with the condition reversed), then it will be missed, likely causing the debuggee to run away from the control of GDB and consequently breaking the process of investigation. Fortunately GDB continues using the older PTRACE_GETFPREGS ptrace(2) request which is unaffected, so the regression only really hits with post-mortem debug sessions using a core dump file, in which case execution, and consequently single-stepping through branches is not possible. Of course core files created by buggy kernels out there will have the value of FCSR recorded clobbered, but such core files cannot be corrected and the person using them simply will have to be aware that the value of FCSR retrieved is not reliable. Which also means we can likely get away without defining a replacement API which would ensure a correct value of FSCR to be retrieved, or none at all. This is based on previous work by Alex Smith, extensively rewritten. Signed-off-by: Alex Smith <alex@alex-smith.me.uk> Signed-off-by: James Hogan <james.hogan@mips.com> Signed-off-by: Maciej W. Rozycki <macro@mips.com> Fixes: 72b22bbad1e7 ("MIPS: Don't assume 64-bit FP registers for FP regset") Cc: Paul Burton <Paul.Burton@mips.com> Cc: Dave Martin <Dave.Martin@arm.com> Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Cc: stable@vger.kernel.org # v3.15+ Patchwork: https://patchwork.linux-mips.org/patch/17928/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
-rw-r--r--arch/mips/kernel/ptrace.c47
1 files changed, 36 insertions, 11 deletions
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index 47a01d5f26ea..0a939593ccb7 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -422,7 +422,7 @@ static int gpr64_set(struct task_struct *target,
422/* 422/*
423 * Copy the floating-point context to the supplied NT_PRFPREG buffer, 423 * Copy the floating-point context to the supplied NT_PRFPREG buffer,
424 * !CONFIG_CPU_HAS_MSA variant. FP context's general register slots 424 * !CONFIG_CPU_HAS_MSA variant. FP context's general register slots
425 * correspond 1:1 to buffer slots. 425 * correspond 1:1 to buffer slots. Only general registers are copied.
426 */ 426 */
427static int fpr_get_fpa(struct task_struct *target, 427static int fpr_get_fpa(struct task_struct *target,
428 unsigned int *pos, unsigned int *count, 428 unsigned int *pos, unsigned int *count,
@@ -430,13 +430,14 @@ static int fpr_get_fpa(struct task_struct *target,
430{ 430{
431 return user_regset_copyout(pos, count, kbuf, ubuf, 431 return user_regset_copyout(pos, count, kbuf, ubuf,
432 &target->thread.fpu, 432 &target->thread.fpu,
433 0, sizeof(elf_fpregset_t)); 433 0, NUM_FPU_REGS * sizeof(elf_fpreg_t));
434} 434}
435 435
436/* 436/*
437 * Copy the floating-point context to the supplied NT_PRFPREG buffer, 437 * Copy the floating-point context to the supplied NT_PRFPREG buffer,
438 * CONFIG_CPU_HAS_MSA variant. Only lower 64 bits of FP context's 438 * CONFIG_CPU_HAS_MSA variant. Only lower 64 bits of FP context's
439 * general register slots are copied to buffer slots. 439 * general register slots are copied to buffer slots. Only general
440 * registers are copied.
440 */ 441 */
441static int fpr_get_msa(struct task_struct *target, 442static int fpr_get_msa(struct task_struct *target,
442 unsigned int *pos, unsigned int *count, 443 unsigned int *pos, unsigned int *count,
@@ -458,20 +459,29 @@ static int fpr_get_msa(struct task_struct *target,
458 return 0; 459 return 0;
459} 460}
460 461
461/* Copy the floating-point context to the supplied NT_PRFPREG buffer. */ 462/*
463 * Copy the floating-point context to the supplied NT_PRFPREG buffer.
464 * Choose the appropriate helper for general registers, and then copy
465 * the FCSR register separately.
466 */
462static int fpr_get(struct task_struct *target, 467static int fpr_get(struct task_struct *target,
463 const struct user_regset *regset, 468 const struct user_regset *regset,
464 unsigned int pos, unsigned int count, 469 unsigned int pos, unsigned int count,
465 void *kbuf, void __user *ubuf) 470 void *kbuf, void __user *ubuf)
466{ 471{
472 const int fcr31_pos = NUM_FPU_REGS * sizeof(elf_fpreg_t);
467 int err; 473 int err;
468 474
469 /* XXX fcr31 */
470
471 if (sizeof(target->thread.fpu.fpr[0]) == sizeof(elf_fpreg_t)) 475 if (sizeof(target->thread.fpu.fpr[0]) == sizeof(elf_fpreg_t))
472 err = fpr_get_fpa(target, &pos, &count, &kbuf, &ubuf); 476 err = fpr_get_fpa(target, &pos, &count, &kbuf, &ubuf);
473 else 477 else
474 err = fpr_get_msa(target, &pos, &count, &kbuf, &ubuf); 478 err = fpr_get_msa(target, &pos, &count, &kbuf, &ubuf);
479 if (err)
480 return err;
481
482 err = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
483 &target->thread.fpu.fcr31,
484 fcr31_pos, fcr31_pos + sizeof(u32));
475 485
476 return err; 486 return err;
477} 487}
@@ -479,7 +489,7 @@ static int fpr_get(struct task_struct *target,
479/* 489/*
480 * Copy the supplied NT_PRFPREG buffer to the floating-point context, 490 * Copy the supplied NT_PRFPREG buffer to the floating-point context,
481 * !CONFIG_CPU_HAS_MSA variant. Buffer slots correspond 1:1 to FP 491 * !CONFIG_CPU_HAS_MSA variant. Buffer slots correspond 1:1 to FP
482 * context's general register slots. 492 * context's general register slots. Only general registers are copied.
483 */ 493 */
484static int fpr_set_fpa(struct task_struct *target, 494static int fpr_set_fpa(struct task_struct *target,
485 unsigned int *pos, unsigned int *count, 495 unsigned int *pos, unsigned int *count,
@@ -487,13 +497,14 @@ static int fpr_set_fpa(struct task_struct *target,
487{ 497{
488 return user_regset_copyin(pos, count, kbuf, ubuf, 498 return user_regset_copyin(pos, count, kbuf, ubuf,
489 &target->thread.fpu, 499 &target->thread.fpu,
490 0, sizeof(elf_fpregset_t)); 500 0, NUM_FPU_REGS * sizeof(elf_fpreg_t));
491} 501}
492 502
493/* 503/*
494 * Copy the supplied NT_PRFPREG buffer to the floating-point context, 504 * Copy the supplied NT_PRFPREG buffer to the floating-point context,
495 * CONFIG_CPU_HAS_MSA variant. Buffer slots are copied to lower 64 505 * CONFIG_CPU_HAS_MSA variant. Buffer slots are copied to lower 64
496 * bits only of FP context's general register slots. 506 * bits only of FP context's general register slots. Only general
507 * registers are copied.
497 */ 508 */
498static int fpr_set_msa(struct task_struct *target, 509static int fpr_set_msa(struct task_struct *target,
499 unsigned int *pos, unsigned int *count, 510 unsigned int *pos, unsigned int *count,
@@ -518,6 +529,8 @@ static int fpr_set_msa(struct task_struct *target,
518 529
519/* 530/*
520 * Copy the supplied NT_PRFPREG buffer to the floating-point context. 531 * Copy the supplied NT_PRFPREG buffer to the floating-point context.
532 * Choose the appropriate helper for general registers, and then copy
533 * the FCSR register separately.
521 * 534 *
522 * We optimize for the case where `count % sizeof(elf_fpreg_t) == 0', 535 * We optimize for the case where `count % sizeof(elf_fpreg_t) == 0',
523 * which is supposed to have been guaranteed by the kernel before 536 * which is supposed to have been guaranteed by the kernel before
@@ -530,18 +543,30 @@ static int fpr_set(struct task_struct *target,
530 unsigned int pos, unsigned int count, 543 unsigned int pos, unsigned int count,
531 const void *kbuf, const void __user *ubuf) 544 const void *kbuf, const void __user *ubuf)
532{ 545{
546 const int fcr31_pos = NUM_FPU_REGS * sizeof(elf_fpreg_t);
547 u32 fcr31;
533 int err; 548 int err;
534 549
535 BUG_ON(count % sizeof(elf_fpreg_t)); 550 BUG_ON(count % sizeof(elf_fpreg_t));
536 551
537 /* XXX fcr31 */
538
539 init_fp_ctx(target); 552 init_fp_ctx(target);
540 553
541 if (sizeof(target->thread.fpu.fpr[0]) == sizeof(elf_fpreg_t)) 554 if (sizeof(target->thread.fpu.fpr[0]) == sizeof(elf_fpreg_t))
542 err = fpr_set_fpa(target, &pos, &count, &kbuf, &ubuf); 555 err = fpr_set_fpa(target, &pos, &count, &kbuf, &ubuf);
543 else 556 else
544 err = fpr_set_msa(target, &pos, &count, &kbuf, &ubuf); 557 err = fpr_set_msa(target, &pos, &count, &kbuf, &ubuf);
558 if (err)
559 return err;
560
561 if (count > 0) {
562 err = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
563 &fcr31,
564 fcr31_pos, fcr31_pos + sizeof(u32));
565 if (err)
566 return err;
567
568 ptrace_setfcr31(target, fcr31);
569 }
545 570
546 return err; 571 return err;
547} 572}