+
+static int
+genregs_get(struct task_struct *target,
+ const struct utrace_regset *regset,
+ unsigned int pos, unsigned int count,
+ void *kbuf, void __user *ubuf)
+{
+ if (kbuf) {
+ unsigned long *kp = kbuf;
+ while (count > 0) {
+ *kp++ = getreg(target, pos);
+ pos += 4;
+ count -= 4;
+ }
+ }
+ else {
+ unsigned long __user *up = ubuf;
+ while (count > 0) {
+ if (__put_user(getreg(target, pos), up++))
+ return -EFAULT;
+ pos += 4;
+ count -= 4;
+ }
+ }
+
+ return 0;
+}
+
+static int
+genregs_set(struct task_struct *target,
+ const struct utrace_regset *regset,
+ unsigned int pos, unsigned int count,
+ const void *kbuf, const void __user *ubuf)
+{
+ int ret = 0;
+
+ if (kbuf) {
+ const unsigned long *kp = kbuf;
+ while (!ret && count > 0) {
+ ret = putreg(target, pos, *kp++);
+ pos += 4;
+ count -= 4;
+ }
+ }
+ else {
+ int ret = 0;
+ const unsigned long __user *up = ubuf;
+ while (!ret && count > 0) {
+ unsigned long val;
+ ret = __get_user(val, up++);
+ if (!ret)
+ ret = putreg(target, pos, val);
+ pos += 4;
+ count -= 4;
+ }
+ }
+
+ return ret;
+}
+
+static int
+fpregs_active(struct task_struct *target, const struct utrace_regset *regset)
+{
+ return tsk_used_math(target) ? regset->n : 0;
+}
+
+static int
+fpregs_get(struct task_struct *target,
+ const struct utrace_regset *regset,
+ unsigned int pos, unsigned int count,
+ void *kbuf, void __user *ubuf)
+{
+ struct user_i387_struct fp;
+ int ret;
+
+ if (tsk_used_math(target)) {
+ if (target == current)
+ unlazy_fpu(target);
+ }
+ else
+ init_fpu(target);
+
+ ret = get_fpregs(&fp, target);
+ if (ret == 0)
+ ret = utrace_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ &fp, 0, -1);
+
+ return ret;
+}
+
+static int
+fpregs_set(struct task_struct *target,
+ const struct utrace_regset *regset,
+ unsigned int pos, unsigned int count,
+ const void *kbuf, const void __user *ubuf)
+{
+ struct user_i387_struct fp;
+ int ret;
+
+ if (tsk_used_math(target)) {
+ if (target == current)
+ unlazy_fpu(target);
+ }
+ else if (pos == 0 && count == sizeof(fp))
+ set_stopped_child_used_math(target);
+ else
+ init_fpu(target);
+
+ if (pos > 0 || count < sizeof(fp)) {
+ ret = get_fpregs(&fp, target);
+ if (ret == 0)
+ ret = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ &fp, 0, -1);
+ if (ret)
+ return ret;
+ kbuf = &fp;
+ }
+ else if (kbuf == NULL) {
+ if (__copy_from_user(&fp, ubuf, sizeof(fp)))
+ return -EFAULT;
+ kbuf = &fp;
+ }
+
+ return set_fpregs(target, kbuf);
+}
+
+static int
+fpxregs_active(struct task_struct *target, const struct utrace_regset *regset)
+{
+ return !cpu_has_fxsr ? -ENODEV : tsk_used_math(target) ? regset->n : 0;
+}
+
+static int
+fpxregs_get(struct task_struct *target,
+ const struct utrace_regset *regset,
+ unsigned int pos, unsigned int count,
+ void *kbuf, void __user *ubuf)
+{
+ if (!cpu_has_fxsr)
+ return -ENODEV;
+
+ if (tsk_used_math(target))
+ unlazy_fpu(target);
+ else
+ init_fpu(target);
+
+ return utrace_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ &target->thread.i387.fxsave, 0, -1);
+}
+
+static int
+fpxregs_set(struct task_struct *target,
+ const struct utrace_regset *regset,
+ unsigned int pos, unsigned int count,
+ const void *kbuf, const void __user *ubuf)
+{
+ int ret;
+
+ if (!cpu_has_fxsr)
+ return -ENODEV;
+
+ if (tsk_used_math(target))
+ unlazy_fpu(target);
+ else if (pos == 0 && count == sizeof(target->thread.i387.fxsave))
+ set_stopped_child_used_math(target);
+ else
+ init_fpu(target);
+
+ ret = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ &target->thread.i387.fxsave, 0, -1);
+
+ updated_fpxregs(target);
+
+ return ret;
+}
+
+
+static int
+dbregs_active(struct task_struct *tsk, const struct utrace_regset *regset)
+{
+ if (tsk->thread.debugreg[DR_CONTROL] | tsk->thread.debugreg[DR_STATUS])
+ return 8;
+ return 0;
+}
+
+static int
+dbregs_get(struct task_struct *target,
+ const struct utrace_regset *regset,
+ unsigned int pos, unsigned int count,
+ void *kbuf, void __user *ubuf)