From 1ae22a0e35636efceab83728ba30b013df761592 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Tue, 15 May 2018 23:40:18 +0100 Subject: [PATCH] MIPS: Add FP_MODE regset support 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 Signed-off-by: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/19331/ Cc: James Hogan Cc: Ralf Baechle Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org --- arch/mips/kernel/ptrace.c | 63 +++++++++++++++++++++++++++++++++++++++ include/uapi/linux/elf.h | 1 + 2 files changed, 64 insertions(+) diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index a536271ba084..e5ba56c01ee0 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -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 = { diff --git a/include/uapi/linux/elf.h b/include/uapi/linux/elf.h index e326c99b3881..c5358e0ae7c5 100644 --- a/include/uapi/linux/elf.h +++ b/include/uapi/linux/elf.h @@ -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 {