]> Git Repo - linux.git/blob - arch/riscv/kernel/ptrace.c
Merge tag 'amd-drm-next-6.5-2023-06-09' of https://gitlab.freedesktop.org/agd5f/linux...
[linux.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 <asm/switch_to.h>
14 #include <linux/audit.h>
15 #include <linux/compat.h>
16 #include <linux/ptrace.h>
17 #include <linux/elf.h>
18 #include <linux/regset.h>
19 #include <linux/sched.h>
20 #include <linux/sched/task_stack.h>
21
22 enum riscv_regset {
23         REGSET_X,
24 #ifdef CONFIG_FPU
25         REGSET_F,
26 #endif
27 };
28
29 static int riscv_gpr_get(struct task_struct *target,
30                          const struct user_regset *regset,
31                          struct membuf to)
32 {
33         return membuf_write(&to, task_pt_regs(target),
34                             sizeof(struct user_regs_struct));
35 }
36
37 static int riscv_gpr_set(struct task_struct *target,
38                          const struct user_regset *regset,
39                          unsigned int pos, unsigned int count,
40                          const void *kbuf, const void __user *ubuf)
41 {
42         struct pt_regs *regs;
43
44         regs = task_pt_regs(target);
45         return user_regset_copyin(&pos, &count, &kbuf, &ubuf, regs, 0, -1);
46 }
47
48 #ifdef CONFIG_FPU
49 static int riscv_fpr_get(struct task_struct *target,
50                          const struct user_regset *regset,
51                          struct membuf to)
52 {
53         struct __riscv_d_ext_state *fstate = &target->thread.fstate;
54
55         if (target == current)
56                 fstate_save(current, task_pt_regs(current));
57
58         membuf_write(&to, fstate, offsetof(struct __riscv_d_ext_state, fcsr));
59         membuf_store(&to, fstate->fcsr);
60         return membuf_zero(&to, 4);     // explicitly pad
61 }
62
63 static int riscv_fpr_set(struct task_struct *target,
64                          const struct user_regset *regset,
65                          unsigned int pos, unsigned int count,
66                          const void *kbuf, const void __user *ubuf)
67 {
68         int ret;
69         struct __riscv_d_ext_state *fstate = &target->thread.fstate;
70
71         ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, fstate, 0,
72                                  offsetof(struct __riscv_d_ext_state, fcsr));
73         if (!ret) {
74                 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, fstate, 0,
75                                          offsetof(struct __riscv_d_ext_state, fcsr) +
76                                          sizeof(fstate->fcsr));
77         }
78
79         return ret;
80 }
81 #endif
82
83 static const struct user_regset riscv_user_regset[] = {
84         [REGSET_X] = {
85                 .core_note_type = NT_PRSTATUS,
86                 .n = ELF_NGREG,
87                 .size = sizeof(elf_greg_t),
88                 .align = sizeof(elf_greg_t),
89                 .regset_get = riscv_gpr_get,
90                 .set = riscv_gpr_set,
91         },
92 #ifdef CONFIG_FPU
93         [REGSET_F] = {
94                 .core_note_type = NT_PRFPREG,
95                 .n = ELF_NFPREG,
96                 .size = sizeof(elf_fpreg_t),
97                 .align = sizeof(elf_fpreg_t),
98                 .regset_get = riscv_fpr_get,
99                 .set = riscv_fpr_set,
100         },
101 #endif
102 };
103
104 static const struct user_regset_view riscv_user_native_view = {
105         .name = "riscv",
106         .e_machine = EM_RISCV,
107         .regsets = riscv_user_regset,
108         .n = ARRAY_SIZE(riscv_user_regset),
109 };
110
111 struct pt_regs_offset {
112         const char *name;
113         int offset;
114 };
115
116 #define REG_OFFSET_NAME(r) {.name = #r, .offset = offsetof(struct pt_regs, r)}
117 #define REG_OFFSET_END {.name = NULL, .offset = 0}
118
119 static const struct pt_regs_offset regoffset_table[] = {
120         REG_OFFSET_NAME(epc),
121         REG_OFFSET_NAME(ra),
122         REG_OFFSET_NAME(sp),
123         REG_OFFSET_NAME(gp),
124         REG_OFFSET_NAME(tp),
125         REG_OFFSET_NAME(t0),
126         REG_OFFSET_NAME(t1),
127         REG_OFFSET_NAME(t2),
128         REG_OFFSET_NAME(s0),
129         REG_OFFSET_NAME(s1),
130         REG_OFFSET_NAME(a0),
131         REG_OFFSET_NAME(a1),
132         REG_OFFSET_NAME(a2),
133         REG_OFFSET_NAME(a3),
134         REG_OFFSET_NAME(a4),
135         REG_OFFSET_NAME(a5),
136         REG_OFFSET_NAME(a6),
137         REG_OFFSET_NAME(a7),
138         REG_OFFSET_NAME(s2),
139         REG_OFFSET_NAME(s3),
140         REG_OFFSET_NAME(s4),
141         REG_OFFSET_NAME(s5),
142         REG_OFFSET_NAME(s6),
143         REG_OFFSET_NAME(s7),
144         REG_OFFSET_NAME(s8),
145         REG_OFFSET_NAME(s9),
146         REG_OFFSET_NAME(s10),
147         REG_OFFSET_NAME(s11),
148         REG_OFFSET_NAME(t3),
149         REG_OFFSET_NAME(t4),
150         REG_OFFSET_NAME(t5),
151         REG_OFFSET_NAME(t6),
152         REG_OFFSET_NAME(status),
153         REG_OFFSET_NAME(badaddr),
154         REG_OFFSET_NAME(cause),
155         REG_OFFSET_NAME(orig_a0),
156         REG_OFFSET_END,
157 };
158
159 /**
160  * regs_query_register_offset() - query register offset from its name
161  * @name:       the name of a register
162  *
163  * regs_query_register_offset() returns the offset of a register in struct
164  * pt_regs from its name. If the name is invalid, this returns -EINVAL;
165  */
166 int regs_query_register_offset(const char *name)
167 {
168         const struct pt_regs_offset *roff;
169
170         for (roff = regoffset_table; roff->name != NULL; roff++)
171                 if (!strcmp(roff->name, name))
172                         return roff->offset;
173         return -EINVAL;
174 }
175
176 /**
177  * regs_within_kernel_stack() - check the address in the stack
178  * @regs:      pt_regs which contains kernel stack pointer.
179  * @addr:      address which is checked.
180  *
181  * regs_within_kernel_stack() checks @addr is within the kernel stack page(s).
182  * If @addr is within the kernel stack, it returns true. If not, returns false.
183  */
184 static bool regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr)
185 {
186         return (addr & ~(THREAD_SIZE - 1))  ==
187                 (kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1));
188 }
189
190 /**
191  * regs_get_kernel_stack_nth() - get Nth entry of the stack
192  * @regs:       pt_regs which contains kernel stack pointer.
193  * @n:          stack entry number.
194  *
195  * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which
196  * is specified by @regs. If the @n th entry is NOT in the kernel stack,
197  * this returns 0.
198  */
199 unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n)
200 {
201         unsigned long *addr = (unsigned long *)kernel_stack_pointer(regs);
202
203         addr += n;
204         if (regs_within_kernel_stack(regs, (unsigned long)addr))
205                 return *addr;
206         else
207                 return 0;
208 }
209
210 void ptrace_disable(struct task_struct *child)
211 {
212 }
213
214 long arch_ptrace(struct task_struct *child, long request,
215                  unsigned long addr, unsigned long data)
216 {
217         long ret = -EIO;
218
219         switch (request) {
220         default:
221                 ret = ptrace_request(child, request, addr, data);
222                 break;
223         }
224
225         return ret;
226 }
227
228 #ifdef CONFIG_COMPAT
229 static int compat_riscv_gpr_get(struct task_struct *target,
230                                 const struct user_regset *regset,
231                                 struct membuf to)
232 {
233         struct compat_user_regs_struct cregs;
234
235         regs_to_cregs(&cregs, task_pt_regs(target));
236
237         return membuf_write(&to, &cregs,
238                             sizeof(struct compat_user_regs_struct));
239 }
240
241 static int compat_riscv_gpr_set(struct task_struct *target,
242                                 const struct user_regset *regset,
243                                 unsigned int pos, unsigned int count,
244                                 const void *kbuf, const void __user *ubuf)
245 {
246         int ret;
247         struct compat_user_regs_struct cregs;
248
249         ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &cregs, 0, -1);
250
251         cregs_to_regs(&cregs, task_pt_regs(target));
252
253         return ret;
254 }
255
256 static const struct user_regset compat_riscv_user_regset[] = {
257         [REGSET_X] = {
258                 .core_note_type = NT_PRSTATUS,
259                 .n = ELF_NGREG,
260                 .size = sizeof(compat_elf_greg_t),
261                 .align = sizeof(compat_elf_greg_t),
262                 .regset_get = compat_riscv_gpr_get,
263                 .set = compat_riscv_gpr_set,
264         },
265 #ifdef CONFIG_FPU
266         [REGSET_F] = {
267                 .core_note_type = NT_PRFPREG,
268                 .n = ELF_NFPREG,
269                 .size = sizeof(elf_fpreg_t),
270                 .align = sizeof(elf_fpreg_t),
271                 .regset_get = riscv_fpr_get,
272                 .set = riscv_fpr_set,
273         },
274 #endif
275 };
276
277 static const struct user_regset_view compat_riscv_user_native_view = {
278         .name = "riscv",
279         .e_machine = EM_RISCV,
280         .regsets = compat_riscv_user_regset,
281         .n = ARRAY_SIZE(compat_riscv_user_regset),
282 };
283
284 long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
285                         compat_ulong_t caddr, compat_ulong_t cdata)
286 {
287         long ret = -EIO;
288
289         switch (request) {
290         default:
291                 ret = compat_ptrace_request(child, request, caddr, cdata);
292                 break;
293         }
294
295         return ret;
296 }
297 #endif /* CONFIG_COMPAT */
298
299 const struct user_regset_view *task_user_regset_view(struct task_struct *task)
300 {
301 #ifdef CONFIG_COMPAT
302         if (test_tsk_thread_flag(task, TIF_32BIT))
303                 return &compat_riscv_user_native_view;
304         else
305 #endif
306                 return &riscv_user_native_view;
307 }
This page took 0.049961 seconds and 4 git commands to generate.