17b99ed4eSChristophe Leroy // SPDX-License-Identifier: GPL-2.0-or-later
27b99ed4eSChristophe Leroy
37b99ed4eSChristophe Leroy #include <linux/regset.h>
47b99ed4eSChristophe Leroy
57b99ed4eSChristophe Leroy #include <asm/switch_to.h>
67b99ed4eSChristophe Leroy
77b99ed4eSChristophe Leroy #include "ptrace-decl.h"
87b99ed4eSChristophe Leroy
97b99ed4eSChristophe Leroy /*
107b99ed4eSChristophe Leroy * Regardless of transactions, 'fp_state' holds the current running
117b99ed4eSChristophe Leroy * value of all FPR registers and 'ckfp_state' holds the last checkpointed
127b99ed4eSChristophe Leroy * value of all FPR registers for the current transaction.
137b99ed4eSChristophe Leroy *
147b99ed4eSChristophe Leroy * Userspace interface buffer layout:
157b99ed4eSChristophe Leroy *
167b99ed4eSChristophe Leroy * struct data {
177b99ed4eSChristophe Leroy * u64 fpr[32];
187b99ed4eSChristophe Leroy * u64 fpscr;
197b99ed4eSChristophe Leroy * };
207b99ed4eSChristophe Leroy */
fpr_get(struct task_struct * target,const struct user_regset * regset,struct membuf to)217b99ed4eSChristophe Leroy int fpr_get(struct task_struct *target, const struct user_regset *regset,
2247e12855SAl Viro struct membuf to)
237b99ed4eSChristophe Leroy {
247b99ed4eSChristophe Leroy u64 buf[33];
257b99ed4eSChristophe Leroy int i;
267b99ed4eSChristophe Leroy
277b99ed4eSChristophe Leroy flush_fp_to_thread(target);
287b99ed4eSChristophe Leroy
297b99ed4eSChristophe Leroy /* copy to local buffer then write that out */
307b99ed4eSChristophe Leroy for (i = 0; i < 32 ; i++)
317b99ed4eSChristophe Leroy buf[i] = target->thread.TS_FPR(i);
327b99ed4eSChristophe Leroy buf[32] = target->thread.fp_state.fpscr;
3347e12855SAl Viro return membuf_write(&to, buf, 33 * sizeof(u64));
347b99ed4eSChristophe Leroy }
357b99ed4eSChristophe Leroy
367b99ed4eSChristophe Leroy /*
377b99ed4eSChristophe Leroy * Regardless of transactions, 'fp_state' holds the current running
387b99ed4eSChristophe Leroy * value of all FPR registers and 'ckfp_state' holds the last checkpointed
397b99ed4eSChristophe Leroy * value of all FPR registers for the current transaction.
407b99ed4eSChristophe Leroy *
417b99ed4eSChristophe Leroy * Userspace interface buffer layout:
427b99ed4eSChristophe Leroy *
437b99ed4eSChristophe Leroy * struct data {
447b99ed4eSChristophe Leroy * u64 fpr[32];
457b99ed4eSChristophe Leroy * u64 fpscr;
467b99ed4eSChristophe Leroy * };
477b99ed4eSChristophe Leroy *
487b99ed4eSChristophe Leroy */
fpr_set(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,const void * kbuf,const void __user * ubuf)497b99ed4eSChristophe Leroy int fpr_set(struct task_struct *target, const struct user_regset *regset,
507b99ed4eSChristophe Leroy unsigned int pos, unsigned int count,
517b99ed4eSChristophe Leroy const void *kbuf, const void __user *ubuf)
527b99ed4eSChristophe Leroy {
537b99ed4eSChristophe Leroy u64 buf[33];
547b99ed4eSChristophe Leroy int i;
557b99ed4eSChristophe Leroy
567b99ed4eSChristophe Leroy flush_fp_to_thread(target);
577b99ed4eSChristophe Leroy
587b99ed4eSChristophe Leroy for (i = 0; i < 32 ; i++)
597b99ed4eSChristophe Leroy buf[i] = target->thread.TS_FPR(i);
607b99ed4eSChristophe Leroy buf[32] = target->thread.fp_state.fpscr;
617b99ed4eSChristophe Leroy
627b99ed4eSChristophe Leroy /* copy to local buffer then write that out */
637b99ed4eSChristophe Leroy i = user_regset_copyin(&pos, &count, &kbuf, &ubuf, buf, 0, -1);
647b99ed4eSChristophe Leroy if (i)
657b99ed4eSChristophe Leroy return i;
667b99ed4eSChristophe Leroy
677b99ed4eSChristophe Leroy for (i = 0; i < 32 ; i++)
687b99ed4eSChristophe Leroy target->thread.TS_FPR(i) = buf[i];
697b99ed4eSChristophe Leroy target->thread.fp_state.fpscr = buf[32];
707b99ed4eSChristophe Leroy return 0;
717b99ed4eSChristophe Leroy }
727b99ed4eSChristophe Leroy
737b99ed4eSChristophe Leroy /*
74*2b461880SMichael Ellerman * Currently to set and get all the vsx state, you need to call
757b99ed4eSChristophe Leroy * the fp and VMX calls as well. This only get/sets the lower 32
767b99ed4eSChristophe Leroy * 128bit VSX registers.
777b99ed4eSChristophe Leroy */
787b99ed4eSChristophe Leroy
vsr_active(struct task_struct * target,const struct user_regset * regset)797b99ed4eSChristophe Leroy int vsr_active(struct task_struct *target, const struct user_regset *regset)
807b99ed4eSChristophe Leroy {
817b99ed4eSChristophe Leroy flush_vsx_to_thread(target);
827b99ed4eSChristophe Leroy return target->thread.used_vsr ? regset->n : 0;
837b99ed4eSChristophe Leroy }
847b99ed4eSChristophe Leroy
857b99ed4eSChristophe Leroy /*
867b99ed4eSChristophe Leroy * Regardless of transactions, 'fp_state' holds the current running
877b99ed4eSChristophe Leroy * value of all FPR registers and 'ckfp_state' holds the last
887b99ed4eSChristophe Leroy * checkpointed value of all FPR registers for the current
897b99ed4eSChristophe Leroy * transaction.
907b99ed4eSChristophe Leroy *
917b99ed4eSChristophe Leroy * Userspace interface buffer layout:
927b99ed4eSChristophe Leroy *
937b99ed4eSChristophe Leroy * struct data {
947b99ed4eSChristophe Leroy * u64 vsx[32];
957b99ed4eSChristophe Leroy * };
967b99ed4eSChristophe Leroy */
vsr_get(struct task_struct * target,const struct user_regset * regset,struct membuf to)977b99ed4eSChristophe Leroy int vsr_get(struct task_struct *target, const struct user_regset *regset,
9847e12855SAl Viro struct membuf to)
997b99ed4eSChristophe Leroy {
1007b99ed4eSChristophe Leroy u64 buf[32];
10147e12855SAl Viro int i;
1027b99ed4eSChristophe Leroy
1037b99ed4eSChristophe Leroy flush_tmregs_to_thread(target);
1047b99ed4eSChristophe Leroy flush_fp_to_thread(target);
1057b99ed4eSChristophe Leroy flush_altivec_to_thread(target);
1067b99ed4eSChristophe Leroy flush_vsx_to_thread(target);
1077b99ed4eSChristophe Leroy
1087b99ed4eSChristophe Leroy for (i = 0; i < 32 ; i++)
1097b99ed4eSChristophe Leroy buf[i] = target->thread.fp_state.fpr[i][TS_VSRLOWOFFSET];
1107b99ed4eSChristophe Leroy
11147e12855SAl Viro return membuf_write(&to, buf, 32 * sizeof(double));
1127b99ed4eSChristophe Leroy }
1137b99ed4eSChristophe Leroy
1147b99ed4eSChristophe Leroy /*
1157b99ed4eSChristophe Leroy * Regardless of transactions, 'fp_state' holds the current running
1167b99ed4eSChristophe Leroy * value of all FPR registers and 'ckfp_state' holds the last
1177b99ed4eSChristophe Leroy * checkpointed value of all FPR registers for the current
1187b99ed4eSChristophe Leroy * transaction.
1197b99ed4eSChristophe Leroy *
1207b99ed4eSChristophe Leroy * Userspace interface buffer layout:
1217b99ed4eSChristophe Leroy *
1227b99ed4eSChristophe Leroy * struct data {
1237b99ed4eSChristophe Leroy * u64 vsx[32];
1247b99ed4eSChristophe Leroy * };
1257b99ed4eSChristophe Leroy */
vsr_set(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,const void * kbuf,const void __user * ubuf)1267b99ed4eSChristophe Leroy int vsr_set(struct task_struct *target, const struct user_regset *regset,
1277b99ed4eSChristophe Leroy unsigned int pos, unsigned int count,
1287b99ed4eSChristophe Leroy const void *kbuf, const void __user *ubuf)
1297b99ed4eSChristophe Leroy {
1307b99ed4eSChristophe Leroy u64 buf[32];
1317b99ed4eSChristophe Leroy int ret, i;
1327b99ed4eSChristophe Leroy
1337b99ed4eSChristophe Leroy flush_tmregs_to_thread(target);
1347b99ed4eSChristophe Leroy flush_fp_to_thread(target);
1357b99ed4eSChristophe Leroy flush_altivec_to_thread(target);
1367b99ed4eSChristophe Leroy flush_vsx_to_thread(target);
1377b99ed4eSChristophe Leroy
1387b99ed4eSChristophe Leroy for (i = 0; i < 32 ; i++)
1397b99ed4eSChristophe Leroy buf[i] = target->thread.fp_state.fpr[i][TS_VSRLOWOFFSET];
1407b99ed4eSChristophe Leroy
1417b99ed4eSChristophe Leroy ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
1427b99ed4eSChristophe Leroy buf, 0, 32 * sizeof(double));
1437b99ed4eSChristophe Leroy if (!ret)
1447b99ed4eSChristophe Leroy for (i = 0; i < 32 ; i++)
1457b99ed4eSChristophe Leroy target->thread.fp_state.fpr[i][TS_VSRLOWOFFSET] = buf[i];
1467b99ed4eSChristophe Leroy
1477b99ed4eSChristophe Leroy return ret;
1487b99ed4eSChristophe Leroy }
149