xref: /openbmc/linux/arch/powerpc/kernel/ptrace/ptrace-altivec.c (revision 4b4193256c8d3bc3a5397b5cd9494c2ad386317d)
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