// SPDX-License-Identifier: GPL-2.0-or-later #include <linux/regset.h> #include <asm/switch_to.h> #include "ptrace-decl.h" /* * Regardless of transactions, 'fp_state' holds the current running * value of all FPR registers and 'ckfp_state' holds the last checkpointed * value of all FPR registers for the current transaction. * * Userspace interface buffer layout: * * struct data { * u64 fpr[32]; * u64 fpscr; * }; */ int fpr_get(struct task_struct *target, const struct user_regset *regset, struct membuf to) { u64 buf[33]; int i; flush_fp_to_thread(target); /* copy to local buffer then write that out */ for (i = 0; i < 32 ; i++) buf[i] = target->thread.TS_FPR(i); buf[32] = target->thread.fp_state.fpscr; return membuf_write(&to, buf, 33 * sizeof(u64)); } /* * Regardless of transactions, 'fp_state' holds the current running * value of all FPR registers and 'ckfp_state' holds the last checkpointed * value of all FPR registers for the current transaction. * * Userspace interface buffer layout: * * struct data { * u64 fpr[32]; * u64 fpscr; * }; * */ int fpr_set(struct task_struct *target, const struct user_regset *regset, unsigned int pos, unsigned int count, const void *kbuf, const void __user *ubuf) { u64 buf[33]; int i; flush_fp_to_thread(target); for (i = 0; i < 32 ; i++) buf[i] = target->thread.TS_FPR(i); buf[32] = target->thread.fp_state.fpscr; /* copy to local buffer then write that out */ i = user_regset_copyin(&pos, &count, &kbuf, &ubuf, buf, 0, -1); if (i) return i; for (i = 0; i < 32 ; i++) target->thread.TS_FPR(i) = buf[i]; target->thread.fp_state.fpscr = buf[32]; return 0; } /* * Currently to set and get all the vsx state, you need to call * the fp and VMX calls as well. This only get/sets the lower 32 * 128bit VSX registers. */ int vsr_active(struct task_struct *target, const struct user_regset *regset) { flush_vsx_to_thread(target); return target->thread.used_vsr ? regset->n : 0; } /* * Regardless of transactions, 'fp_state' holds the current running * value of all FPR registers and 'ckfp_state' holds the last * checkpointed value of all FPR registers for the current * transaction. * * Userspace interface buffer layout: * * struct data { * u64 vsx[32]; * }; */ int vsr_get(struct task_struct *target, const struct user_regset *regset, struct membuf to) { u64 buf[32]; int i; flush_tmregs_to_thread(target); flush_fp_to_thread(target); flush_altivec_to_thread(target); flush_vsx_to_thread(target); for (i = 0; i < 32 ; i++) buf[i] = target->thread.fp_state.fpr[i][TS_VSRLOWOFFSET]; return membuf_write(&to, buf, 32 * sizeof(double)); } /* * Regardless of transactions, 'fp_state' holds the current running * value of all FPR registers and 'ckfp_state' holds the last * checkpointed value of all FPR registers for the current * transaction. * * Userspace interface buffer layout: * * struct data { * u64 vsx[32]; * }; */ int vsr_set(struct task_struct *target, const struct user_regset *regset, unsigned int pos, unsigned int count, const void *kbuf, const void __user *ubuf) { u64 buf[32]; int ret, i; flush_tmregs_to_thread(target); flush_fp_to_thread(target); flush_altivec_to_thread(target); flush_vsx_to_thread(target); for (i = 0; i < 32 ; i++) buf[i] = target->thread.fp_state.fpr[i][TS_VSRLOWOFFSET]; ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, buf, 0, 32 * sizeof(double)); if (!ret) for (i = 0; i < 32 ; i++) target->thread.fp_state.fpr[i][TS_VSRLOWOFFSET] = buf[i]; return ret; }