1/* SPDX-License-Identifier: GPL-2.0-only */
2/*
3 * Copyright (C) 2012 Regents of the University of California
4 */
5
6#ifndef _ASM_RISCV_PTRACE_H
7#define _ASM_RISCV_PTRACE_H
8
9#include <uapi/asm/ptrace.h>
10#include <asm/csr.h>
11#include <linux/compiler.h>
12
13#ifndef __ASSEMBLY__
14
15struct pt_regs {
16	unsigned long epc;
17	unsigned long ra;
18	unsigned long sp;
19	unsigned long gp;
20	unsigned long tp;
21	unsigned long t0;
22	unsigned long t1;
23	unsigned long t2;
24	unsigned long s0;
25	unsigned long s1;
26	unsigned long a0;
27	unsigned long a1;
28	unsigned long a2;
29	unsigned long a3;
30	unsigned long a4;
31	unsigned long a5;
32	unsigned long a6;
33	unsigned long a7;
34	unsigned long s2;
35	unsigned long s3;
36	unsigned long s4;
37	unsigned long s5;
38	unsigned long s6;
39	unsigned long s7;
40	unsigned long s8;
41	unsigned long s9;
42	unsigned long s10;
43	unsigned long s11;
44	unsigned long t3;
45	unsigned long t4;
46	unsigned long t5;
47	unsigned long t6;
48	/* Supervisor/Machine CSRs */
49	unsigned long status;
50	unsigned long badaddr;
51	unsigned long cause;
52	/* a0 value before the syscall */
53	unsigned long orig_a0;
54};
55
56#define PTRACE_SYSEMU			0x1f
57#define PTRACE_SYSEMU_SINGLESTEP	0x20
58
59#ifdef CONFIG_64BIT
60#define REG_FMT "%016lx"
61#else
62#define REG_FMT "%08lx"
63#endif
64
65#define user_mode(regs) (((regs)->status & SR_PP) == 0)
66
67#define MAX_REG_OFFSET offsetof(struct pt_regs, orig_a0)
68
69/* Helpers for working with the instruction pointer */
70static inline unsigned long instruction_pointer(struct pt_regs *regs)
71{
72	return regs->epc;
73}
74static inline void instruction_pointer_set(struct pt_regs *regs,
75					   unsigned long val)
76{
77	regs->epc = val;
78}
79
80#define profile_pc(regs) instruction_pointer(regs)
81
82/* Helpers for working with the user stack pointer */
83static inline unsigned long user_stack_pointer(struct pt_regs *regs)
84{
85	return regs->sp;
86}
87static inline void user_stack_pointer_set(struct pt_regs *regs,
88					  unsigned long val)
89{
90	regs->sp =  val;
91}
92
93/* Valid only for Kernel mode traps. */
94static inline unsigned long kernel_stack_pointer(struct pt_regs *regs)
95{
96	return regs->sp;
97}
98
99/* Helpers for working with the frame pointer */
100static inline unsigned long frame_pointer(struct pt_regs *regs)
101{
102	return regs->s0;
103}
104static inline void frame_pointer_set(struct pt_regs *regs,
105				     unsigned long val)
106{
107	regs->s0 = val;
108}
109
110static inline unsigned long regs_return_value(struct pt_regs *regs)
111{
112	return regs->a0;
113}
114
115static inline void regs_set_return_value(struct pt_regs *regs,
116					 unsigned long val)
117{
118	regs->a0 = val;
119}
120
121extern int regs_query_register_offset(const char *name);
122extern unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs,
123					       unsigned int n);
124
125void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
126			   unsigned long frame_pointer);
127
128/**
129 * regs_get_register() - get register value from its offset
130 * @regs:	pt_regs from which register value is gotten
131 * @offset:	offset of the register.
132 *
133 * regs_get_register returns the value of a register whose offset from @regs.
134 * The @offset is the offset of the register in struct pt_regs.
135 * If @offset is bigger than MAX_REG_OFFSET, this returns 0.
136 */
137static inline unsigned long regs_get_register(struct pt_regs *regs,
138					      unsigned int offset)
139{
140	if (unlikely(offset > MAX_REG_OFFSET))
141		return 0;
142
143	return *(unsigned long *)((unsigned long)regs + offset);
144}
145
146/**
147 * regs_get_kernel_argument() - get Nth function argument in kernel
148 * @regs:       pt_regs of that context
149 * @n:          function argument number (start from 0)
150 *
151 * regs_get_argument() returns @n th argument of the function call.
152 *
153 * Note you can get the parameter correctly if the function has no
154 * more than eight arguments.
155 */
156static inline unsigned long regs_get_kernel_argument(struct pt_regs *regs,
157						unsigned int n)
158{
159	static const int nr_reg_arguments = 8;
160	static const unsigned int argument_offs[] = {
161		offsetof(struct pt_regs, a0),
162		offsetof(struct pt_regs, a1),
163		offsetof(struct pt_regs, a2),
164		offsetof(struct pt_regs, a3),
165		offsetof(struct pt_regs, a4),
166		offsetof(struct pt_regs, a5),
167		offsetof(struct pt_regs, a6),
168		offsetof(struct pt_regs, a7),
169	};
170
171	if (n < nr_reg_arguments)
172		return regs_get_register(regs, argument_offs[n]);
173	return 0;
174}
175
176static inline int regs_irqs_disabled(struct pt_regs *regs)
177{
178	return !(regs->status & SR_PIE);
179}
180
181#endif /* __ASSEMBLY__ */
182
183#endif /* _ASM_RISCV_PTRACE_H */
184