xref: /linux/arch/powerpc/kernel/ptrace/ptrace-tm.c (revision c771600c6af14749609b49565ffb4cac2959710d)
17c1f8db0SChristophe Leroy // SPDX-License-Identifier: GPL-2.0-or-later
27c1f8db0SChristophe Leroy 
37c1f8db0SChristophe Leroy #include <linux/regset.h>
47c1f8db0SChristophe Leroy 
57c1f8db0SChristophe Leroy #include <asm/switch_to.h>
67c1f8db0SChristophe Leroy #include <asm/tm.h>
77c1f8db0SChristophe Leroy #include <asm/asm-prototypes.h>
87c1f8db0SChristophe Leroy 
97c1f8db0SChristophe Leroy #include "ptrace-decl.h"
107c1f8db0SChristophe Leroy 
flush_tmregs_to_thread(struct task_struct * tsk)117c1f8db0SChristophe Leroy void flush_tmregs_to_thread(struct task_struct *tsk)
127c1f8db0SChristophe Leroy {
137c1f8db0SChristophe Leroy 	/*
147c1f8db0SChristophe Leroy 	 * If task is not current, it will have been flushed already to
150ddbbb89SBjorn Helgaas 	 * its thread_struct during __switch_to().
167c1f8db0SChristophe Leroy 	 *
177c1f8db0SChristophe Leroy 	 * A reclaim flushes ALL the state or if not in TM save TM SPRs
187c1f8db0SChristophe Leroy 	 * in the appropriate thread structures from live.
197c1f8db0SChristophe Leroy 	 */
207c1f8db0SChristophe Leroy 
217c1f8db0SChristophe Leroy 	if (!cpu_has_feature(CPU_FTR_TM) || tsk != current)
227c1f8db0SChristophe Leroy 		return;
237c1f8db0SChristophe Leroy 
247c1f8db0SChristophe Leroy 	if (MSR_TM_SUSPENDED(mfmsr())) {
257c1f8db0SChristophe Leroy 		tm_reclaim_current(TM_CAUSE_SIGNAL);
267c1f8db0SChristophe Leroy 	} else {
277c1f8db0SChristophe Leroy 		tm_enable();
287c1f8db0SChristophe Leroy 		tm_save_sprs(&tsk->thread);
297c1f8db0SChristophe Leroy 	}
307c1f8db0SChristophe Leroy }
317c1f8db0SChristophe Leroy 
get_user_ckpt_msr(struct task_struct * task)327c1f8db0SChristophe Leroy static unsigned long get_user_ckpt_msr(struct task_struct *task)
337c1f8db0SChristophe Leroy {
347c1f8db0SChristophe Leroy 	return task->thread.ckpt_regs.msr | task->thread.fpexc_mode;
357c1f8db0SChristophe Leroy }
367c1f8db0SChristophe Leroy 
set_user_ckpt_msr(struct task_struct * task,unsigned long msr)377c1f8db0SChristophe Leroy static int set_user_ckpt_msr(struct task_struct *task, unsigned long msr)
387c1f8db0SChristophe Leroy {
397c1f8db0SChristophe Leroy 	task->thread.ckpt_regs.msr &= ~MSR_DEBUGCHANGE;
407c1f8db0SChristophe Leroy 	task->thread.ckpt_regs.msr |= msr & MSR_DEBUGCHANGE;
417c1f8db0SChristophe Leroy 	return 0;
427c1f8db0SChristophe Leroy }
437c1f8db0SChristophe Leroy 
set_user_ckpt_trap(struct task_struct * task,unsigned long trap)447c1f8db0SChristophe Leroy static int set_user_ckpt_trap(struct task_struct *task, unsigned long trap)
457c1f8db0SChristophe Leroy {
46db30144bSNicholas Piggin 	set_trap(&task->thread.ckpt_regs, trap);
477c1f8db0SChristophe Leroy 	return 0;
487c1f8db0SChristophe Leroy }
497c1f8db0SChristophe Leroy 
507c1f8db0SChristophe Leroy /**
517c1f8db0SChristophe Leroy  * tm_cgpr_active - get active number of registers in CGPR
527c1f8db0SChristophe Leroy  * @target:	The target task.
537c1f8db0SChristophe Leroy  * @regset:	The user regset structure.
547c1f8db0SChristophe Leroy  *
557c1f8db0SChristophe Leroy  * This function checks for the active number of available
567c1f8db0SChristophe Leroy  * regisers in transaction checkpointed GPR category.
577c1f8db0SChristophe Leroy  */
tm_cgpr_active(struct task_struct * target,const struct user_regset * regset)587c1f8db0SChristophe Leroy int tm_cgpr_active(struct task_struct *target, const struct user_regset *regset)
597c1f8db0SChristophe Leroy {
607c1f8db0SChristophe Leroy 	if (!cpu_has_feature(CPU_FTR_TM))
617c1f8db0SChristophe Leroy 		return -ENODEV;
627c1f8db0SChristophe Leroy 
637c1f8db0SChristophe Leroy 	if (!MSR_TM_ACTIVE(target->thread.regs->msr))
647c1f8db0SChristophe Leroy 		return 0;
657c1f8db0SChristophe Leroy 
667c1f8db0SChristophe Leroy 	return regset->n;
677c1f8db0SChristophe Leroy }
687c1f8db0SChristophe Leroy 
697c1f8db0SChristophe Leroy /**
707c1f8db0SChristophe Leroy  * tm_cgpr_get - get CGPR registers
717c1f8db0SChristophe Leroy  * @target:	The target task.
727c1f8db0SChristophe Leroy  * @regset:	The user regset structure.
7347e12855SAl Viro  * @to:		Destination of copy.
747c1f8db0SChristophe Leroy  *
757c1f8db0SChristophe Leroy  * This function gets transaction checkpointed GPR registers.
767c1f8db0SChristophe Leroy  *
777c1f8db0SChristophe Leroy  * When the transaction is active, 'ckpt_regs' holds all the checkpointed
787c1f8db0SChristophe Leroy  * GPR register values for the current transaction to fall back on if it
797c1f8db0SChristophe Leroy  * aborts in between. This function gets those checkpointed GPR registers.
807c1f8db0SChristophe Leroy  * The userspace interface buffer layout is as follows.
817c1f8db0SChristophe Leroy  *
827c1f8db0SChristophe Leroy  * struct data {
837c1f8db0SChristophe Leroy  *	struct pt_regs ckpt_regs;
847c1f8db0SChristophe Leroy  * };
857c1f8db0SChristophe Leroy  */
tm_cgpr_get(struct task_struct * target,const struct user_regset * regset,struct membuf to)867c1f8db0SChristophe Leroy int tm_cgpr_get(struct task_struct *target, const struct user_regset *regset,
8747e12855SAl Viro 		struct membuf to)
887c1f8db0SChristophe Leroy {
89640586f8SOleg Nesterov 	struct membuf to_msr = membuf_at(&to, offsetof(struct pt_regs, msr));
90324a6946SOleg Nesterov #ifdef CONFIG_PPC64
91324a6946SOleg Nesterov 	struct membuf to_softe = membuf_at(&to, offsetof(struct pt_regs, softe));
92324a6946SOleg Nesterov #endif
93640586f8SOleg Nesterov 
947c1f8db0SChristophe Leroy 	if (!cpu_has_feature(CPU_FTR_TM))
957c1f8db0SChristophe Leroy 		return -ENODEV;
967c1f8db0SChristophe Leroy 
977c1f8db0SChristophe Leroy 	if (!MSR_TM_ACTIVE(target->thread.regs->msr))
987c1f8db0SChristophe Leroy 		return -ENODATA;
997c1f8db0SChristophe Leroy 
1007c1f8db0SChristophe Leroy 	flush_tmregs_to_thread(target);
1017c1f8db0SChristophe Leroy 	flush_fp_to_thread(target);
1027c1f8db0SChristophe Leroy 	flush_altivec_to_thread(target);
1037c1f8db0SChristophe Leroy 
104640586f8SOleg Nesterov 	membuf_write(&to, &target->thread.ckpt_regs, sizeof(struct user_pt_regs));
1057c1f8db0SChristophe Leroy 
106640586f8SOleg Nesterov 	membuf_store(&to_msr, get_user_ckpt_msr(target));
107324a6946SOleg Nesterov #ifdef CONFIG_PPC64
108324a6946SOleg Nesterov 	membuf_store(&to_softe, 0x1ul);
109324a6946SOleg Nesterov #endif
11047e12855SAl Viro 	return membuf_zero(&to, ELF_NGREG * sizeof(unsigned long) -
1117c1f8db0SChristophe Leroy 			sizeof(struct user_pt_regs));
1127c1f8db0SChristophe Leroy }
1137c1f8db0SChristophe Leroy 
1147c1f8db0SChristophe Leroy /*
1157c1f8db0SChristophe Leroy  * tm_cgpr_set - set the CGPR registers
1167c1f8db0SChristophe Leroy  * @target:	The target task.
1177c1f8db0SChristophe Leroy  * @regset:	The user regset structure.
1187c1f8db0SChristophe Leroy  * @pos:	The buffer position.
1197c1f8db0SChristophe Leroy  * @count:	Number of bytes to copy.
1207c1f8db0SChristophe Leroy  * @kbuf:	Kernel buffer to copy into.
1217c1f8db0SChristophe Leroy  * @ubuf:	User buffer to copy from.
1227c1f8db0SChristophe Leroy  *
1237c1f8db0SChristophe Leroy  * This function sets in transaction checkpointed GPR registers.
1247c1f8db0SChristophe Leroy  *
1257c1f8db0SChristophe Leroy  * When the transaction is active, 'ckpt_regs' holds the checkpointed
1267c1f8db0SChristophe Leroy  * GPR register values for the current transaction to fall back on if it
1277c1f8db0SChristophe Leroy  * aborts in between. This function sets those checkpointed GPR registers.
1287c1f8db0SChristophe Leroy  * The userspace interface buffer layout is as follows.
1297c1f8db0SChristophe Leroy  *
1307c1f8db0SChristophe Leroy  * struct data {
1317c1f8db0SChristophe Leroy  *	struct pt_regs ckpt_regs;
1327c1f8db0SChristophe Leroy  * };
1337c1f8db0SChristophe Leroy  */
tm_cgpr_set(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,const void * kbuf,const void __user * ubuf)1347c1f8db0SChristophe Leroy int tm_cgpr_set(struct task_struct *target, const struct user_regset *regset,
1357c1f8db0SChristophe Leroy 		unsigned int pos, unsigned int count,
1367c1f8db0SChristophe Leroy 		const void *kbuf, const void __user *ubuf)
1377c1f8db0SChristophe Leroy {
1387c1f8db0SChristophe Leroy 	unsigned long reg;
1397c1f8db0SChristophe Leroy 	int ret;
1407c1f8db0SChristophe Leroy 
1417c1f8db0SChristophe Leroy 	if (!cpu_has_feature(CPU_FTR_TM))
1427c1f8db0SChristophe Leroy 		return -ENODEV;
1437c1f8db0SChristophe Leroy 
1447c1f8db0SChristophe Leroy 	if (!MSR_TM_ACTIVE(target->thread.regs->msr))
1457c1f8db0SChristophe Leroy 		return -ENODATA;
1467c1f8db0SChristophe Leroy 
1477c1f8db0SChristophe Leroy 	flush_tmregs_to_thread(target);
1487c1f8db0SChristophe Leroy 	flush_fp_to_thread(target);
1497c1f8db0SChristophe Leroy 	flush_altivec_to_thread(target);
1507c1f8db0SChristophe Leroy 
1517c1f8db0SChristophe Leroy 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
1527c1f8db0SChristophe Leroy 				 &target->thread.ckpt_regs,
1537c1f8db0SChristophe Leroy 				 0, PT_MSR * sizeof(reg));
1547c1f8db0SChristophe Leroy 
1557c1f8db0SChristophe Leroy 	if (!ret && count > 0) {
1567c1f8db0SChristophe Leroy 		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &reg,
1577c1f8db0SChristophe Leroy 					 PT_MSR * sizeof(reg),
1587c1f8db0SChristophe Leroy 					 (PT_MSR + 1) * sizeof(reg));
1597c1f8db0SChristophe Leroy 		if (!ret)
1607c1f8db0SChristophe Leroy 			ret = set_user_ckpt_msr(target, reg);
1617c1f8db0SChristophe Leroy 	}
1627c1f8db0SChristophe Leroy 
1637c1f8db0SChristophe Leroy 	BUILD_BUG_ON(offsetof(struct pt_regs, orig_gpr3) !=
1647c1f8db0SChristophe Leroy 		     offsetof(struct pt_regs, msr) + sizeof(long));
1657c1f8db0SChristophe Leroy 
1667c1f8db0SChristophe Leroy 	if (!ret)
1677c1f8db0SChristophe Leroy 		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
1687c1f8db0SChristophe Leroy 					 &target->thread.ckpt_regs.orig_gpr3,
1697c1f8db0SChristophe Leroy 					 PT_ORIG_R3 * sizeof(reg),
1707c1f8db0SChristophe Leroy 					 (PT_MAX_PUT_REG + 1) * sizeof(reg));
1717c1f8db0SChristophe Leroy 
1727c1f8db0SChristophe Leroy 	if (PT_MAX_PUT_REG + 1 < PT_TRAP && !ret)
17318b9fe54SSergey Shtylyov 		user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
1747c1f8db0SChristophe Leroy 					  (PT_MAX_PUT_REG + 1) * sizeof(reg),
1757c1f8db0SChristophe Leroy 					  PT_TRAP * sizeof(reg));
1767c1f8db0SChristophe Leroy 
1777c1f8db0SChristophe Leroy 	if (!ret && count > 0) {
1787c1f8db0SChristophe Leroy 		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &reg,
1797c1f8db0SChristophe Leroy 					 PT_TRAP * sizeof(reg),
1807c1f8db0SChristophe Leroy 					 (PT_TRAP + 1) * sizeof(reg));
1817c1f8db0SChristophe Leroy 		if (!ret)
1827c1f8db0SChristophe Leroy 			ret = set_user_ckpt_trap(target, reg);
1837c1f8db0SChristophe Leroy 	}
1847c1f8db0SChristophe Leroy 
1857c1f8db0SChristophe Leroy 	if (!ret)
18618b9fe54SSergey Shtylyov 		user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
1877c1f8db0SChristophe Leroy 					  (PT_TRAP + 1) * sizeof(reg), -1);
1887c1f8db0SChristophe Leroy 
1897c1f8db0SChristophe Leroy 	return ret;
1907c1f8db0SChristophe Leroy }
1917c1f8db0SChristophe Leroy 
1927c1f8db0SChristophe Leroy /**
1937c1f8db0SChristophe Leroy  * tm_cfpr_active - get active number of registers in CFPR
1947c1f8db0SChristophe Leroy  * @target:	The target task.
1957c1f8db0SChristophe Leroy  * @regset:	The user regset structure.
1967c1f8db0SChristophe Leroy  *
1977c1f8db0SChristophe Leroy  * This function checks for the active number of available
1987c1f8db0SChristophe Leroy  * regisers in transaction checkpointed FPR category.
1997c1f8db0SChristophe Leroy  */
tm_cfpr_active(struct task_struct * target,const struct user_regset * regset)2007c1f8db0SChristophe Leroy int tm_cfpr_active(struct task_struct *target, const struct user_regset *regset)
2017c1f8db0SChristophe Leroy {
2027c1f8db0SChristophe Leroy 	if (!cpu_has_feature(CPU_FTR_TM))
2037c1f8db0SChristophe Leroy 		return -ENODEV;
2047c1f8db0SChristophe Leroy 
2057c1f8db0SChristophe Leroy 	if (!MSR_TM_ACTIVE(target->thread.regs->msr))
2067c1f8db0SChristophe Leroy 		return 0;
2077c1f8db0SChristophe Leroy 
2087c1f8db0SChristophe Leroy 	return regset->n;
2097c1f8db0SChristophe Leroy }
2107c1f8db0SChristophe Leroy 
2117c1f8db0SChristophe Leroy /**
2127c1f8db0SChristophe Leroy  * tm_cfpr_get - get CFPR registers
2137c1f8db0SChristophe Leroy  * @target:	The target task.
2147c1f8db0SChristophe Leroy  * @regset:	The user regset structure.
21547e12855SAl Viro  * @to:		Destination of copy.
2167c1f8db0SChristophe Leroy  *
2177c1f8db0SChristophe Leroy  * This function gets in transaction checkpointed FPR registers.
2187c1f8db0SChristophe Leroy  *
2197c1f8db0SChristophe Leroy  * When the transaction is active 'ckfp_state' holds the checkpointed
2207c1f8db0SChristophe Leroy  * values for the current transaction to fall back on if it aborts
2217c1f8db0SChristophe Leroy  * in between. This function gets those checkpointed FPR registers.
2227c1f8db0SChristophe Leroy  * The userspace interface buffer layout is as follows.
2237c1f8db0SChristophe Leroy  *
2247c1f8db0SChristophe Leroy  * struct data {
2257c1f8db0SChristophe Leroy  *	u64	fpr[32];
2267c1f8db0SChristophe Leroy  *	u64	fpscr;
2277c1f8db0SChristophe Leroy  *};
2287c1f8db0SChristophe Leroy  */
tm_cfpr_get(struct task_struct * target,const struct user_regset * regset,struct membuf to)2297c1f8db0SChristophe Leroy int tm_cfpr_get(struct task_struct *target, const struct user_regset *regset,
23047e12855SAl Viro 		struct membuf to)
2317c1f8db0SChristophe Leroy {
2327c1f8db0SChristophe Leroy 	u64 buf[33];
2337c1f8db0SChristophe Leroy 	int i;
2347c1f8db0SChristophe Leroy 
2357c1f8db0SChristophe Leroy 	if (!cpu_has_feature(CPU_FTR_TM))
2367c1f8db0SChristophe Leroy 		return -ENODEV;
2377c1f8db0SChristophe Leroy 
2387c1f8db0SChristophe Leroy 	if (!MSR_TM_ACTIVE(target->thread.regs->msr))
2397c1f8db0SChristophe Leroy 		return -ENODATA;
2407c1f8db0SChristophe Leroy 
2417c1f8db0SChristophe Leroy 	flush_tmregs_to_thread(target);
2427c1f8db0SChristophe Leroy 	flush_fp_to_thread(target);
2437c1f8db0SChristophe Leroy 	flush_altivec_to_thread(target);
2447c1f8db0SChristophe Leroy 
2457c1f8db0SChristophe Leroy 	/* copy to local buffer then write that out */
2467c1f8db0SChristophe Leroy 	for (i = 0; i < 32 ; i++)
2477c1f8db0SChristophe Leroy 		buf[i] = target->thread.TS_CKFPR(i);
2487c1f8db0SChristophe Leroy 	buf[32] = target->thread.ckfp_state.fpscr;
24947e12855SAl Viro 	return membuf_write(&to, buf, sizeof(buf));
2507c1f8db0SChristophe Leroy }
2517c1f8db0SChristophe Leroy 
2527c1f8db0SChristophe Leroy /**
2537c1f8db0SChristophe Leroy  * tm_cfpr_set - set CFPR registers
2547c1f8db0SChristophe Leroy  * @target:	The target task.
2557c1f8db0SChristophe Leroy  * @regset:	The user regset structure.
2567c1f8db0SChristophe Leroy  * @pos:	The buffer position.
2577c1f8db0SChristophe Leroy  * @count:	Number of bytes to copy.
2587c1f8db0SChristophe Leroy  * @kbuf:	Kernel buffer to copy into.
2597c1f8db0SChristophe Leroy  * @ubuf:	User buffer to copy from.
2607c1f8db0SChristophe Leroy  *
2617c1f8db0SChristophe Leroy  * This function sets in transaction checkpointed FPR registers.
2627c1f8db0SChristophe Leroy  *
2637c1f8db0SChristophe Leroy  * When the transaction is active 'ckfp_state' holds the checkpointed
2647c1f8db0SChristophe Leroy  * FPR register values for the current transaction to fall back on
2657c1f8db0SChristophe Leroy  * if it aborts in between. This function sets these checkpointed
2667c1f8db0SChristophe Leroy  * FPR registers. The userspace interface buffer layout is as follows.
2677c1f8db0SChristophe Leroy  *
2687c1f8db0SChristophe Leroy  * struct data {
2697c1f8db0SChristophe Leroy  *	u64	fpr[32];
2707c1f8db0SChristophe Leroy  *	u64	fpscr;
2717c1f8db0SChristophe Leroy  *};
2727c1f8db0SChristophe Leroy  */
tm_cfpr_set(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,const void * kbuf,const void __user * ubuf)2737c1f8db0SChristophe Leroy int tm_cfpr_set(struct task_struct *target, const struct user_regset *regset,
2747c1f8db0SChristophe Leroy 		unsigned int pos, unsigned int count,
2757c1f8db0SChristophe Leroy 		const void *kbuf, const void __user *ubuf)
2767c1f8db0SChristophe Leroy {
2777c1f8db0SChristophe Leroy 	u64 buf[33];
2787c1f8db0SChristophe Leroy 	int i;
2797c1f8db0SChristophe Leroy 
2807c1f8db0SChristophe Leroy 	if (!cpu_has_feature(CPU_FTR_TM))
2817c1f8db0SChristophe Leroy 		return -ENODEV;
2827c1f8db0SChristophe Leroy 
2837c1f8db0SChristophe Leroy 	if (!MSR_TM_ACTIVE(target->thread.regs->msr))
2847c1f8db0SChristophe Leroy 		return -ENODATA;
2857c1f8db0SChristophe Leroy 
2867c1f8db0SChristophe Leroy 	flush_tmregs_to_thread(target);
2877c1f8db0SChristophe Leroy 	flush_fp_to_thread(target);
2887c1f8db0SChristophe Leroy 	flush_altivec_to_thread(target);
2897c1f8db0SChristophe Leroy 
2907c1f8db0SChristophe Leroy 	for (i = 0; i < 32; i++)
2917c1f8db0SChristophe Leroy 		buf[i] = target->thread.TS_CKFPR(i);
2927c1f8db0SChristophe Leroy 	buf[32] = target->thread.ckfp_state.fpscr;
2937c1f8db0SChristophe Leroy 
2947c1f8db0SChristophe Leroy 	/* copy to local buffer then write that out */
2957c1f8db0SChristophe Leroy 	i = user_regset_copyin(&pos, &count, &kbuf, &ubuf, buf, 0, -1);
2967c1f8db0SChristophe Leroy 	if (i)
2977c1f8db0SChristophe Leroy 		return i;
2987c1f8db0SChristophe Leroy 	for (i = 0; i < 32 ; i++)
2997c1f8db0SChristophe Leroy 		target->thread.TS_CKFPR(i) = buf[i];
3007c1f8db0SChristophe Leroy 	target->thread.ckfp_state.fpscr = buf[32];
3017c1f8db0SChristophe Leroy 	return 0;
3027c1f8db0SChristophe Leroy }
3037c1f8db0SChristophe Leroy 
3047c1f8db0SChristophe Leroy /**
3057c1f8db0SChristophe Leroy  * tm_cvmx_active - get active number of registers in CVMX
3067c1f8db0SChristophe Leroy  * @target:	The target task.
3077c1f8db0SChristophe Leroy  * @regset:	The user regset structure.
3087c1f8db0SChristophe Leroy  *
3097c1f8db0SChristophe Leroy  * This function checks for the active number of available
3107c1f8db0SChristophe Leroy  * regisers in checkpointed VMX category.
3117c1f8db0SChristophe Leroy  */
tm_cvmx_active(struct task_struct * target,const struct user_regset * regset)3127c1f8db0SChristophe Leroy int tm_cvmx_active(struct task_struct *target, const struct user_regset *regset)
3137c1f8db0SChristophe Leroy {
3147c1f8db0SChristophe Leroy 	if (!cpu_has_feature(CPU_FTR_TM))
3157c1f8db0SChristophe Leroy 		return -ENODEV;
3167c1f8db0SChristophe Leroy 
3177c1f8db0SChristophe Leroy 	if (!MSR_TM_ACTIVE(target->thread.regs->msr))
3187c1f8db0SChristophe Leroy 		return 0;
3197c1f8db0SChristophe Leroy 
3207c1f8db0SChristophe Leroy 	return regset->n;
3217c1f8db0SChristophe Leroy }
3227c1f8db0SChristophe Leroy 
3237c1f8db0SChristophe Leroy /**
3247c1f8db0SChristophe Leroy  * tm_cvmx_get - get CMVX registers
3257c1f8db0SChristophe Leroy  * @target:	The target task.
3267c1f8db0SChristophe Leroy  * @regset:	The user regset structure.
32747e12855SAl Viro  * @to:		Destination of copy.
3287c1f8db0SChristophe Leroy  *
3297c1f8db0SChristophe Leroy  * This function gets in transaction checkpointed VMX registers.
3307c1f8db0SChristophe Leroy  *
3317c1f8db0SChristophe Leroy  * When the transaction is active 'ckvr_state' and 'ckvrsave' hold
3327c1f8db0SChristophe Leroy  * the checkpointed values for the current transaction to fall
3337c1f8db0SChristophe Leroy  * back on if it aborts in between. The userspace interface buffer
3347c1f8db0SChristophe Leroy  * layout is as follows.
3357c1f8db0SChristophe Leroy  *
3367c1f8db0SChristophe Leroy  * struct data {
3377c1f8db0SChristophe Leroy  *	vector128	vr[32];
3387c1f8db0SChristophe Leroy  *	vector128	vscr;
3397c1f8db0SChristophe Leroy  *	vector128	vrsave;
3407c1f8db0SChristophe Leroy  *};
3417c1f8db0SChristophe Leroy  */
tm_cvmx_get(struct task_struct * target,const struct user_regset * regset,struct membuf to)3427c1f8db0SChristophe Leroy int tm_cvmx_get(struct task_struct *target, const struct user_regset *regset,
34347e12855SAl Viro 		struct membuf to)
3447c1f8db0SChristophe Leroy {
34547e12855SAl Viro 	union {
34647e12855SAl Viro 		elf_vrreg_t reg;
34747e12855SAl Viro 		u32 word;
34847e12855SAl Viro 	} vrsave;
3497c1f8db0SChristophe Leroy 	BUILD_BUG_ON(TVSO(vscr) != TVSO(vr[32]));
3507c1f8db0SChristophe Leroy 
3517c1f8db0SChristophe Leroy 	if (!cpu_has_feature(CPU_FTR_TM))
3527c1f8db0SChristophe Leroy 		return -ENODEV;
3537c1f8db0SChristophe Leroy 
3547c1f8db0SChristophe Leroy 	if (!MSR_TM_ACTIVE(target->thread.regs->msr))
3557c1f8db0SChristophe Leroy 		return -ENODATA;
3567c1f8db0SChristophe Leroy 
3577c1f8db0SChristophe Leroy 	/* Flush the state */
3587c1f8db0SChristophe Leroy 	flush_tmregs_to_thread(target);
3597c1f8db0SChristophe Leroy 	flush_fp_to_thread(target);
3607c1f8db0SChristophe Leroy 	flush_altivec_to_thread(target);
3617c1f8db0SChristophe Leroy 
36247e12855SAl Viro 	membuf_write(&to, &target->thread.ckvr_state, 33 * sizeof(vector128));
3637c1f8db0SChristophe Leroy 	/*
3647c1f8db0SChristophe Leroy 	 * Copy out only the low-order word of vrsave.
3657c1f8db0SChristophe Leroy 	 */
3667c1f8db0SChristophe Leroy 	memset(&vrsave, 0, sizeof(vrsave));
3677c1f8db0SChristophe Leroy 	vrsave.word = target->thread.ckvrsave;
36847e12855SAl Viro 	return membuf_write(&to, &vrsave, sizeof(vrsave));
3697c1f8db0SChristophe Leroy }
3707c1f8db0SChristophe Leroy 
3717c1f8db0SChristophe Leroy /**
3727c1f8db0SChristophe Leroy  * tm_cvmx_set - set CMVX registers
3737c1f8db0SChristophe Leroy  * @target:	The target task.
3747c1f8db0SChristophe Leroy  * @regset:	The user regset structure.
3757c1f8db0SChristophe Leroy  * @pos:	The buffer position.
3767c1f8db0SChristophe Leroy  * @count:	Number of bytes to copy.
3777c1f8db0SChristophe Leroy  * @kbuf:	Kernel buffer to copy into.
3787c1f8db0SChristophe Leroy  * @ubuf:	User buffer to copy from.
3797c1f8db0SChristophe Leroy  *
3807c1f8db0SChristophe Leroy  * This function sets in transaction checkpointed VMX registers.
3817c1f8db0SChristophe Leroy  *
3827c1f8db0SChristophe Leroy  * When the transaction is active 'ckvr_state' and 'ckvrsave' hold
3837c1f8db0SChristophe Leroy  * the checkpointed values for the current transaction to fall
3847c1f8db0SChristophe Leroy  * back on if it aborts in between. The userspace interface buffer
3857c1f8db0SChristophe Leroy  * layout is as follows.
3867c1f8db0SChristophe Leroy  *
3877c1f8db0SChristophe Leroy  * struct data {
3887c1f8db0SChristophe Leroy  *	vector128	vr[32];
3897c1f8db0SChristophe Leroy  *	vector128	vscr;
3907c1f8db0SChristophe Leroy  *	vector128	vrsave;
3917c1f8db0SChristophe Leroy  *};
3927c1f8db0SChristophe Leroy  */
tm_cvmx_set(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,const void * kbuf,const void __user * ubuf)3937c1f8db0SChristophe Leroy int tm_cvmx_set(struct task_struct *target, const struct user_regset *regset,
3947c1f8db0SChristophe Leroy 		unsigned int pos, unsigned int count,
3957c1f8db0SChristophe Leroy 		const void *kbuf, const void __user *ubuf)
3967c1f8db0SChristophe Leroy {
3977c1f8db0SChristophe Leroy 	int ret;
3987c1f8db0SChristophe Leroy 
3997c1f8db0SChristophe Leroy 	BUILD_BUG_ON(TVSO(vscr) != TVSO(vr[32]));
4007c1f8db0SChristophe Leroy 
4017c1f8db0SChristophe Leroy 	if (!cpu_has_feature(CPU_FTR_TM))
4027c1f8db0SChristophe Leroy 		return -ENODEV;
4037c1f8db0SChristophe Leroy 
4047c1f8db0SChristophe Leroy 	if (!MSR_TM_ACTIVE(target->thread.regs->msr))
4057c1f8db0SChristophe Leroy 		return -ENODATA;
4067c1f8db0SChristophe Leroy 
4077c1f8db0SChristophe Leroy 	flush_tmregs_to_thread(target);
4087c1f8db0SChristophe Leroy 	flush_fp_to_thread(target);
4097c1f8db0SChristophe Leroy 	flush_altivec_to_thread(target);
4107c1f8db0SChristophe Leroy 
4117c1f8db0SChristophe Leroy 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &target->thread.ckvr_state,
4127c1f8db0SChristophe Leroy 				 0, 33 * sizeof(vector128));
4137c1f8db0SChristophe Leroy 	if (!ret && count > 0) {
4147c1f8db0SChristophe Leroy 		/*
4157c1f8db0SChristophe Leroy 		 * We use only the low-order word of vrsave.
4167c1f8db0SChristophe Leroy 		 */
4177c1f8db0SChristophe Leroy 		union {
4187c1f8db0SChristophe Leroy 			elf_vrreg_t reg;
4197c1f8db0SChristophe Leroy 			u32 word;
4207c1f8db0SChristophe Leroy 		} vrsave;
4217c1f8db0SChristophe Leroy 		memset(&vrsave, 0, sizeof(vrsave));
4227c1f8db0SChristophe Leroy 		vrsave.word = target->thread.ckvrsave;
4237c1f8db0SChristophe Leroy 		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &vrsave,
4247c1f8db0SChristophe Leroy 					 33 * sizeof(vector128), -1);
4257c1f8db0SChristophe Leroy 		if (!ret)
4267c1f8db0SChristophe Leroy 			target->thread.ckvrsave = vrsave.word;
4277c1f8db0SChristophe Leroy 	}
4287c1f8db0SChristophe Leroy 
4297c1f8db0SChristophe Leroy 	return ret;
4307c1f8db0SChristophe Leroy }
4317c1f8db0SChristophe Leroy 
4327c1f8db0SChristophe Leroy /**
4337c1f8db0SChristophe Leroy  * tm_cvsx_active - get active number of registers in CVSX
4347c1f8db0SChristophe Leroy  * @target:	The target task.
4357c1f8db0SChristophe Leroy  * @regset:	The user regset structure.
4367c1f8db0SChristophe Leroy  *
4377c1f8db0SChristophe Leroy  * This function checks for the active number of available
4387c1f8db0SChristophe Leroy  * regisers in transaction checkpointed VSX category.
4397c1f8db0SChristophe Leroy  */
tm_cvsx_active(struct task_struct * target,const struct user_regset * regset)4407c1f8db0SChristophe Leroy int tm_cvsx_active(struct task_struct *target, const struct user_regset *regset)
4417c1f8db0SChristophe Leroy {
4427c1f8db0SChristophe Leroy 	if (!cpu_has_feature(CPU_FTR_TM))
4437c1f8db0SChristophe Leroy 		return -ENODEV;
4447c1f8db0SChristophe Leroy 
4457c1f8db0SChristophe Leroy 	if (!MSR_TM_ACTIVE(target->thread.regs->msr))
4467c1f8db0SChristophe Leroy 		return 0;
4477c1f8db0SChristophe Leroy 
4487c1f8db0SChristophe Leroy 	flush_vsx_to_thread(target);
4497c1f8db0SChristophe Leroy 	return target->thread.used_vsr ? regset->n : 0;
4507c1f8db0SChristophe Leroy }
4517c1f8db0SChristophe Leroy 
4527c1f8db0SChristophe Leroy /**
4537c1f8db0SChristophe Leroy  * tm_cvsx_get - get CVSX registers
4547c1f8db0SChristophe Leroy  * @target:	The target task.
4557c1f8db0SChristophe Leroy  * @regset:	The user regset structure.
45647e12855SAl Viro  * @to:		Destination of copy.
4577c1f8db0SChristophe Leroy  *
4587c1f8db0SChristophe Leroy  * This function gets in transaction checkpointed VSX registers.
4597c1f8db0SChristophe Leroy  *
4607c1f8db0SChristophe Leroy  * When the transaction is active 'ckfp_state' holds the checkpointed
4617c1f8db0SChristophe Leroy  * values for the current transaction to fall back on if it aborts
4627c1f8db0SChristophe Leroy  * in between. This function gets those checkpointed VSX registers.
4637c1f8db0SChristophe Leroy  * The userspace interface buffer layout is as follows.
4647c1f8db0SChristophe Leroy  *
4657c1f8db0SChristophe Leroy  * struct data {
4667c1f8db0SChristophe Leroy  *	u64	vsx[32];
4677c1f8db0SChristophe Leroy  *};
4687c1f8db0SChristophe Leroy  */
tm_cvsx_get(struct task_struct * target,const struct user_regset * regset,struct membuf to)4697c1f8db0SChristophe Leroy int tm_cvsx_get(struct task_struct *target, const struct user_regset *regset,
47047e12855SAl Viro 		struct membuf to)
4717c1f8db0SChristophe Leroy {
4727c1f8db0SChristophe Leroy 	u64 buf[32];
47347e12855SAl Viro 	int i;
4747c1f8db0SChristophe Leroy 
4757c1f8db0SChristophe Leroy 	if (!cpu_has_feature(CPU_FTR_TM))
4767c1f8db0SChristophe Leroy 		return -ENODEV;
4777c1f8db0SChristophe Leroy 
4787c1f8db0SChristophe Leroy 	if (!MSR_TM_ACTIVE(target->thread.regs->msr))
4797c1f8db0SChristophe Leroy 		return -ENODATA;
4807c1f8db0SChristophe Leroy 
4817c1f8db0SChristophe Leroy 	/* Flush the state */
4827c1f8db0SChristophe Leroy 	flush_tmregs_to_thread(target);
4837c1f8db0SChristophe Leroy 	flush_fp_to_thread(target);
4847c1f8db0SChristophe Leroy 	flush_altivec_to_thread(target);
4857c1f8db0SChristophe Leroy 	flush_vsx_to_thread(target);
4867c1f8db0SChristophe Leroy 
4877c1f8db0SChristophe Leroy 	for (i = 0; i < 32 ; i++)
4887c1f8db0SChristophe Leroy 		buf[i] = target->thread.ckfp_state.fpr[i][TS_VSRLOWOFFSET];
48947e12855SAl Viro 	return membuf_write(&to, buf, 32 * sizeof(double));
4907c1f8db0SChristophe Leroy }
4917c1f8db0SChristophe Leroy 
4927c1f8db0SChristophe Leroy /**
4937c1f8db0SChristophe Leroy  * tm_cvsx_set - set CFPR registers
4947c1f8db0SChristophe Leroy  * @target:	The target task.
4957c1f8db0SChristophe Leroy  * @regset:	The user regset structure.
4967c1f8db0SChristophe Leroy  * @pos:	The buffer position.
4977c1f8db0SChristophe Leroy  * @count:	Number of bytes to copy.
4987c1f8db0SChristophe Leroy  * @kbuf:	Kernel buffer to copy into.
4997c1f8db0SChristophe Leroy  * @ubuf:	User buffer to copy from.
5007c1f8db0SChristophe Leroy  *
5017c1f8db0SChristophe Leroy  * This function sets in transaction checkpointed VSX registers.
5027c1f8db0SChristophe Leroy  *
5037c1f8db0SChristophe Leroy  * When the transaction is active 'ckfp_state' holds the checkpointed
5047c1f8db0SChristophe Leroy  * VSX register values for the current transaction to fall back on
5057c1f8db0SChristophe Leroy  * if it aborts in between. This function sets these checkpointed
5067c1f8db0SChristophe Leroy  * FPR registers. The userspace interface buffer layout is as follows.
5077c1f8db0SChristophe Leroy  *
5087c1f8db0SChristophe Leroy  * struct data {
5097c1f8db0SChristophe Leroy  *	u64	vsx[32];
5107c1f8db0SChristophe Leroy  *};
5117c1f8db0SChristophe Leroy  */
tm_cvsx_set(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,const void * kbuf,const void __user * ubuf)5127c1f8db0SChristophe Leroy int tm_cvsx_set(struct task_struct *target, const struct user_regset *regset,
5137c1f8db0SChristophe Leroy 		unsigned int pos, unsigned int count,
5147c1f8db0SChristophe Leroy 		const void *kbuf, const void __user *ubuf)
5157c1f8db0SChristophe Leroy {
5167c1f8db0SChristophe Leroy 	u64 buf[32];
5177c1f8db0SChristophe Leroy 	int ret, i;
5187c1f8db0SChristophe Leroy 
5197c1f8db0SChristophe Leroy 	if (!cpu_has_feature(CPU_FTR_TM))
5207c1f8db0SChristophe Leroy 		return -ENODEV;
5217c1f8db0SChristophe Leroy 
5227c1f8db0SChristophe Leroy 	if (!MSR_TM_ACTIVE(target->thread.regs->msr))
5237c1f8db0SChristophe Leroy 		return -ENODATA;
5247c1f8db0SChristophe Leroy 
5257c1f8db0SChristophe Leroy 	/* Flush the state */
5267c1f8db0SChristophe Leroy 	flush_tmregs_to_thread(target);
5277c1f8db0SChristophe Leroy 	flush_fp_to_thread(target);
5287c1f8db0SChristophe Leroy 	flush_altivec_to_thread(target);
5297c1f8db0SChristophe Leroy 	flush_vsx_to_thread(target);
5307c1f8db0SChristophe Leroy 
5317c1f8db0SChristophe Leroy 	for (i = 0; i < 32 ; i++)
5327c1f8db0SChristophe Leroy 		buf[i] = target->thread.ckfp_state.fpr[i][TS_VSRLOWOFFSET];
5337c1f8db0SChristophe Leroy 
5347c1f8db0SChristophe Leroy 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
5357c1f8db0SChristophe Leroy 				 buf, 0, 32 * sizeof(double));
5367c1f8db0SChristophe Leroy 	if (!ret)
5377c1f8db0SChristophe Leroy 		for (i = 0; i < 32 ; i++)
5387c1f8db0SChristophe Leroy 			target->thread.ckfp_state.fpr[i][TS_VSRLOWOFFSET] = buf[i];
5397c1f8db0SChristophe Leroy 
5407c1f8db0SChristophe Leroy 	return ret;
5417c1f8db0SChristophe Leroy }
5427c1f8db0SChristophe Leroy 
5437c1f8db0SChristophe Leroy /**
5447c1f8db0SChristophe Leroy  * tm_spr_active - get active number of registers in TM SPR
5457c1f8db0SChristophe Leroy  * @target:	The target task.
5467c1f8db0SChristophe Leroy  * @regset:	The user regset structure.
5477c1f8db0SChristophe Leroy  *
5487c1f8db0SChristophe Leroy  * This function checks the active number of available
5497c1f8db0SChristophe Leroy  * regisers in the transactional memory SPR category.
5507c1f8db0SChristophe Leroy  */
tm_spr_active(struct task_struct * target,const struct user_regset * regset)5517c1f8db0SChristophe Leroy int tm_spr_active(struct task_struct *target, const struct user_regset *regset)
5527c1f8db0SChristophe Leroy {
5537c1f8db0SChristophe Leroy 	if (!cpu_has_feature(CPU_FTR_TM))
5547c1f8db0SChristophe Leroy 		return -ENODEV;
5557c1f8db0SChristophe Leroy 
5567c1f8db0SChristophe Leroy 	return regset->n;
5577c1f8db0SChristophe Leroy }
5587c1f8db0SChristophe Leroy 
5597c1f8db0SChristophe Leroy /**
5607c1f8db0SChristophe Leroy  * tm_spr_get - get the TM related SPR registers
5617c1f8db0SChristophe Leroy  * @target:	The target task.
5627c1f8db0SChristophe Leroy  * @regset:	The user regset structure.
56347e12855SAl Viro  * @to:		Destination of copy.
5647c1f8db0SChristophe Leroy  *
5657c1f8db0SChristophe Leroy  * This function gets transactional memory related SPR registers.
5667c1f8db0SChristophe Leroy  * The userspace interface buffer layout is as follows.
5677c1f8db0SChristophe Leroy  *
5687c1f8db0SChristophe Leroy  * struct {
5697c1f8db0SChristophe Leroy  *	u64		tm_tfhar;
5707c1f8db0SChristophe Leroy  *	u64		tm_texasr;
5717c1f8db0SChristophe Leroy  *	u64		tm_tfiar;
5727c1f8db0SChristophe Leroy  * };
5737c1f8db0SChristophe Leroy  */
tm_spr_get(struct task_struct * target,const struct user_regset * regset,struct membuf to)5747c1f8db0SChristophe Leroy int tm_spr_get(struct task_struct *target, const struct user_regset *regset,
57547e12855SAl Viro 	       struct membuf to)
5767c1f8db0SChristophe Leroy {
5777c1f8db0SChristophe Leroy 	/* Build tests */
5787c1f8db0SChristophe Leroy 	BUILD_BUG_ON(TSO(tm_tfhar) + sizeof(u64) != TSO(tm_texasr));
5797c1f8db0SChristophe Leroy 	BUILD_BUG_ON(TSO(tm_texasr) + sizeof(u64) != TSO(tm_tfiar));
5807c1f8db0SChristophe Leroy 	BUILD_BUG_ON(TSO(tm_tfiar) + sizeof(u64) != TSO(ckpt_regs));
5817c1f8db0SChristophe Leroy 
5827c1f8db0SChristophe Leroy 	if (!cpu_has_feature(CPU_FTR_TM))
5837c1f8db0SChristophe Leroy 		return -ENODEV;
5847c1f8db0SChristophe Leroy 
5857c1f8db0SChristophe Leroy 	/* Flush the states */
5867c1f8db0SChristophe Leroy 	flush_tmregs_to_thread(target);
5877c1f8db0SChristophe Leroy 	flush_fp_to_thread(target);
5887c1f8db0SChristophe Leroy 	flush_altivec_to_thread(target);
5897c1f8db0SChristophe Leroy 
5907c1f8db0SChristophe Leroy 	/* TFHAR register */
59147e12855SAl Viro 	membuf_write(&to, &target->thread.tm_tfhar, sizeof(u64));
5927c1f8db0SChristophe Leroy 	/* TEXASR register */
59347e12855SAl Viro 	membuf_write(&to, &target->thread.tm_texasr, sizeof(u64));
5947c1f8db0SChristophe Leroy 	/* TFIAR register */
59547e12855SAl Viro 	return membuf_write(&to, &target->thread.tm_tfiar, sizeof(u64));
5967c1f8db0SChristophe Leroy }
5977c1f8db0SChristophe Leroy 
5987c1f8db0SChristophe Leroy /**
5997c1f8db0SChristophe Leroy  * tm_spr_set - set the TM related SPR registers
6007c1f8db0SChristophe Leroy  * @target:	The target task.
6017c1f8db0SChristophe Leroy  * @regset:	The user regset structure.
6027c1f8db0SChristophe Leroy  * @pos:	The buffer position.
6037c1f8db0SChristophe Leroy  * @count:	Number of bytes to copy.
6047c1f8db0SChristophe Leroy  * @kbuf:	Kernel buffer to copy into.
6057c1f8db0SChristophe Leroy  * @ubuf:	User buffer to copy from.
6067c1f8db0SChristophe Leroy  *
6077c1f8db0SChristophe Leroy  * This function sets transactional memory related SPR registers.
6087c1f8db0SChristophe Leroy  * The userspace interface buffer layout is as follows.
6097c1f8db0SChristophe Leroy  *
6107c1f8db0SChristophe Leroy  * struct {
6117c1f8db0SChristophe Leroy  *	u64		tm_tfhar;
6127c1f8db0SChristophe Leroy  *	u64		tm_texasr;
6137c1f8db0SChristophe Leroy  *	u64		tm_tfiar;
6147c1f8db0SChristophe Leroy  * };
6157c1f8db0SChristophe Leroy  */
tm_spr_set(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,const void * kbuf,const void __user * ubuf)6167c1f8db0SChristophe Leroy int tm_spr_set(struct task_struct *target, const struct user_regset *regset,
6177c1f8db0SChristophe Leroy 	       unsigned int pos, unsigned int count,
6187c1f8db0SChristophe Leroy 	       const void *kbuf, const void __user *ubuf)
6197c1f8db0SChristophe Leroy {
6207c1f8db0SChristophe Leroy 	int ret;
6217c1f8db0SChristophe Leroy 
6227c1f8db0SChristophe Leroy 	/* Build tests */
6237c1f8db0SChristophe Leroy 	BUILD_BUG_ON(TSO(tm_tfhar) + sizeof(u64) != TSO(tm_texasr));
6247c1f8db0SChristophe Leroy 	BUILD_BUG_ON(TSO(tm_texasr) + sizeof(u64) != TSO(tm_tfiar));
6257c1f8db0SChristophe Leroy 	BUILD_BUG_ON(TSO(tm_tfiar) + sizeof(u64) != TSO(ckpt_regs));
6267c1f8db0SChristophe Leroy 
6277c1f8db0SChristophe Leroy 	if (!cpu_has_feature(CPU_FTR_TM))
6287c1f8db0SChristophe Leroy 		return -ENODEV;
6297c1f8db0SChristophe Leroy 
6307c1f8db0SChristophe Leroy 	/* Flush the states */
6317c1f8db0SChristophe Leroy 	flush_tmregs_to_thread(target);
6327c1f8db0SChristophe Leroy 	flush_fp_to_thread(target);
6337c1f8db0SChristophe Leroy 	flush_altivec_to_thread(target);
6347c1f8db0SChristophe Leroy 
6357c1f8db0SChristophe Leroy 	/* TFHAR register */
6367c1f8db0SChristophe Leroy 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
6377c1f8db0SChristophe Leroy 				 &target->thread.tm_tfhar, 0, sizeof(u64));
6387c1f8db0SChristophe Leroy 
6397c1f8db0SChristophe Leroy 	/* TEXASR register */
6407c1f8db0SChristophe Leroy 	if (!ret)
6417c1f8db0SChristophe Leroy 		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
6427c1f8db0SChristophe Leroy 					 &target->thread.tm_texasr, sizeof(u64),
6437c1f8db0SChristophe Leroy 					 2 * sizeof(u64));
6447c1f8db0SChristophe Leroy 
6457c1f8db0SChristophe Leroy 	/* TFIAR register */
6467c1f8db0SChristophe Leroy 	if (!ret)
6477c1f8db0SChristophe Leroy 		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
6487c1f8db0SChristophe Leroy 					 &target->thread.tm_tfiar,
6497c1f8db0SChristophe Leroy 					 2 * sizeof(u64), 3 * sizeof(u64));
6507c1f8db0SChristophe Leroy 	return ret;
6517c1f8db0SChristophe Leroy }
6527c1f8db0SChristophe Leroy 
tm_tar_active(struct task_struct * target,const struct user_regset * regset)6537c1f8db0SChristophe Leroy int tm_tar_active(struct task_struct *target, const struct user_regset *regset)
6547c1f8db0SChristophe Leroy {
6557c1f8db0SChristophe Leroy 	if (!cpu_has_feature(CPU_FTR_TM))
6567c1f8db0SChristophe Leroy 		return -ENODEV;
6577c1f8db0SChristophe Leroy 
6587c1f8db0SChristophe Leroy 	if (MSR_TM_ACTIVE(target->thread.regs->msr))
6597c1f8db0SChristophe Leroy 		return regset->n;
6607c1f8db0SChristophe Leroy 
6617c1f8db0SChristophe Leroy 	return 0;
6627c1f8db0SChristophe Leroy }
6637c1f8db0SChristophe Leroy 
tm_tar_get(struct task_struct * target,const struct user_regset * regset,struct membuf to)6647c1f8db0SChristophe Leroy int tm_tar_get(struct task_struct *target, const struct user_regset *regset,
66547e12855SAl Viro 	       struct membuf to)
6667c1f8db0SChristophe Leroy {
6677c1f8db0SChristophe Leroy 	if (!cpu_has_feature(CPU_FTR_TM))
6687c1f8db0SChristophe Leroy 		return -ENODEV;
6697c1f8db0SChristophe Leroy 
6707c1f8db0SChristophe Leroy 	if (!MSR_TM_ACTIVE(target->thread.regs->msr))
6717c1f8db0SChristophe Leroy 		return -ENODATA;
6727c1f8db0SChristophe Leroy 
67347e12855SAl Viro 	return membuf_write(&to, &target->thread.tm_tar, sizeof(u64));
6747c1f8db0SChristophe Leroy }
6757c1f8db0SChristophe Leroy 
tm_tar_set(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,const void * kbuf,const void __user * ubuf)6767c1f8db0SChristophe Leroy int tm_tar_set(struct task_struct *target, const struct user_regset *regset,
6777c1f8db0SChristophe Leroy 	       unsigned int pos, unsigned int count,
6787c1f8db0SChristophe Leroy 	       const void *kbuf, const void __user *ubuf)
6797c1f8db0SChristophe Leroy {
6807c1f8db0SChristophe Leroy 	int ret;
6817c1f8db0SChristophe Leroy 
6827c1f8db0SChristophe Leroy 	if (!cpu_has_feature(CPU_FTR_TM))
6837c1f8db0SChristophe Leroy 		return -ENODEV;
6847c1f8db0SChristophe Leroy 
6857c1f8db0SChristophe Leroy 	if (!MSR_TM_ACTIVE(target->thread.regs->msr))
6867c1f8db0SChristophe Leroy 		return -ENODATA;
6877c1f8db0SChristophe Leroy 
6887c1f8db0SChristophe Leroy 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
6897c1f8db0SChristophe Leroy 				 &target->thread.tm_tar, 0, sizeof(u64));
6907c1f8db0SChristophe Leroy 	return ret;
6917c1f8db0SChristophe Leroy }
6927c1f8db0SChristophe Leroy 
tm_ppr_active(struct task_struct * target,const struct user_regset * regset)6937c1f8db0SChristophe Leroy int tm_ppr_active(struct task_struct *target, const struct user_regset *regset)
6947c1f8db0SChristophe Leroy {
6957c1f8db0SChristophe Leroy 	if (!cpu_has_feature(CPU_FTR_TM))
6967c1f8db0SChristophe Leroy 		return -ENODEV;
6977c1f8db0SChristophe Leroy 
6987c1f8db0SChristophe Leroy 	if (MSR_TM_ACTIVE(target->thread.regs->msr))
6997c1f8db0SChristophe Leroy 		return regset->n;
7007c1f8db0SChristophe Leroy 
7017c1f8db0SChristophe Leroy 	return 0;
7027c1f8db0SChristophe Leroy }
7037c1f8db0SChristophe Leroy 
7047c1f8db0SChristophe Leroy 
tm_ppr_get(struct task_struct * target,const struct user_regset * regset,struct membuf to)7057c1f8db0SChristophe Leroy int tm_ppr_get(struct task_struct *target, const struct user_regset *regset,
70647e12855SAl Viro 	       struct membuf to)
7077c1f8db0SChristophe Leroy {
7087c1f8db0SChristophe Leroy 	if (!cpu_has_feature(CPU_FTR_TM))
7097c1f8db0SChristophe Leroy 		return -ENODEV;
7107c1f8db0SChristophe Leroy 
7117c1f8db0SChristophe Leroy 	if (!MSR_TM_ACTIVE(target->thread.regs->msr))
7127c1f8db0SChristophe Leroy 		return -ENODATA;
7137c1f8db0SChristophe Leroy 
71447e12855SAl Viro 	return membuf_write(&to, &target->thread.tm_ppr, sizeof(u64));
7157c1f8db0SChristophe Leroy }
7167c1f8db0SChristophe Leroy 
tm_ppr_set(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,const void * kbuf,const void __user * ubuf)7177c1f8db0SChristophe Leroy int tm_ppr_set(struct task_struct *target, const struct user_regset *regset,
7187c1f8db0SChristophe Leroy 	       unsigned int pos, unsigned int count,
7197c1f8db0SChristophe Leroy 	       const void *kbuf, const void __user *ubuf)
7207c1f8db0SChristophe Leroy {
7217c1f8db0SChristophe Leroy 	int ret;
7227c1f8db0SChristophe Leroy 
7237c1f8db0SChristophe Leroy 	if (!cpu_has_feature(CPU_FTR_TM))
7247c1f8db0SChristophe Leroy 		return -ENODEV;
7257c1f8db0SChristophe Leroy 
7267c1f8db0SChristophe Leroy 	if (!MSR_TM_ACTIVE(target->thread.regs->msr))
7277c1f8db0SChristophe Leroy 		return -ENODATA;
7287c1f8db0SChristophe Leroy 
7297c1f8db0SChristophe Leroy 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
7307c1f8db0SChristophe Leroy 				 &target->thread.tm_ppr, 0, sizeof(u64));
7317c1f8db0SChristophe Leroy 	return ret;
7327c1f8db0SChristophe Leroy }
7337c1f8db0SChristophe Leroy 
tm_dscr_active(struct task_struct * target,const struct user_regset * regset)7347c1f8db0SChristophe Leroy int tm_dscr_active(struct task_struct *target, const struct user_regset *regset)
7357c1f8db0SChristophe Leroy {
7367c1f8db0SChristophe Leroy 	if (!cpu_has_feature(CPU_FTR_TM))
7377c1f8db0SChristophe Leroy 		return -ENODEV;
7387c1f8db0SChristophe Leroy 
7397c1f8db0SChristophe Leroy 	if (MSR_TM_ACTIVE(target->thread.regs->msr))
7407c1f8db0SChristophe Leroy 		return regset->n;
7417c1f8db0SChristophe Leroy 
7427c1f8db0SChristophe Leroy 	return 0;
7437c1f8db0SChristophe Leroy }
7447c1f8db0SChristophe Leroy 
tm_dscr_get(struct task_struct * target,const struct user_regset * regset,struct membuf to)7457c1f8db0SChristophe Leroy int tm_dscr_get(struct task_struct *target, const struct user_regset *regset,
74647e12855SAl Viro 		struct membuf to)
7477c1f8db0SChristophe Leroy {
7487c1f8db0SChristophe Leroy 	if (!cpu_has_feature(CPU_FTR_TM))
7497c1f8db0SChristophe Leroy 		return -ENODEV;
7507c1f8db0SChristophe Leroy 
7517c1f8db0SChristophe Leroy 	if (!MSR_TM_ACTIVE(target->thread.regs->msr))
7527c1f8db0SChristophe Leroy 		return -ENODATA;
7537c1f8db0SChristophe Leroy 
75447e12855SAl Viro 	return membuf_write(&to, &target->thread.tm_dscr, sizeof(u64));
7557c1f8db0SChristophe Leroy }
7567c1f8db0SChristophe Leroy 
tm_dscr_set(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,const void * kbuf,const void __user * ubuf)7577c1f8db0SChristophe Leroy int tm_dscr_set(struct task_struct *target, const struct user_regset *regset,
7587c1f8db0SChristophe Leroy 		unsigned int pos, unsigned int count,
7597c1f8db0SChristophe Leroy 		const void *kbuf, const void __user *ubuf)
7607c1f8db0SChristophe Leroy {
7617c1f8db0SChristophe Leroy 	int ret;
7627c1f8db0SChristophe Leroy 
7637c1f8db0SChristophe Leroy 	if (!cpu_has_feature(CPU_FTR_TM))
7647c1f8db0SChristophe Leroy 		return -ENODEV;
7657c1f8db0SChristophe Leroy 
7667c1f8db0SChristophe Leroy 	if (!MSR_TM_ACTIVE(target->thread.regs->msr))
7677c1f8db0SChristophe Leroy 		return -ENODATA;
7687c1f8db0SChristophe Leroy 
7697c1f8db0SChristophe Leroy 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
7707c1f8db0SChristophe Leroy 				 &target->thread.tm_dscr, 0, sizeof(u64));
7717c1f8db0SChristophe Leroy 	return ret;
7727c1f8db0SChristophe Leroy }
7737c1f8db0SChristophe Leroy 
tm_cgpr32_get(struct task_struct * target,const struct user_regset * regset,struct membuf to)7747c1f8db0SChristophe Leroy int tm_cgpr32_get(struct task_struct *target, const struct user_regset *regset,
77547e12855SAl Viro 		  struct membuf to)
7767c1f8db0SChristophe Leroy {
77747e12855SAl Viro 	gpr32_get_common(target, regset, to,
7787c1f8db0SChristophe Leroy 				&target->thread.ckpt_regs.gpr[0]);
77947e12855SAl Viro 	return membuf_zero(&to, ELF_NGREG * sizeof(u32));
7807c1f8db0SChristophe Leroy }
7817c1f8db0SChristophe Leroy 
tm_cgpr32_set(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,const void * kbuf,const void __user * ubuf)7827c1f8db0SChristophe Leroy int tm_cgpr32_set(struct task_struct *target, const struct user_regset *regset,
7837c1f8db0SChristophe Leroy 		  unsigned int pos, unsigned int count,
7847c1f8db0SChristophe Leroy 		  const void *kbuf, const void __user *ubuf)
7857c1f8db0SChristophe Leroy {
7867c1f8db0SChristophe Leroy 	return gpr32_set_common(target, regset, pos, count, kbuf, ubuf,
7877c1f8db0SChristophe Leroy 				&target->thread.ckpt_regs.gpr[0]);
7887c1f8db0SChristophe Leroy }
789