|
@@ -501,8 +501,170 @@ static const struct user_regset_view user_ppc_native_view = {
|
|
|
.regsets = native_regsets, .n = ARRAY_SIZE(native_regsets)
|
|
|
};
|
|
|
|
|
|
+#ifdef CONFIG_PPC64
|
|
|
+#include <linux/compat.h>
|
|
|
+
|
|
|
+static int gpr32_get(struct task_struct *target,
|
|
|
+ const struct user_regset *regset,
|
|
|
+ unsigned int pos, unsigned int count,
|
|
|
+ void *kbuf, void __user *ubuf)
|
|
|
+{
|
|
|
+ const unsigned long *regs = &target->thread.regs->gpr[0];
|
|
|
+ compat_ulong_t *k = kbuf;
|
|
|
+ compat_ulong_t __user *u = ubuf;
|
|
|
+ compat_ulong_t reg;
|
|
|
+
|
|
|
+ if (target->thread.regs == NULL)
|
|
|
+ return -EIO;
|
|
|
+
|
|
|
+ CHECK_FULL_REGS(target->thread.regs);
|
|
|
+
|
|
|
+ pos /= sizeof(reg);
|
|
|
+ count /= sizeof(reg);
|
|
|
+
|
|
|
+ if (kbuf)
|
|
|
+ for (; count > 0 && pos < PT_MSR; --count)
|
|
|
+ *k++ = regs[pos++];
|
|
|
+ else
|
|
|
+ for (; count > 0 && pos < PT_MSR; --count)
|
|
|
+ if (__put_user((compat_ulong_t) regs[pos++], u++))
|
|
|
+ return -EFAULT;
|
|
|
+
|
|
|
+ if (count > 0 && pos == PT_MSR) {
|
|
|
+ reg = get_user_msr(target);
|
|
|
+ if (kbuf)
|
|
|
+ *k++ = reg;
|
|
|
+ else if (__put_user(reg, u++))
|
|
|
+ return -EFAULT;
|
|
|
+ ++pos;
|
|
|
+ --count;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (kbuf)
|
|
|
+ for (; count > 0 && pos < PT_REGS_COUNT; --count)
|
|
|
+ *k++ = regs[pos++];
|
|
|
+ else
|
|
|
+ for (; count > 0 && pos < PT_REGS_COUNT; --count)
|
|
|
+ if (__put_user((compat_ulong_t) regs[pos++], u++))
|
|
|
+ return -EFAULT;
|
|
|
+
|
|
|
+ kbuf = k;
|
|
|
+ ubuf = u;
|
|
|
+ pos *= sizeof(reg);
|
|
|
+ count *= sizeof(reg);
|
|
|
+ return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
|
|
|
+ PT_REGS_COUNT * sizeof(reg), -1);
|
|
|
+}
|
|
|
+
|
|
|
+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)
|
|
|
+{
|
|
|
+ unsigned long *regs = &target->thread.regs->gpr[0];
|
|
|
+ const compat_ulong_t *k = kbuf;
|
|
|
+ const compat_ulong_t __user *u = ubuf;
|
|
|
+ compat_ulong_t reg;
|
|
|
+
|
|
|
+ if (target->thread.regs == NULL)
|
|
|
+ return -EIO;
|
|
|
+
|
|
|
+ CHECK_FULL_REGS(target->thread.regs);
|
|
|
+
|
|
|
+ pos /= sizeof(reg);
|
|
|
+ count /= sizeof(reg);
|
|
|
+
|
|
|
+ if (kbuf)
|
|
|
+ for (; count > 0 && pos < PT_MSR; --count)
|
|
|
+ regs[pos++] = *k++;
|
|
|
+ else
|
|
|
+ for (; count > 0 && pos < PT_MSR; --count) {
|
|
|
+ if (__get_user(reg, u++))
|
|
|
+ return -EFAULT;
|
|
|
+ regs[pos++] = reg;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if (count > 0 && pos == PT_MSR) {
|
|
|
+ if (kbuf)
|
|
|
+ reg = *k++;
|
|
|
+ else if (__get_user(reg, u++))
|
|
|
+ return -EFAULT;
|
|
|
+ set_user_msr(target, reg);
|
|
|
+ ++pos;
|
|
|
+ --count;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (kbuf)
|
|
|
+ for (; count > 0 && pos <= PT_MAX_PUT_REG; --count)
|
|
|
+ regs[pos++] = *k++;
|
|
|
+ else
|
|
|
+ for (; count > 0 && pos <= PT_MAX_PUT_REG; --count) {
|
|
|
+ if (__get_user(reg, u++))
|
|
|
+ return -EFAULT;
|
|
|
+ regs[pos++] = reg;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (count > 0 && pos == PT_TRAP) {
|
|
|
+ if (kbuf)
|
|
|
+ reg = *k++;
|
|
|
+ else if (__get_user(reg, u++))
|
|
|
+ return -EFAULT;
|
|
|
+ set_user_trap(target, reg);
|
|
|
+ ++pos;
|
|
|
+ --count;
|
|
|
+ }
|
|
|
+
|
|
|
+ kbuf = k;
|
|
|
+ ubuf = u;
|
|
|
+ pos *= sizeof(reg);
|
|
|
+ count *= sizeof(reg);
|
|
|
+ return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
|
|
|
+ (PT_TRAP + 1) * sizeof(reg), -1);
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * These are the regset flavors matching the CONFIG_PPC32 native set.
|
|
|
+ */
|
|
|
+static const struct user_regset compat_regsets[] = {
|
|
|
+ [REGSET_GPR] = {
|
|
|
+ .core_note_type = NT_PRSTATUS, .n = ELF_NGREG,
|
|
|
+ .size = sizeof(compat_long_t), .align = sizeof(compat_long_t),
|
|
|
+ .get = gpr32_get, .set = gpr32_set
|
|
|
+ },
|
|
|
+ [REGSET_FPR] = {
|
|
|
+ .core_note_type = NT_PRFPREG, .n = ELF_NFPREG,
|
|
|
+ .size = sizeof(double), .align = sizeof(double),
|
|
|
+ .get = fpr_get, .set = fpr_set
|
|
|
+ },
|
|
|
+#ifdef CONFIG_ALTIVEC
|
|
|
+ [REGSET_VMX] = {
|
|
|
+ .core_note_type = NT_PPC_VMX, .n = 34,
|
|
|
+ .size = sizeof(vector128), .align = sizeof(vector128),
|
|
|
+ .active = vr_active, .get = vr_get, .set = vr_set
|
|
|
+ },
|
|
|
+#endif
|
|
|
+#ifdef CONFIG_SPE
|
|
|
+ [REGSET_SPE] = {
|
|
|
+ .n = 35,
|
|
|
+ .size = sizeof(u32), .align = sizeof(u32),
|
|
|
+ .active = evr_active, .get = evr_get, .set = evr_set
|
|
|
+ },
|
|
|
+#endif
|
|
|
+};
|
|
|
+
|
|
|
+static const struct user_regset_view user_ppc_compat_view = {
|
|
|
+ .name = "ppc", .e_machine = EM_PPC, .ei_osabi = ELF_OSABI,
|
|
|
+ .regsets = compat_regsets, .n = ARRAY_SIZE(compat_regsets)
|
|
|
+};
|
|
|
+#endif /* CONFIG_PPC64 */
|
|
|
+
|
|
|
const struct user_regset_view *task_user_regset_view(struct task_struct *task)
|
|
|
{
|
|
|
+#ifdef CONFIG_PPC64
|
|
|
+ if (test_tsk_thread_flag(task, TIF_32BIT))
|
|
|
+ return &user_ppc_compat_view;
|
|
|
+#endif
|
|
|
return &user_ppc_native_view;
|
|
|
}
|
|
|
|