| /* SPDX-License-Identifier: GPL-2.0 */ | 
 | #ifndef __SPARC_PTRACE_H | 
 | #define __SPARC_PTRACE_H | 
 |  | 
 | #include <uapi/asm/ptrace.h> | 
 |  | 
 | #if defined(__sparc__) && defined(__arch64__) | 
 | #ifndef __ASSEMBLY__ | 
 |  | 
 | #include <linux/compiler.h> | 
 | #include <linux/threads.h> | 
 | #include <asm/switch_to.h> | 
 |  | 
 | static inline int pt_regs_trap_type(struct pt_regs *regs) | 
 | { | 
 | 	return regs->magic & 0x1ff; | 
 | } | 
 |  | 
 | static inline bool pt_regs_is_syscall(struct pt_regs *regs) | 
 | { | 
 | 	return (regs->tstate & TSTATE_SYSCALL); | 
 | } | 
 |  | 
 | static inline bool pt_regs_clear_syscall(struct pt_regs *regs) | 
 | { | 
 | 	return (regs->tstate &= ~TSTATE_SYSCALL); | 
 | } | 
 |  | 
 | #define arch_ptrace_stop_needed(exit_code, info) \ | 
 | ({	flush_user_windows(); \ | 
 | 	get_thread_wsaved() != 0; \ | 
 | }) | 
 |  | 
 | #define arch_ptrace_stop(exit_code, info) \ | 
 | 	synchronize_user_stack() | 
 |  | 
 | #define current_pt_regs() \ | 
 | 	((struct pt_regs *)((unsigned long)current_thread_info() + THREAD_SIZE) - 1) | 
 |  | 
 | struct global_reg_snapshot { | 
 | 	unsigned long		tstate; | 
 | 	unsigned long		tpc; | 
 | 	unsigned long		tnpc; | 
 | 	unsigned long		o7; | 
 | 	unsigned long		i7; | 
 | 	unsigned long		rpc; | 
 | 	struct thread_info	*thread; | 
 | 	unsigned long		pad1; | 
 | }; | 
 |  | 
 | struct global_pmu_snapshot { | 
 | 	unsigned long		pcr[4]; | 
 | 	unsigned long		pic[4]; | 
 | }; | 
 |  | 
 | union global_cpu_snapshot { | 
 | 	struct global_reg_snapshot	reg; | 
 | 	struct global_pmu_snapshot	pmu; | 
 | }; | 
 |  | 
 | extern union global_cpu_snapshot global_cpu_snapshot[NR_CPUS]; | 
 |  | 
 | #define force_successful_syscall_return() set_thread_noerror(1) | 
 | #define user_mode(regs) (!((regs)->tstate & TSTATE_PRIV)) | 
 | #define instruction_pointer(regs) ((regs)->tpc) | 
 | #define instruction_pointer_set(regs, val) do { \ | 
 | 		(regs)->tpc = (val); \ | 
 | 		(regs)->tnpc = (val)+4; \ | 
 | 	} while (0) | 
 | #define user_stack_pointer(regs) ((regs)->u_regs[UREG_FP]) | 
 | static inline int is_syscall_success(struct pt_regs *regs) | 
 | { | 
 | 	return !(regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY)); | 
 | } | 
 |  | 
 | static inline long regs_return_value(struct pt_regs *regs) | 
 | { | 
 | 	return regs->u_regs[UREG_I0]; | 
 | } | 
 | #ifdef CONFIG_SMP | 
 | unsigned long profile_pc(struct pt_regs *); | 
 | #else | 
 | #define profile_pc(regs) instruction_pointer(regs) | 
 | #endif | 
 |  | 
 | #define MAX_REG_OFFSET (offsetof(struct pt_regs, magic)) | 
 |  | 
 | int regs_query_register_offset(const char *name); | 
 | unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n); | 
 |  | 
 | /** | 
 |  * regs_get_register() - get register value from its offset | 
 |  * @regs:	pt_regs from which register value is gotten | 
 |  * @offset:	offset number of the register. | 
 |  * | 
 |  * regs_get_register returns the value of a register whose | 
 |  * offset from @regs. The @offset is the offset of the register | 
 |  * in struct pt_regs. If @offset is bigger than MAX_REG_OFFSET, | 
 |  * this returns 0. | 
 |  */ | 
 | static inline unsigned long regs_get_register(struct pt_regs *regs, | 
 | 					     unsigned long offset) | 
 | { | 
 | 	if (unlikely(offset >= MAX_REG_OFFSET)) | 
 | 		return 0; | 
 | 	if (offset == PT_V9_Y) | 
 | 		return *(unsigned int *)((unsigned long)regs + offset); | 
 | 	return *(unsigned long *)((unsigned long)regs + offset); | 
 | } | 
 |  | 
 | /* Valid only for Kernel mode traps. */ | 
 | static inline unsigned long kernel_stack_pointer(struct pt_regs *regs) | 
 | { | 
 | 	return regs->u_regs[UREG_I6]; | 
 | } | 
 | #else /* __ASSEMBLY__ */ | 
 | #endif /* __ASSEMBLY__ */ | 
 | #else /* (defined(__sparc__) && defined(__arch64__)) */ | 
 | #ifndef __ASSEMBLY__ | 
 | #include <asm/switch_to.h> | 
 |  | 
 | static inline bool pt_regs_is_syscall(struct pt_regs *regs) | 
 | { | 
 | 	return (regs->psr & PSR_SYSCALL); | 
 | } | 
 |  | 
 | static inline bool pt_regs_clear_syscall(struct pt_regs *regs) | 
 | { | 
 | 	return (regs->psr &= ~PSR_SYSCALL); | 
 | } | 
 |  | 
 | #define arch_ptrace_stop_needed(exit_code, info) \ | 
 | ({	flush_user_windows(); \ | 
 | 	current_thread_info()->w_saved != 0;	\ | 
 | }) | 
 |  | 
 | #define arch_ptrace_stop(exit_code, info) \ | 
 | 	synchronize_user_stack() | 
 |  | 
 | #define current_pt_regs() \ | 
 | 	((struct pt_regs *)((unsigned long)current_thread_info() + THREAD_SIZE) - 1) | 
 |  | 
 | #define user_mode(regs) (!((regs)->psr & PSR_PS)) | 
 | #define instruction_pointer(regs) ((regs)->pc) | 
 | #define user_stack_pointer(regs) ((regs)->u_regs[UREG_FP]) | 
 | unsigned long profile_pc(struct pt_regs *); | 
 | #else /* (!__ASSEMBLY__) */ | 
 | #endif /* (!__ASSEMBLY__) */ | 
 | #endif /* (defined(__sparc__) && defined(__arch64__)) */ | 
 | #define STACK_BIAS		2047 | 
 |  | 
 | /* global_reg_snapshot offsets */ | 
 | #define GR_SNAP_TSTATE	0x00 | 
 | #define GR_SNAP_TPC	0x08 | 
 | #define GR_SNAP_TNPC	0x10 | 
 | #define GR_SNAP_O7	0x18 | 
 | #define GR_SNAP_I7	0x20 | 
 | #define GR_SNAP_RPC	0x28 | 
 | #define GR_SNAP_THREAD	0x30 | 
 | #define GR_SNAP_PAD1	0x38 | 
 |  | 
 | #endif /* !(__SPARC_PTRACE_H) */ |