1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright 2010 Tilera Corporation. All Rights Reserved.
4 * Copyright 2015 Regents of the University of California
5 * Copyright 2017 SiFive
7 * Copied from arch/tile/kernel/ptrace.c
10 #include <asm/vector.h>
11 #include <asm/ptrace.h>
12 #include <asm/syscall.h>
13 #include <asm/thread_info.h>
14 #include <asm/switch_to.h>
15 #include <linux/audit.h>
16 #include <linux/compat.h>
17 #include <linux/ptrace.h>
18 #include <linux/elf.h>
19 #include <linux/regset.h>
20 #include <linux/sched.h>
21 #include <linux/sched/task_stack.h>
28 #ifdef CONFIG_RISCV_ISA_V
33 static int riscv_gpr_get(struct task_struct
*target
,
34 const struct user_regset
*regset
,
37 return membuf_write(&to
, task_pt_regs(target
),
38 sizeof(struct user_regs_struct
));
41 static int riscv_gpr_set(struct task_struct
*target
,
42 const struct user_regset
*regset
,
43 unsigned int pos
, unsigned int count
,
44 const void *kbuf
, const void __user
*ubuf
)
48 regs
= task_pt_regs(target
);
49 return user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
, regs
, 0, -1);
53 static int riscv_fpr_get(struct task_struct
*target
,
54 const struct user_regset
*regset
,
57 struct __riscv_d_ext_state
*fstate
= &target
->thread
.fstate
;
59 if (target
== current
)
60 fstate_save(current
, task_pt_regs(current
));
62 membuf_write(&to
, fstate
, offsetof(struct __riscv_d_ext_state
, fcsr
));
63 membuf_store(&to
, fstate
->fcsr
);
64 return membuf_zero(&to
, 4); // explicitly pad
67 static int riscv_fpr_set(struct task_struct
*target
,
68 const struct user_regset
*regset
,
69 unsigned int pos
, unsigned int count
,
70 const void *kbuf
, const void __user
*ubuf
)
73 struct __riscv_d_ext_state
*fstate
= &target
->thread
.fstate
;
75 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
, fstate
, 0,
76 offsetof(struct __riscv_d_ext_state
, fcsr
));
78 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
, fstate
, 0,
79 offsetof(struct __riscv_d_ext_state
, fcsr
) +
80 sizeof(fstate
->fcsr
));
87 #ifdef CONFIG_RISCV_ISA_V
88 static int riscv_vr_get(struct task_struct
*target
,
89 const struct user_regset
*regset
,
92 struct __riscv_v_ext_state
*vstate
= &target
->thread
.vstate
;
93 struct __riscv_v_regset_state ptrace_vstate
;
95 if (!riscv_v_vstate_query(task_pt_regs(target
)))
99 * Ensure the vector registers have been saved to the memory before
100 * copying them to membuf.
102 if (target
== current
) {
103 get_cpu_vector_context();
104 riscv_v_vstate_save(¤t
->thread
.vstate
, task_pt_regs(current
));
105 put_cpu_vector_context();
108 ptrace_vstate
.vstart
= vstate
->vstart
;
109 ptrace_vstate
.vl
= vstate
->vl
;
110 ptrace_vstate
.vtype
= vstate
->vtype
;
111 ptrace_vstate
.vcsr
= vstate
->vcsr
;
112 ptrace_vstate
.vlenb
= vstate
->vlenb
;
114 /* Copy vector header from vstate. */
115 membuf_write(&to
, &ptrace_vstate
, sizeof(struct __riscv_v_regset_state
));
117 /* Copy all the vector registers from vstate. */
118 return membuf_write(&to
, vstate
->datap
, riscv_v_vsize
);
121 static int riscv_vr_set(struct task_struct
*target
,
122 const struct user_regset
*regset
,
123 unsigned int pos
, unsigned int count
,
124 const void *kbuf
, const void __user
*ubuf
)
127 struct __riscv_v_ext_state
*vstate
= &target
->thread
.vstate
;
128 struct __riscv_v_regset_state ptrace_vstate
;
130 if (!riscv_v_vstate_query(task_pt_regs(target
)))
133 /* Copy rest of the vstate except datap */
134 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
, &ptrace_vstate
, 0,
135 sizeof(struct __riscv_v_regset_state
));
139 if (vstate
->vlenb
!= ptrace_vstate
.vlenb
)
142 vstate
->vstart
= ptrace_vstate
.vstart
;
143 vstate
->vl
= ptrace_vstate
.vl
;
144 vstate
->vtype
= ptrace_vstate
.vtype
;
145 vstate
->vcsr
= ptrace_vstate
.vcsr
;
147 /* Copy all the vector registers. */
149 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
, vstate
->datap
,
155 static const struct user_regset riscv_user_regset
[] = {
157 .core_note_type
= NT_PRSTATUS
,
159 .size
= sizeof(elf_greg_t
),
160 .align
= sizeof(elf_greg_t
),
161 .regset_get
= riscv_gpr_get
,
162 .set
= riscv_gpr_set
,
166 .core_note_type
= NT_PRFPREG
,
168 .size
= sizeof(elf_fpreg_t
),
169 .align
= sizeof(elf_fpreg_t
),
170 .regset_get
= riscv_fpr_get
,
171 .set
= riscv_fpr_set
,
174 #ifdef CONFIG_RISCV_ISA_V
176 .core_note_type
= NT_RISCV_VECTOR
,
178 .n
= ((32 * RISCV_MAX_VLENB
) +
179 sizeof(struct __riscv_v_regset_state
)) / sizeof(__u32
),
180 .size
= sizeof(__u32
),
181 .regset_get
= riscv_vr_get
,
187 static const struct user_regset_view riscv_user_native_view
= {
189 .e_machine
= EM_RISCV
,
190 .regsets
= riscv_user_regset
,
191 .n
= ARRAY_SIZE(riscv_user_regset
),
194 struct pt_regs_offset
{
199 #define REG_OFFSET_NAME(r) {.name = #r, .offset = offsetof(struct pt_regs, r)}
200 #define REG_OFFSET_END {.name = NULL, .offset = 0}
202 static const struct pt_regs_offset regoffset_table
[] = {
203 REG_OFFSET_NAME(epc
),
229 REG_OFFSET_NAME(s10
),
230 REG_OFFSET_NAME(s11
),
235 REG_OFFSET_NAME(status
),
236 REG_OFFSET_NAME(badaddr
),
237 REG_OFFSET_NAME(cause
),
238 REG_OFFSET_NAME(orig_a0
),
243 * regs_query_register_offset() - query register offset from its name
244 * @name: the name of a register
246 * regs_query_register_offset() returns the offset of a register in struct
247 * pt_regs from its name. If the name is invalid, this returns -EINVAL;
249 int regs_query_register_offset(const char *name
)
251 const struct pt_regs_offset
*roff
;
253 for (roff
= regoffset_table
; roff
->name
!= NULL
; roff
++)
254 if (!strcmp(roff
->name
, name
))
260 * regs_within_kernel_stack() - check the address in the stack
261 * @regs: pt_regs which contains kernel stack pointer.
262 * @addr: address which is checked.
264 * regs_within_kernel_stack() checks @addr is within the kernel stack page(s).
265 * If @addr is within the kernel stack, it returns true. If not, returns false.
267 static bool regs_within_kernel_stack(struct pt_regs
*regs
, unsigned long addr
)
269 return (addr
& ~(THREAD_SIZE
- 1)) ==
270 (kernel_stack_pointer(regs
) & ~(THREAD_SIZE
- 1));
274 * regs_get_kernel_stack_nth() - get Nth entry of the stack
275 * @regs: pt_regs which contains kernel stack pointer.
276 * @n: stack entry number.
278 * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which
279 * is specified by @regs. If the @n th entry is NOT in the kernel stack,
282 unsigned long regs_get_kernel_stack_nth(struct pt_regs
*regs
, unsigned int n
)
284 unsigned long *addr
= (unsigned long *)kernel_stack_pointer(regs
);
287 if (regs_within_kernel_stack(regs
, (unsigned long)addr
))
293 void ptrace_disable(struct task_struct
*child
)
297 long arch_ptrace(struct task_struct
*child
, long request
,
298 unsigned long addr
, unsigned long data
)
304 ret
= ptrace_request(child
, request
, addr
, data
);
312 static int compat_riscv_gpr_get(struct task_struct
*target
,
313 const struct user_regset
*regset
,
316 struct compat_user_regs_struct cregs
;
318 regs_to_cregs(&cregs
, task_pt_regs(target
));
320 return membuf_write(&to
, &cregs
,
321 sizeof(struct compat_user_regs_struct
));
324 static int compat_riscv_gpr_set(struct task_struct
*target
,
325 const struct user_regset
*regset
,
326 unsigned int pos
, unsigned int count
,
327 const void *kbuf
, const void __user
*ubuf
)
330 struct compat_user_regs_struct cregs
;
332 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
, &cregs
, 0, -1);
334 cregs_to_regs(&cregs
, task_pt_regs(target
));
339 static const struct user_regset compat_riscv_user_regset
[] = {
341 .core_note_type
= NT_PRSTATUS
,
343 .size
= sizeof(compat_elf_greg_t
),
344 .align
= sizeof(compat_elf_greg_t
),
345 .regset_get
= compat_riscv_gpr_get
,
346 .set
= compat_riscv_gpr_set
,
350 .core_note_type
= NT_PRFPREG
,
352 .size
= sizeof(elf_fpreg_t
),
353 .align
= sizeof(elf_fpreg_t
),
354 .regset_get
= riscv_fpr_get
,
355 .set
= riscv_fpr_set
,
360 static const struct user_regset_view compat_riscv_user_native_view
= {
362 .e_machine
= EM_RISCV
,
363 .regsets
= compat_riscv_user_regset
,
364 .n
= ARRAY_SIZE(compat_riscv_user_regset
),
367 long compat_arch_ptrace(struct task_struct
*child
, compat_long_t request
,
368 compat_ulong_t caddr
, compat_ulong_t cdata
)
374 ret
= compat_ptrace_request(child
, request
, caddr
, cdata
);
381 static const struct user_regset_view compat_riscv_user_native_view
= {};
382 #endif /* CONFIG_COMPAT */
384 const struct user_regset_view
*task_user_regset_view(struct task_struct
*task
)
386 if (is_compat_thread(&task
->thread_info
))
387 return &compat_riscv_user_native_view
;
389 return &riscv_user_native_view
;