Merge branch 'for-5.13/warnings' into for-linus
[linux-2.6-microblaze.git] / arch / riscv / kernel / ptrace.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright 2010 Tilera Corporation. All Rights Reserved.
4  * Copyright 2015 Regents of the University of California
5  * Copyright 2017 SiFive
6  *
7  * Copied from arch/tile/kernel/ptrace.c
8  */
9
10 #include <asm/ptrace.h>
11 #include <asm/syscall.h>
12 #include <asm/thread_info.h>
13 #include <linux/audit.h>
14 #include <linux/ptrace.h>
15 #include <linux/elf.h>
16 #include <linux/regset.h>
17 #include <linux/sched.h>
18 #include <linux/sched/task_stack.h>
19 #include <linux/tracehook.h>
20
21 #define CREATE_TRACE_POINTS
22 #include <trace/events/syscalls.h>
23
24 enum riscv_regset {
25         REGSET_X,
26 #ifdef CONFIG_FPU
27         REGSET_F,
28 #endif
29 };
30
31 static int riscv_gpr_get(struct task_struct *target,
32                          const struct user_regset *regset,
33                          struct membuf to)
34 {
35         return membuf_write(&to, task_pt_regs(target),
36                             sizeof(struct user_regs_struct));
37 }
38
39 static int riscv_gpr_set(struct task_struct *target,
40                          const struct user_regset *regset,
41                          unsigned int pos, unsigned int count,
42                          const void *kbuf, const void __user *ubuf)
43 {
44         int ret;
45         struct pt_regs *regs;
46
47         regs = task_pt_regs(target);
48         ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, regs, 0, -1);
49         return ret;
50 }
51
52 #ifdef CONFIG_FPU
53 static int riscv_fpr_get(struct task_struct *target,
54                          const struct user_regset *regset,
55                          struct membuf to)
56 {
57         struct __riscv_d_ext_state *fstate = &target->thread.fstate;
58
59         membuf_write(&to, fstate, offsetof(struct __riscv_d_ext_state, fcsr));
60         membuf_store(&to, fstate->fcsr);
61         return membuf_zero(&to, 4);     // explicitly pad
62 }
63
64 static int riscv_fpr_set(struct task_struct *target,
65                          const struct user_regset *regset,
66                          unsigned int pos, unsigned int count,
67                          const void *kbuf, const void __user *ubuf)
68 {
69         int ret;
70         struct __riscv_d_ext_state *fstate = &target->thread.fstate;
71
72         ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, fstate, 0,
73                                  offsetof(struct __riscv_d_ext_state, fcsr));
74         if (!ret) {
75                 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, fstate, 0,
76                                          offsetof(struct __riscv_d_ext_state, fcsr) +
77                                          sizeof(fstate->fcsr));
78         }
79
80         return ret;
81 }
82 #endif
83
84 static const struct user_regset riscv_user_regset[] = {
85         [REGSET_X] = {
86                 .core_note_type = NT_PRSTATUS,
87                 .n = ELF_NGREG,
88                 .size = sizeof(elf_greg_t),
89                 .align = sizeof(elf_greg_t),
90                 .regset_get = riscv_gpr_get,
91                 .set = riscv_gpr_set,
92         },
93 #ifdef CONFIG_FPU
94         [REGSET_F] = {
95                 .core_note_type = NT_PRFPREG,
96                 .n = ELF_NFPREG,
97                 .size = sizeof(elf_fpreg_t),
98                 .align = sizeof(elf_fpreg_t),
99                 .regset_get = riscv_fpr_get,
100                 .set = riscv_fpr_set,
101         },
102 #endif
103 };
104
105 static const struct user_regset_view riscv_user_native_view = {
106         .name = "riscv",
107         .e_machine = EM_RISCV,
108         .regsets = riscv_user_regset,
109         .n = ARRAY_SIZE(riscv_user_regset),
110 };
111
112 const struct user_regset_view *task_user_regset_view(struct task_struct *task)
113 {
114         return &riscv_user_native_view;
115 }
116
117 struct pt_regs_offset {
118         const char *name;
119         int offset;
120 };
121
122 #define REG_OFFSET_NAME(r) {.name = #r, .offset = offsetof(struct pt_regs, r)}
123 #define REG_OFFSET_END {.name = NULL, .offset = 0}
124
125 static const struct pt_regs_offset regoffset_table[] = {
126         REG_OFFSET_NAME(epc),
127         REG_OFFSET_NAME(ra),
128         REG_OFFSET_NAME(sp),
129         REG_OFFSET_NAME(gp),
130         REG_OFFSET_NAME(tp),
131         REG_OFFSET_NAME(t0),
132         REG_OFFSET_NAME(t1),
133         REG_OFFSET_NAME(t2),
134         REG_OFFSET_NAME(s0),
135         REG_OFFSET_NAME(s1),
136         REG_OFFSET_NAME(a0),
137         REG_OFFSET_NAME(a1),
138         REG_OFFSET_NAME(a2),
139         REG_OFFSET_NAME(a3),
140         REG_OFFSET_NAME(a4),
141         REG_OFFSET_NAME(a5),
142         REG_OFFSET_NAME(a6),
143         REG_OFFSET_NAME(a7),
144         REG_OFFSET_NAME(s2),
145         REG_OFFSET_NAME(s3),
146         REG_OFFSET_NAME(s4),
147         REG_OFFSET_NAME(s5),
148         REG_OFFSET_NAME(s6),
149         REG_OFFSET_NAME(s7),
150         REG_OFFSET_NAME(s8),
151         REG_OFFSET_NAME(s9),
152         REG_OFFSET_NAME(s10),
153         REG_OFFSET_NAME(s11),
154         REG_OFFSET_NAME(t3),
155         REG_OFFSET_NAME(t4),
156         REG_OFFSET_NAME(t5),
157         REG_OFFSET_NAME(t6),
158         REG_OFFSET_NAME(status),
159         REG_OFFSET_NAME(badaddr),
160         REG_OFFSET_NAME(cause),
161         REG_OFFSET_NAME(orig_a0),
162         REG_OFFSET_END,
163 };
164
165 /**
166  * regs_query_register_offset() - query register offset from its name
167  * @name:       the name of a register
168  *
169  * regs_query_register_offset() returns the offset of a register in struct
170  * pt_regs from its name. If the name is invalid, this returns -EINVAL;
171  */
172 int regs_query_register_offset(const char *name)
173 {
174         const struct pt_regs_offset *roff;
175
176         for (roff = regoffset_table; roff->name != NULL; roff++)
177                 if (!strcmp(roff->name, name))
178                         return roff->offset;
179         return -EINVAL;
180 }
181
182 /**
183  * regs_within_kernel_stack() - check the address in the stack
184  * @regs:      pt_regs which contains kernel stack pointer.
185  * @addr:      address which is checked.
186  *
187  * regs_within_kernel_stack() checks @addr is within the kernel stack page(s).
188  * If @addr is within the kernel stack, it returns true. If not, returns false.
189  */
190 static bool regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr)
191 {
192         return (addr & ~(THREAD_SIZE - 1))  ==
193                 (kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1));
194 }
195
196 /**
197  * regs_get_kernel_stack_nth() - get Nth entry of the stack
198  * @regs:       pt_regs which contains kernel stack pointer.
199  * @n:          stack entry number.
200  *
201  * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which
202  * is specified by @regs. If the @n th entry is NOT in the kernel stack,
203  * this returns 0.
204  */
205 unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n)
206 {
207         unsigned long *addr = (unsigned long *)kernel_stack_pointer(regs);
208
209         addr += n;
210         if (regs_within_kernel_stack(regs, (unsigned long)addr))
211                 return *addr;
212         else
213                 return 0;
214 }
215
216 void ptrace_disable(struct task_struct *child)
217 {
218         clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
219 }
220
221 long arch_ptrace(struct task_struct *child, long request,
222                  unsigned long addr, unsigned long data)
223 {
224         long ret = -EIO;
225
226         switch (request) {
227         default:
228                 ret = ptrace_request(child, request, addr, data);
229                 break;
230         }
231
232         return ret;
233 }
234
235 /*
236  * Allows PTRACE_SYSCALL to work.  These are called from entry.S in
237  * {handle,ret_from}_syscall.
238  */
239 __visible int do_syscall_trace_enter(struct pt_regs *regs)
240 {
241         if (test_thread_flag(TIF_SYSCALL_TRACE))
242                 if (tracehook_report_syscall_entry(regs))
243                         return -1;
244
245         /*
246          * Do the secure computing after ptrace; failures should be fast.
247          * If this fails we might have return value in a0 from seccomp
248          * (via SECCOMP_RET_ERRNO/TRACE).
249          */
250         if (secure_computing() == -1)
251                 return -1;
252
253 #ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS
254         if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
255                 trace_sys_enter(regs, syscall_get_nr(current, regs));
256 #endif
257
258         audit_syscall_entry(regs->a7, regs->a0, regs->a1, regs->a2, regs->a3);
259         return 0;
260 }
261
262 __visible void do_syscall_trace_exit(struct pt_regs *regs)
263 {
264         audit_syscall_exit(regs);
265
266         if (test_thread_flag(TIF_SYSCALL_TRACE))
267                 tracehook_report_syscall_exit(regs, 0);
268
269 #ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS
270         if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
271                 trace_sys_exit(regs, regs_return_value(regs));
272 #endif
273 }