aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel
diff options
context:
space:
mode:
authorMaciej W. Rozycki <macro@mips.com>2018-05-15 18:34:28 -0400
committerPaul Burton <paul.burton@mips.com>2018-07-19 16:47:51 -0400
commit44109c60176ae73924a42a6bef64ef151aba9095 (patch)
tree464878c5c84bd2dfc7a22274c59b5bb445826caf /arch/mips/kernel
parentf5958b4cf4fc38ed4583ab83fb7c4cd1ab05f47b (diff)
MIPS: Add DSP ASE regset support
Define an NT_MIPS_DSP core file note type and implement a corresponding regset holding the DSP ASE register context, following the layout of the `mips_dsp_state' structure, except for the DSPControl register stored as a 64-bit rather than 32-bit quantity in a 64-bit note. The lack of DSP ASE register saving to core files can be considered a design flaw with commit e50c0a8fa60d ("Support the MIPS32 / MIPS64 DSP ASE."), leading to an incomplete state being saved. Consequently no DSP ASE regset has been created with commit 7aeb753b5353 ("MIPS: Implement task_user_regset_view."), when regset support was added to the MIPS port. Additionally there is no way for ptrace(2) to correctly access the DSP accumulator registers in n32 processes with the existing interfaces. This is due to 32-bit truncation of data passed with PTRACE_PEEKUSR and PTRACE_POKEUSR requests, which cannot be avoided owing to how the data types for ptrace(3) have been defined. This new NT_MIPS_DSP regset fills the missing interface gap. [paul.burton@mips.com: - Change NT_MIPS_DSP to 0x800 to avoid conflict with NT_VMCOREDD introduced by commit 2724273e8fd0 ("vmcore: add API to collect hardware dump in second kernel"). - Drop stable tag. Whilst I agree the lack of this functionality can be considered a flaw in earlier DSP ASE support, it's still new functionality which doesn't meet up to the requirements set out in Documentation/process/stable-kernel-rules.rst.] Signed-off-by: Maciej W. Rozycki <macro@mips.com> Signed-off-by: Paul Burton <paul.burton@mips.com> References: 7aeb753b5353 ("MIPS: Implement task_user_regset_view.") Patchwork: https://patchwork.linux-mips.org/patch/19330/ Cc: Alexander Viro <viro@zeniv.linux.org.uk> Cc: James Hogan <jhogan@kernel.org> Cc: Ralf Baechle <ralf@linux-mips.org> Cc: linux-fsdevel@vger.kernel.org Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org
Diffstat (limited to 'arch/mips/kernel')
-rw-r--r--arch/mips/kernel/ptrace.c189
1 files changed, 189 insertions, 0 deletions
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index 8c8d42823bda..a536271ba084 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -41,6 +41,7 @@
41#include <asm/mipsmtregs.h> 41#include <asm/mipsmtregs.h>
42#include <asm/pgtable.h> 42#include <asm/pgtable.h>
43#include <asm/page.h> 43#include <asm/page.h>
44#include <asm/processor.h>
44#include <asm/syscall.h> 45#include <asm/syscall.h>
45#include <linux/uaccess.h> 46#include <linux/uaccess.h>
46#include <asm/bootinfo.h> 47#include <asm/bootinfo.h>
@@ -589,9 +590,179 @@ static int fpr_set(struct task_struct *target,
589 return err; 590 return err;
590} 591}
591 592
593#if defined(CONFIG_32BIT) || defined(CONFIG_MIPS32_O32)
594
595/*
596 * Copy the DSP context to the supplied 32-bit NT_MIPS_DSP buffer.
597 */
598static int dsp32_get(struct task_struct *target,
599 const struct user_regset *regset,
600 unsigned int pos, unsigned int count,
601 void *kbuf, void __user *ubuf)
602{
603 unsigned int start, num_regs, i;
604 u32 dspregs[NUM_DSP_REGS + 1];
605
606 BUG_ON(count % sizeof(u32));
607
608 if (!cpu_has_dsp)
609 return -EIO;
610
611 start = pos / sizeof(u32);
612 num_regs = count / sizeof(u32);
613
614 if (start + num_regs > NUM_DSP_REGS + 1)
615 return -EIO;
616
617 for (i = start; i < num_regs; i++)
618 switch (i) {
619 case 0 ... NUM_DSP_REGS - 1:
620 dspregs[i] = target->thread.dsp.dspr[i];
621 break;
622 case NUM_DSP_REGS:
623 dspregs[i] = target->thread.dsp.dspcontrol;
624 break;
625 }
626 return user_regset_copyout(&pos, &count, &kbuf, &ubuf, dspregs, 0,
627 sizeof(dspregs));
628}
629
630/*
631 * Copy the supplied 32-bit NT_MIPS_DSP buffer to the DSP context.
632 */
633static int dsp32_set(struct task_struct *target,
634 const struct user_regset *regset,
635 unsigned int pos, unsigned int count,
636 const void *kbuf, const void __user *ubuf)
637{
638 unsigned int start, num_regs, i;
639 u32 dspregs[NUM_DSP_REGS + 1];
640 int err;
641
642 BUG_ON(count % sizeof(u32));
643
644 if (!cpu_has_dsp)
645 return -EIO;
646
647 start = pos / sizeof(u32);
648 num_regs = count / sizeof(u32);
649
650 if (start + num_regs > NUM_DSP_REGS + 1)
651 return -EIO;
652
653 err = user_regset_copyin(&pos, &count, &kbuf, &ubuf, dspregs, 0,
654 sizeof(dspregs));
655 if (err)
656 return err;
657
658 for (i = start; i < num_regs; i++)
659 switch (i) {
660 case 0 ... NUM_DSP_REGS - 1:
661 target->thread.dsp.dspr[i] = (s32)dspregs[i];
662 break;
663 case NUM_DSP_REGS:
664 target->thread.dsp.dspcontrol = (s32)dspregs[i];
665 break;
666 }
667
668 return 0;
669}
670
671#endif /* CONFIG_32BIT || CONFIG_MIPS32_O32 */
672
673#ifdef CONFIG_64BIT
674
675/*
676 * Copy the DSP context to the supplied 64-bit NT_MIPS_DSP buffer.
677 */
678static int dsp64_get(struct task_struct *target,
679 const struct user_regset *regset,
680 unsigned int pos, unsigned int count,
681 void *kbuf, void __user *ubuf)
682{
683 unsigned int start, num_regs, i;
684 u64 dspregs[NUM_DSP_REGS + 1];
685
686 BUG_ON(count % sizeof(u64));
687
688 if (!cpu_has_dsp)
689 return -EIO;
690
691 start = pos / sizeof(u64);
692 num_regs = count / sizeof(u64);
693
694 if (start + num_regs > NUM_DSP_REGS + 1)
695 return -EIO;
696
697 for (i = start; i < num_regs; i++)
698 switch (i) {
699 case 0 ... NUM_DSP_REGS - 1:
700 dspregs[i] = target->thread.dsp.dspr[i];
701 break;
702 case NUM_DSP_REGS:
703 dspregs[i] = target->thread.dsp.dspcontrol;
704 break;
705 }
706 return user_regset_copyout(&pos, &count, &kbuf, &ubuf, dspregs, 0,
707 sizeof(dspregs));
708}
709
710/*
711 * Copy the supplied 64-bit NT_MIPS_DSP buffer to the DSP context.
712 */
713static int dsp64_set(struct task_struct *target,
714 const struct user_regset *regset,
715 unsigned int pos, unsigned int count,
716 const void *kbuf, const void __user *ubuf)
717{
718 unsigned int start, num_regs, i;
719 u64 dspregs[NUM_DSP_REGS + 1];
720 int err;
721
722 BUG_ON(count % sizeof(u64));
723
724 if (!cpu_has_dsp)
725 return -EIO;
726
727 start = pos / sizeof(u64);
728 num_regs = count / sizeof(u64);
729
730 if (start + num_regs > NUM_DSP_REGS + 1)
731 return -EIO;
732
733 err = user_regset_copyin(&pos, &count, &kbuf, &ubuf, dspregs, 0,
734 sizeof(dspregs));
735 if (err)
736 return err;
737
738 for (i = start; i < num_regs; i++)
739 switch (i) {
740 case 0 ... NUM_DSP_REGS - 1:
741 target->thread.dsp.dspr[i] = dspregs[i];
742 break;
743 case NUM_DSP_REGS:
744 target->thread.dsp.dspcontrol = dspregs[i];
745 break;
746 }
747
748 return 0;
749}
750
751#endif /* CONFIG_64BIT */
752
753/*
754 * Determine whether the DSP context is present.
755 */
756static int dsp_active(struct task_struct *target,
757 const struct user_regset *regset)
758{
759 return cpu_has_dsp ? NUM_DSP_REGS + 1 : -ENODEV;
760}
761
592enum mips_regset { 762enum mips_regset {
593 REGSET_GPR, 763 REGSET_GPR,
594 REGSET_FPR, 764 REGSET_FPR,
765 REGSET_DSP,
595}; 766};
596 767
597struct pt_regs_offset { 768struct pt_regs_offset {
@@ -697,6 +868,15 @@ static const struct user_regset mips_regsets[] = {
697 .get = fpr_get, 868 .get = fpr_get,
698 .set = fpr_set, 869 .set = fpr_set,
699 }, 870 },
871 [REGSET_DSP] = {
872 .core_note_type = NT_MIPS_DSP,
873 .n = NUM_DSP_REGS + 1,
874 .size = sizeof(u32),
875 .align = sizeof(u32),
876 .get = dsp32_get,
877 .set = dsp32_set,
878 .active = dsp_active,
879 },
700}; 880};
701 881
702static const struct user_regset_view user_mips_view = { 882static const struct user_regset_view user_mips_view = {
@@ -728,6 +908,15 @@ static const struct user_regset mips64_regsets[] = {
728 .get = fpr_get, 908 .get = fpr_get,
729 .set = fpr_set, 909 .set = fpr_set,
730 }, 910 },
911 [REGSET_DSP] = {
912 .core_note_type = NT_MIPS_DSP,
913 .n = NUM_DSP_REGS + 1,
914 .size = sizeof(u64),
915 .align = sizeof(u64),
916 .get = dsp64_get,
917 .set = dsp64_set,
918 .active = dsp_active,
919 },
731}; 920};
732 921
733static const struct user_regset_view user_mips64_view = { 922static const struct user_regset_view user_mips64_view = {