MIPS: Add FP_MODE regset support
authorMaciej W. Rozycki <macro@mips.com>
Tue, 15 May 2018 22:40:18 +0000 (23:40 +0100)
committerPaul Burton <paul.burton@mips.com>
Thu, 19 Jul 2018 20:58:44 +0000 (13:58 -0700)
Define an NT_MIPS_FP_MODE core file note and implement a corresponding
regset holding the state handled by PR_SET_FP_MODE and PR_GET_FP_MODE
prctl(2) requests.  This lets debug software correctly interpret the
contents of floating-point general registers both in live debugging and
in core files, and also switch floating-point modes of a live process.

[paul.burton@mips.com:
  - Changed NT_MIPS_FP_MODE to 0x801 to match first nibble of
    NT_MIPS_DSP, which was also changed to avoid a conflict.]

Signed-off-by: Maciej W. Rozycki <macro@mips.com>
Signed-off-by: Paul Burton <paul.burton@mips.com>
Patchwork: https://patchwork.linux-mips.org/patch/19331/
Cc: James Hogan <jhogan@kernel.org>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: linux-mips@linux-mips.org
Cc: linux-kernel@vger.kernel.org
arch/mips/kernel/ptrace.c
include/uapi/linux/elf.h

index a536271..e5ba56c 100644 (file)
@@ -759,10 +759,57 @@ static int dsp_active(struct task_struct *target,
        return cpu_has_dsp ? NUM_DSP_REGS + 1 : -ENODEV;
 }
 
+/* Copy the FP mode setting to the supplied NT_MIPS_FP_MODE buffer.  */
+static int fp_mode_get(struct task_struct *target,
+                      const struct user_regset *regset,
+                      unsigned int pos, unsigned int count,
+                      void *kbuf, void __user *ubuf)
+{
+       int fp_mode;
+
+       fp_mode = mips_get_process_fp_mode(target);
+       return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &fp_mode, 0,
+                                  sizeof(fp_mode));
+}
+
+/*
+ * Copy the supplied NT_MIPS_FP_MODE buffer to the FP mode setting.
+ *
+ * We optimize for the case where `count % sizeof(int) == 0', which
+ * is supposed to have been guaranteed by the kernel before calling
+ * us, e.g. in `ptrace_regset'.  We enforce that requirement, so
+ * that we can safely avoid preinitializing temporaries for partial
+ * mode writes.
+ */
+static int fp_mode_set(struct task_struct *target,
+                      const struct user_regset *regset,
+                      unsigned int pos, unsigned int count,
+                      const void *kbuf, const void __user *ubuf)
+{
+       int fp_mode;
+       int err;
+
+       BUG_ON(count % sizeof(int));
+
+       if (pos + count > sizeof(fp_mode))
+               return -EIO;
+
+       err = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &fp_mode, 0,
+                                sizeof(fp_mode));
+       if (err)
+               return err;
+
+       if (count > 0)
+               err = mips_set_process_fp_mode(target, fp_mode);
+
+       return err;
+}
+
 enum mips_regset {
        REGSET_GPR,
        REGSET_FPR,
        REGSET_DSP,
+       REGSET_FP_MODE,
 };
 
 struct pt_regs_offset {
@@ -877,6 +924,14 @@ static const struct user_regset mips_regsets[] = {
                .set            = dsp32_set,
                .active         = dsp_active,
        },
+       [REGSET_FP_MODE] = {
+               .core_note_type = NT_MIPS_FP_MODE,
+               .n              = 1,
+               .size           = sizeof(int),
+               .align          = sizeof(int),
+               .get            = fp_mode_get,
+               .set            = fp_mode_set,
+       },
 };
 
 static const struct user_regset_view user_mips_view = {
@@ -917,6 +972,14 @@ static const struct user_regset mips64_regsets[] = {
                .set            = dsp64_set,
                .active         = dsp_active,
        },
+       [REGSET_FP_MODE] = {
+               .core_note_type = NT_MIPS_FP_MODE,
+               .n              = 1,
+               .size           = sizeof(int),
+               .align          = sizeof(int),
+               .get            = fp_mode_get,
+               .set            = fp_mode_set,
+       },
 };
 
 static const struct user_regset_view user_mips64_view = {
index e326c99..c5358e0 100644 (file)
@@ -423,6 +423,7 @@ typedef struct elf64_shdr {
 #define NT_ARC_V2      0x600           /* ARCv2 accumulator/extra registers */
 #define NT_VMCOREDD    0x700           /* Vmcore Device Dump Note */
 #define NT_MIPS_DSP    0x800           /* MIPS DSP ASE registers */
+#define NT_MIPS_FP_MODE        0x801           /* MIPS floating-point mode */
 
 /* Note header in a PT_NOTE section */
 typedef struct elf32_note {