11b20773bSChristophe Leroy // SPDX-License-Identifier: GPL-2.0-or-later
21b20773bSChristophe Leroy
31b20773bSChristophe Leroy #include <linux/regset.h>
41b20773bSChristophe Leroy #include <linux/elf.h>
51b20773bSChristophe Leroy
61b20773bSChristophe Leroy #include <asm/switch_to.h>
71b20773bSChristophe Leroy
81b20773bSChristophe Leroy #include "ptrace-decl.h"
91b20773bSChristophe Leroy
101b20773bSChristophe Leroy /*
111b20773bSChristophe Leroy * Get/set all the altivec registers vr0..vr31, vscr, vrsave, in one go.
121b20773bSChristophe Leroy * The transfer totals 34 quadword. Quadwords 0-31 contain the
131b20773bSChristophe Leroy * corresponding vector registers. Quadword 32 contains the vscr as the
141b20773bSChristophe Leroy * last word (offset 12) within that quadword. Quadword 33 contains the
151b20773bSChristophe Leroy * vrsave as the first word (offset 0) within the quadword.
161b20773bSChristophe Leroy *
171b20773bSChristophe Leroy * This definition of the VMX state is compatible with the current PPC32
181b20773bSChristophe Leroy * ptrace interface. This allows signal handling and ptrace to use the
191b20773bSChristophe Leroy * same structures. This also simplifies the implementation of a bi-arch
201b20773bSChristophe Leroy * (combined (32- and 64-bit) gdb.
211b20773bSChristophe Leroy */
221b20773bSChristophe Leroy
vr_active(struct task_struct * target,const struct user_regset * regset)231b20773bSChristophe Leroy int vr_active(struct task_struct *target, const struct user_regset *regset)
241b20773bSChristophe Leroy {
251b20773bSChristophe Leroy flush_altivec_to_thread(target);
261b20773bSChristophe Leroy return target->thread.used_vr ? regset->n : 0;
271b20773bSChristophe Leroy }
281b20773bSChristophe Leroy
291b20773bSChristophe Leroy /*
301b20773bSChristophe Leroy * Regardless of transactions, 'vr_state' holds the current running
311b20773bSChristophe Leroy * value of all the VMX registers and 'ckvr_state' holds the last
321b20773bSChristophe Leroy * checkpointed value of all the VMX registers for the current
331b20773bSChristophe Leroy * transaction to fall back on in case it aborts.
341b20773bSChristophe Leroy *
351b20773bSChristophe Leroy * Userspace interface buffer layout:
361b20773bSChristophe Leroy *
371b20773bSChristophe Leroy * struct data {
381b20773bSChristophe Leroy * vector128 vr[32];
391b20773bSChristophe Leroy * vector128 vscr;
401b20773bSChristophe Leroy * vector128 vrsave;
411b20773bSChristophe Leroy * };
421b20773bSChristophe Leroy */
vr_get(struct task_struct * target,const struct user_regset * regset,struct membuf to)431b20773bSChristophe Leroy int vr_get(struct task_struct *target, const struct user_regset *regset,
44*47e12855SAl Viro struct membuf to)
451b20773bSChristophe Leroy {
46*47e12855SAl Viro union {
47*47e12855SAl Viro elf_vrreg_t reg;
48*47e12855SAl Viro u32 word;
49*47e12855SAl Viro } vrsave;
501b20773bSChristophe Leroy
511b20773bSChristophe Leroy flush_altivec_to_thread(target);
521b20773bSChristophe Leroy
531b20773bSChristophe Leroy BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) !=
541b20773bSChristophe Leroy offsetof(struct thread_vr_state, vr[32]));
551b20773bSChristophe Leroy
56*47e12855SAl Viro membuf_write(&to, &target->thread.vr_state, 33 * sizeof(vector128));
571b20773bSChristophe Leroy /*
581b20773bSChristophe Leroy * Copy out only the low-order word of vrsave.
591b20773bSChristophe Leroy */
601b20773bSChristophe Leroy memset(&vrsave, 0, sizeof(vrsave));
611b20773bSChristophe Leroy vrsave.word = target->thread.vrsave;
62*47e12855SAl Viro return membuf_write(&to, &vrsave, sizeof(vrsave));
631b20773bSChristophe Leroy }
641b20773bSChristophe Leroy
651b20773bSChristophe Leroy /*
661b20773bSChristophe Leroy * Regardless of transactions, 'vr_state' holds the current running
671b20773bSChristophe Leroy * value of all the VMX registers and 'ckvr_state' holds the last
681b20773bSChristophe Leroy * checkpointed value of all the VMX registers for the current
691b20773bSChristophe Leroy * transaction to fall back on in case it aborts.
701b20773bSChristophe Leroy *
711b20773bSChristophe Leroy * Userspace interface buffer layout:
721b20773bSChristophe Leroy *
731b20773bSChristophe Leroy * struct data {
741b20773bSChristophe Leroy * vector128 vr[32];
751b20773bSChristophe Leroy * vector128 vscr;
761b20773bSChristophe Leroy * vector128 vrsave;
771b20773bSChristophe Leroy * };
781b20773bSChristophe Leroy */
vr_set(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,const void * kbuf,const void __user * ubuf)791b20773bSChristophe Leroy int vr_set(struct task_struct *target, const struct user_regset *regset,
801b20773bSChristophe Leroy unsigned int pos, unsigned int count,
811b20773bSChristophe Leroy const void *kbuf, const void __user *ubuf)
821b20773bSChristophe Leroy {
831b20773bSChristophe Leroy int ret;
841b20773bSChristophe Leroy
851b20773bSChristophe Leroy flush_altivec_to_thread(target);
861b20773bSChristophe Leroy
871b20773bSChristophe Leroy BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) !=
881b20773bSChristophe Leroy offsetof(struct thread_vr_state, vr[32]));
891b20773bSChristophe Leroy
901b20773bSChristophe Leroy ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
911b20773bSChristophe Leroy &target->thread.vr_state, 0,
921b20773bSChristophe Leroy 33 * sizeof(vector128));
931b20773bSChristophe Leroy if (!ret && count > 0) {
941b20773bSChristophe Leroy /*
951b20773bSChristophe Leroy * We use only the first word of vrsave.
961b20773bSChristophe Leroy */
971b20773bSChristophe Leroy int start, end;
981b20773bSChristophe Leroy union {
991b20773bSChristophe Leroy elf_vrreg_t reg;
1001b20773bSChristophe Leroy u32 word;
1011b20773bSChristophe Leroy } vrsave;
1021b20773bSChristophe Leroy memset(&vrsave, 0, sizeof(vrsave));
1031b20773bSChristophe Leroy
1041b20773bSChristophe Leroy vrsave.word = target->thread.vrsave;
1051b20773bSChristophe Leroy
1061b20773bSChristophe Leroy start = 33 * sizeof(vector128);
1071b20773bSChristophe Leroy end = start + sizeof(vrsave);
1081b20773bSChristophe Leroy ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &vrsave,
1091b20773bSChristophe Leroy start, end);
1101b20773bSChristophe Leroy if (!ret)
1111b20773bSChristophe Leroy target->thread.vrsave = vrsave.word;
1121b20773bSChristophe Leroy }
1131b20773bSChristophe Leroy
1141b20773bSChristophe Leroy return ret;
1151b20773bSChristophe Leroy }
116