|
@@ -246,36 +246,160 @@ int ptrace_set_watch_regs(struct task_struct *child,
|
|
|
|
|
|
/* regset get/set implementations */
|
|
/* regset get/set implementations */
|
|
|
|
|
|
-static int gpr_get(struct task_struct *target,
|
|
|
|
- const struct user_regset *regset,
|
|
|
|
- unsigned int pos, unsigned int count,
|
|
|
|
- void *kbuf, void __user *ubuf)
|
|
|
|
|
|
+#if defined(CONFIG_32BIT) || defined(CONFIG_MIPS32_O32)
|
|
|
|
+
|
|
|
|
+static int gpr32_get(struct task_struct *target,
|
|
|
|
+ const struct user_regset *regset,
|
|
|
|
+ unsigned int pos, unsigned int count,
|
|
|
|
+ void *kbuf, void __user *ubuf)
|
|
{
|
|
{
|
|
struct pt_regs *regs = task_pt_regs(target);
|
|
struct pt_regs *regs = task_pt_regs(target);
|
|
|
|
+ u32 uregs[ELF_NGREG] = {};
|
|
|
|
+ unsigned i;
|
|
|
|
+
|
|
|
|
+ for (i = MIPS32_EF_R1; i <= MIPS32_EF_R31; i++) {
|
|
|
|
+ /* k0/k1 are copied as zero. */
|
|
|
|
+ if (i == MIPS32_EF_R26 || i == MIPS32_EF_R27)
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ uregs[i] = regs->regs[i - MIPS32_EF_R0];
|
|
|
|
+ }
|
|
|
|
|
|
- return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
|
|
|
- regs, 0, sizeof(*regs));
|
|
|
|
|
|
+ uregs[MIPS32_EF_LO] = regs->lo;
|
|
|
|
+ uregs[MIPS32_EF_HI] = regs->hi;
|
|
|
|
+ uregs[MIPS32_EF_CP0_EPC] = regs->cp0_epc;
|
|
|
|
+ uregs[MIPS32_EF_CP0_BADVADDR] = regs->cp0_badvaddr;
|
|
|
|
+ uregs[MIPS32_EF_CP0_STATUS] = regs->cp0_status;
|
|
|
|
+ uregs[MIPS32_EF_CP0_CAUSE] = regs->cp0_cause;
|
|
|
|
+
|
|
|
|
+ return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0,
|
|
|
|
+ sizeof(uregs));
|
|
}
|
|
}
|
|
|
|
|
|
-static int gpr_set(struct task_struct *target,
|
|
|
|
- const struct user_regset *regset,
|
|
|
|
- unsigned int pos, unsigned int count,
|
|
|
|
- const void *kbuf, const void __user *ubuf)
|
|
|
|
|
|
+static int gpr32_set(struct task_struct *target,
|
|
|
|
+ const struct user_regset *regset,
|
|
|
|
+ unsigned int pos, unsigned int count,
|
|
|
|
+ const void *kbuf, const void __user *ubuf)
|
|
{
|
|
{
|
|
- struct pt_regs newregs;
|
|
|
|
- int ret;
|
|
|
|
|
|
+ struct pt_regs *regs = task_pt_regs(target);
|
|
|
|
+ u32 uregs[ELF_NGREG];
|
|
|
|
+ unsigned start, num_regs, i;
|
|
|
|
+ int err;
|
|
|
|
+
|
|
|
|
+ start = pos / sizeof(u32);
|
|
|
|
+ num_regs = count / sizeof(u32);
|
|
|
|
+
|
|
|
|
+ if (start + num_regs > ELF_NGREG)
|
|
|
|
+ return -EIO;
|
|
|
|
+
|
|
|
|
+ err = user_regset_copyin(&pos, &count, &kbuf, &ubuf, uregs, 0,
|
|
|
|
+ sizeof(uregs));
|
|
|
|
+ if (err)
|
|
|
|
+ return err;
|
|
|
|
+
|
|
|
|
+ for (i = start; i < num_regs; i++) {
|
|
|
|
+ /*
|
|
|
|
+ * Cast all values to signed here so that if this is a 64-bit
|
|
|
|
+ * kernel, the supplied 32-bit values will be sign extended.
|
|
|
|
+ */
|
|
|
|
+ switch (i) {
|
|
|
|
+ case MIPS32_EF_R1 ... MIPS32_EF_R25:
|
|
|
|
+ /* k0/k1 are ignored. */
|
|
|
|
+ case MIPS32_EF_R28 ... MIPS32_EF_R31:
|
|
|
|
+ regs->regs[i - MIPS32_EF_R0] = (s32)uregs[i];
|
|
|
|
+ break;
|
|
|
|
+ case MIPS32_EF_LO:
|
|
|
|
+ regs->lo = (s32)uregs[i];
|
|
|
|
+ break;
|
|
|
|
+ case MIPS32_EF_HI:
|
|
|
|
+ regs->hi = (s32)uregs[i];
|
|
|
|
+ break;
|
|
|
|
+ case MIPS32_EF_CP0_EPC:
|
|
|
|
+ regs->cp0_epc = (s32)uregs[i];
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+#endif /* CONFIG_32BIT || CONFIG_MIPS32_O32 */
|
|
|
|
+
|
|
|
|
+#ifdef CONFIG_64BIT
|
|
|
|
+
|
|
|
|
+static int gpr64_get(struct task_struct *target,
|
|
|
|
+ const struct user_regset *regset,
|
|
|
|
+ unsigned int pos, unsigned int count,
|
|
|
|
+ void *kbuf, void __user *ubuf)
|
|
|
|
+{
|
|
|
|
+ struct pt_regs *regs = task_pt_regs(target);
|
|
|
|
+ u64 uregs[ELF_NGREG] = {};
|
|
|
|
+ unsigned i;
|
|
|
|
+
|
|
|
|
+ for (i = MIPS64_EF_R1; i <= MIPS64_EF_R31; i++) {
|
|
|
|
+ /* k0/k1 are copied as zero. */
|
|
|
|
+ if (i == MIPS64_EF_R26 || i == MIPS64_EF_R27)
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ uregs[i] = regs->regs[i - MIPS64_EF_R0];
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ uregs[MIPS64_EF_LO] = regs->lo;
|
|
|
|
+ uregs[MIPS64_EF_HI] = regs->hi;
|
|
|
|
+ uregs[MIPS64_EF_CP0_EPC] = regs->cp0_epc;
|
|
|
|
+ uregs[MIPS64_EF_CP0_BADVADDR] = regs->cp0_badvaddr;
|
|
|
|
+ uregs[MIPS64_EF_CP0_STATUS] = regs->cp0_status;
|
|
|
|
+ uregs[MIPS64_EF_CP0_CAUSE] = regs->cp0_cause;
|
|
|
|
+
|
|
|
|
+ return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0,
|
|
|
|
+ sizeof(uregs));
|
|
|
|
+}
|
|
|
|
|
|
- ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
|
|
|
- &newregs,
|
|
|
|
- 0, sizeof(newregs));
|
|
|
|
- if (ret)
|
|
|
|
- return ret;
|
|
|
|
|
|
+static int gpr64_set(struct task_struct *target,
|
|
|
|
+ const struct user_regset *regset,
|
|
|
|
+ unsigned int pos, unsigned int count,
|
|
|
|
+ const void *kbuf, const void __user *ubuf)
|
|
|
|
+{
|
|
|
|
+ struct pt_regs *regs = task_pt_regs(target);
|
|
|
|
+ u64 uregs[ELF_NGREG];
|
|
|
|
+ unsigned start, num_regs, i;
|
|
|
|
+ int err;
|
|
|
|
+
|
|
|
|
+ start = pos / sizeof(u64);
|
|
|
|
+ num_regs = count / sizeof(u64);
|
|
|
|
|
|
- *task_pt_regs(target) = newregs;
|
|
|
|
|
|
+ if (start + num_regs > ELF_NGREG)
|
|
|
|
+ return -EIO;
|
|
|
|
+
|
|
|
|
+ err = user_regset_copyin(&pos, &count, &kbuf, &ubuf, uregs, 0,
|
|
|
|
+ sizeof(uregs));
|
|
|
|
+ if (err)
|
|
|
|
+ return err;
|
|
|
|
+
|
|
|
|
+ for (i = start; i < num_regs; i++) {
|
|
|
|
+ switch (i) {
|
|
|
|
+ case MIPS64_EF_R1 ... MIPS64_EF_R25:
|
|
|
|
+ /* k0/k1 are ignored. */
|
|
|
|
+ case MIPS64_EF_R28 ... MIPS64_EF_R31:
|
|
|
|
+ regs->regs[i - MIPS64_EF_R0] = uregs[i];
|
|
|
|
+ break;
|
|
|
|
+ case MIPS64_EF_LO:
|
|
|
|
+ regs->lo = uregs[i];
|
|
|
|
+ break;
|
|
|
|
+ case MIPS64_EF_HI:
|
|
|
|
+ regs->hi = uregs[i];
|
|
|
|
+ break;
|
|
|
|
+ case MIPS64_EF_CP0_EPC:
|
|
|
|
+ regs->cp0_epc = uregs[i];
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+#endif /* CONFIG_64BIT */
|
|
|
|
+
|
|
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,
|
|
unsigned int pos, unsigned int count,
|
|
unsigned int pos, unsigned int count,
|
|
@@ -337,14 +461,16 @@ enum mips_regset {
|
|
REGSET_FPR,
|
|
REGSET_FPR,
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+#if defined(CONFIG_32BIT) || defined(CONFIG_MIPS32_O32)
|
|
|
|
+
|
|
static const struct user_regset mips_regsets[] = {
|
|
static const struct user_regset mips_regsets[] = {
|
|
[REGSET_GPR] = {
|
|
[REGSET_GPR] = {
|
|
.core_note_type = NT_PRSTATUS,
|
|
.core_note_type = NT_PRSTATUS,
|
|
.n = ELF_NGREG,
|
|
.n = ELF_NGREG,
|
|
.size = sizeof(unsigned int),
|
|
.size = sizeof(unsigned int),
|
|
.align = sizeof(unsigned int),
|
|
.align = sizeof(unsigned int),
|
|
- .get = gpr_get,
|
|
|
|
- .set = gpr_set,
|
|
|
|
|
|
+ .get = gpr32_get,
|
|
|
|
+ .set = gpr32_set,
|
|
},
|
|
},
|
|
[REGSET_FPR] = {
|
|
[REGSET_FPR] = {
|
|
.core_note_type = NT_PRFPREG,
|
|
.core_note_type = NT_PRFPREG,
|
|
@@ -364,14 +490,18 @@ static const struct user_regset_view user_mips_view = {
|
|
.n = ARRAY_SIZE(mips_regsets),
|
|
.n = ARRAY_SIZE(mips_regsets),
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+#endif /* CONFIG_32BIT || CONFIG_MIPS32_O32 */
|
|
|
|
+
|
|
|
|
+#ifdef CONFIG_64BIT
|
|
|
|
+
|
|
static const struct user_regset mips64_regsets[] = {
|
|
static const struct user_regset mips64_regsets[] = {
|
|
[REGSET_GPR] = {
|
|
[REGSET_GPR] = {
|
|
.core_note_type = NT_PRSTATUS,
|
|
.core_note_type = NT_PRSTATUS,
|
|
.n = ELF_NGREG,
|
|
.n = ELF_NGREG,
|
|
.size = sizeof(unsigned long),
|
|
.size = sizeof(unsigned long),
|
|
.align = sizeof(unsigned long),
|
|
.align = sizeof(unsigned long),
|
|
- .get = gpr_get,
|
|
|
|
- .set = gpr_set,
|
|
|
|
|
|
+ .get = gpr64_get,
|
|
|
|
+ .set = gpr64_set,
|
|
},
|
|
},
|
|
[REGSET_FPR] = {
|
|
[REGSET_FPR] = {
|
|
.core_note_type = NT_PRFPREG,
|
|
.core_note_type = NT_PRFPREG,
|
|
@@ -384,25 +514,26 @@ static const struct user_regset mips64_regsets[] = {
|
|
};
|
|
};
|
|
|
|
|
|
static const struct user_regset_view user_mips64_view = {
|
|
static const struct user_regset_view user_mips64_view = {
|
|
- .name = "mips",
|
|
|
|
|
|
+ .name = "mips64",
|
|
.e_machine = ELF_ARCH,
|
|
.e_machine = ELF_ARCH,
|
|
.ei_osabi = ELF_OSABI,
|
|
.ei_osabi = ELF_OSABI,
|
|
.regsets = mips64_regsets,
|
|
.regsets = mips64_regsets,
|
|
- .n = ARRAY_SIZE(mips_regsets),
|
|
|
|
|
|
+ .n = ARRAY_SIZE(mips64_regsets),
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+#endif /* CONFIG_64BIT */
|
|
|
|
+
|
|
const struct user_regset_view *task_user_regset_view(struct task_struct *task)
|
|
const struct user_regset_view *task_user_regset_view(struct task_struct *task)
|
|
{
|
|
{
|
|
#ifdef CONFIG_32BIT
|
|
#ifdef CONFIG_32BIT
|
|
return &user_mips_view;
|
|
return &user_mips_view;
|
|
-#endif
|
|
|
|
-
|
|
|
|
|
|
+#else
|
|
#ifdef CONFIG_MIPS32_O32
|
|
#ifdef CONFIG_MIPS32_O32
|
|
- if (test_tsk_thread_flag(task, TIF_32BIT_REGS))
|
|
|
|
- return &user_mips_view;
|
|
|
|
|
|
+ if (test_tsk_thread_flag(task, TIF_32BIT_REGS))
|
|
|
|
+ return &user_mips_view;
|
|
#endif
|
|
#endif
|
|
-
|
|
|
|
return &user_mips64_view;
|
|
return &user_mips64_view;
|
|
|
|
+#endif
|
|
}
|
|
}
|
|
|
|
|
|
long arch_ptrace(struct task_struct *child, long request,
|
|
long arch_ptrace(struct task_struct *child, long request,
|