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
31 #ifdef CONFIG_RISCV_ISA_SUPM
32 REGSET_TAGGED_ADDR_CTRL
,
36 static int riscv_gpr_get(struct task_struct
*target
,
37 const struct user_regset
*regset
,
40 return membuf_write(&to
, task_pt_regs(target
),
41 sizeof(struct user_regs_struct
));
44 static int riscv_gpr_set(struct task_struct
*target
,
45 const struct user_regset
*regset
,
46 unsigned int pos
, unsigned int count
,
47 const void *kbuf
, const void __user
*ubuf
)
51 regs
= task_pt_regs(target
);
52 return user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
, regs
, 0, -1);
56 static int riscv_fpr_get(struct task_struct
*target
,
57 const struct user_regset
*regset
,
60 struct __riscv_d_ext_state
*fstate
= &target
->thread
.fstate
;
62 if (target
== current
)
63 fstate_save(current
, task_pt_regs(current
));
65 membuf_write(&to
, fstate
, offsetof(struct __riscv_d_ext_state
, fcsr
));
66 membuf_store(&to
, fstate
->fcsr
);
67 return membuf_zero(&to
, 4); // explicitly pad
70 static int riscv_fpr_set(struct task_struct
*target
,
71 const struct user_regset
*regset
,
72 unsigned int pos
, unsigned int count
,
73 const void *kbuf
, const void __user
*ubuf
)
76 struct __riscv_d_ext_state
*fstate
= &target
->thread
.fstate
;
78 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
, fstate
, 0,
79 offsetof(struct __riscv_d_ext_state
, fcsr
));
81 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
, fstate
, 0,
82 offsetof(struct __riscv_d_ext_state
, fcsr
) +
83 sizeof(fstate
->fcsr
));
90 #ifdef CONFIG_RISCV_ISA_V
91 static int riscv_vr_get(struct task_struct
*target
,
92 const struct user_regset
*regset
,
95 struct __riscv_v_ext_state
*vstate
= &target
->thread
.vstate
;
96 struct __riscv_v_regset_state ptrace_vstate
;
98 if (!riscv_v_vstate_query(task_pt_regs(target
)))
102 * Ensure the vector registers have been saved to the memory before
103 * copying them to membuf.
105 if (target
== current
) {
106 get_cpu_vector_context();
107 riscv_v_vstate_save(¤t
->thread
.vstate
, task_pt_regs(current
));
108 put_cpu_vector_context();
111 ptrace_vstate
.vstart
= vstate
->vstart
;
112 ptrace_vstate
.vl
= vstate
->vl
;
113 ptrace_vstate
.vtype
= vstate
->vtype
;
114 ptrace_vstate
.vcsr
= vstate
->vcsr
;
115 ptrace_vstate
.vlenb
= vstate
->vlenb
;
117 /* Copy vector header from vstate. */
118 membuf_write(&to
, &ptrace_vstate
, sizeof(struct __riscv_v_regset_state
));
120 /* Copy all the vector registers from vstate. */
121 return membuf_write(&to
, vstate
->datap
, riscv_v_vsize
);
124 static int riscv_vr_set(struct task_struct
*target
,
125 const struct user_regset
*regset
,
126 unsigned int pos
, unsigned int count
,
127 const void *kbuf
, const void __user
*ubuf
)
130 struct __riscv_v_ext_state
*vstate
= &target
->thread
.vstate
;
131 struct __riscv_v_regset_state ptrace_vstate
;
133 if (!riscv_v_vstate_query(task_pt_regs(target
)))
136 /* Copy rest of the vstate except datap */
137 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
, &ptrace_vstate
, 0,
138 sizeof(struct __riscv_v_regset_state
));
142 if (vstate
->vlenb
!= ptrace_vstate
.vlenb
)
145 vstate
->vstart
= ptrace_vstate
.vstart
;
146 vstate
->vl
= ptrace_vstate
.vl
;
147 vstate
->vtype
= ptrace_vstate
.vtype
;
148 vstate
->vcsr
= ptrace_vstate
.vcsr
;
150 /* Copy all the vector registers. */
152 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
, vstate
->datap
,
158 #ifdef CONFIG_RISCV_ISA_SUPM
159 static int tagged_addr_ctrl_get(struct task_struct
*target
,
160 const struct user_regset
*regset
,
163 long ctrl
= get_tagged_addr_ctrl(target
);
165 if (IS_ERR_VALUE(ctrl
))
168 return membuf_write(&to
, &ctrl
, sizeof(ctrl
));
171 static int tagged_addr_ctrl_set(struct task_struct
*target
,
172 const struct user_regset
*regset
,
173 unsigned int pos
, unsigned int count
,
174 const void *kbuf
, const void __user
*ubuf
)
179 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
, &ctrl
, 0, -1);
183 return set_tagged_addr_ctrl(target
, ctrl
);
187 static const struct user_regset riscv_user_regset
[] = {
189 .core_note_type
= NT_PRSTATUS
,
191 .size
= sizeof(elf_greg_t
),
192 .align
= sizeof(elf_greg_t
),
193 .regset_get
= riscv_gpr_get
,
194 .set
= riscv_gpr_set
,
198 .core_note_type
= NT_PRFPREG
,
200 .size
= sizeof(elf_fpreg_t
),
201 .align
= sizeof(elf_fpreg_t
),
202 .regset_get
= riscv_fpr_get
,
203 .set
= riscv_fpr_set
,
206 #ifdef CONFIG_RISCV_ISA_V
208 .core_note_type
= NT_RISCV_VECTOR
,
210 .n
= ((32 * RISCV_MAX_VLENB
) +
211 sizeof(struct __riscv_v_regset_state
)) / sizeof(__u32
),
212 .size
= sizeof(__u32
),
213 .regset_get
= riscv_vr_get
,
217 #ifdef CONFIG_RISCV_ISA_SUPM
218 [REGSET_TAGGED_ADDR_CTRL
] = {
219 .core_note_type
= NT_RISCV_TAGGED_ADDR_CTRL
,
221 .size
= sizeof(long),
222 .align
= sizeof(long),
223 .regset_get
= tagged_addr_ctrl_get
,
224 .set
= tagged_addr_ctrl_set
,
229 static const struct user_regset_view riscv_user_native_view
= {
231 .e_machine
= EM_RISCV
,
232 .regsets
= riscv_user_regset
,
233 .n
= ARRAY_SIZE(riscv_user_regset
),
236 struct pt_regs_offset
{
241 #define REG_OFFSET_NAME(r) {.name = #r, .offset = offsetof(struct pt_regs, r)}
242 #define REG_OFFSET_END {.name = NULL, .offset = 0}
244 static const struct pt_regs_offset regoffset_table
[] = {
245 REG_OFFSET_NAME(epc
),
271 REG_OFFSET_NAME(s10
),
272 REG_OFFSET_NAME(s11
),
277 REG_OFFSET_NAME(status
),
278 REG_OFFSET_NAME(badaddr
),
279 REG_OFFSET_NAME(cause
),
280 REG_OFFSET_NAME(orig_a0
),
285 * regs_query_register_offset() - query register offset from its name
286 * @name: the name of a register
288 * regs_query_register_offset() returns the offset of a register in struct
289 * pt_regs from its name. If the name is invalid, this returns -EINVAL;
291 int regs_query_register_offset(const char *name
)
293 const struct pt_regs_offset
*roff
;
295 for (roff
= regoffset_table
; roff
->name
!= NULL
; roff
++)
296 if (!strcmp(roff
->name
, name
))
302 * regs_within_kernel_stack() - check the address in the stack
303 * @regs: pt_regs which contains kernel stack pointer.
304 * @addr: address which is checked.
306 * regs_within_kernel_stack() checks @addr is within the kernel stack page(s).
307 * If @addr is within the kernel stack, it returns true. If not, returns false.
309 static bool regs_within_kernel_stack(struct pt_regs
*regs
, unsigned long addr
)
311 return (addr
& ~(THREAD_SIZE
- 1)) ==
312 (kernel_stack_pointer(regs
) & ~(THREAD_SIZE
- 1));
316 * regs_get_kernel_stack_nth() - get Nth entry of the stack
317 * @regs: pt_regs which contains kernel stack pointer.
318 * @n: stack entry number.
320 * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which
321 * is specified by @regs. If the @n th entry is NOT in the kernel stack,
324 unsigned long regs_get_kernel_stack_nth(struct pt_regs
*regs
, unsigned int n
)
326 unsigned long *addr
= (unsigned long *)kernel_stack_pointer(regs
);
329 if (regs_within_kernel_stack(regs
, (unsigned long)addr
))
335 void ptrace_disable(struct task_struct
*child
)
339 long arch_ptrace(struct task_struct
*child
, long request
,
340 unsigned long addr
, unsigned long data
)
346 ret
= ptrace_request(child
, request
, addr
, data
);
354 static int compat_riscv_gpr_get(struct task_struct
*target
,
355 const struct user_regset
*regset
,
358 struct compat_user_regs_struct cregs
;
360 regs_to_cregs(&cregs
, task_pt_regs(target
));
362 return membuf_write(&to
, &cregs
,
363 sizeof(struct compat_user_regs_struct
));
366 static int compat_riscv_gpr_set(struct task_struct
*target
,
367 const struct user_regset
*regset
,
368 unsigned int pos
, unsigned int count
,
369 const void *kbuf
, const void __user
*ubuf
)
372 struct compat_user_regs_struct cregs
;
374 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
, &cregs
, 0, -1);
376 cregs_to_regs(&cregs
, task_pt_regs(target
));
381 static const struct user_regset compat_riscv_user_regset
[] = {
383 .core_note_type
= NT_PRSTATUS
,
385 .size
= sizeof(compat_elf_greg_t
),
386 .align
= sizeof(compat_elf_greg_t
),
387 .regset_get
= compat_riscv_gpr_get
,
388 .set
= compat_riscv_gpr_set
,
392 .core_note_type
= NT_PRFPREG
,
394 .size
= sizeof(elf_fpreg_t
),
395 .align
= sizeof(elf_fpreg_t
),
396 .regset_get
= riscv_fpr_get
,
397 .set
= riscv_fpr_set
,
402 static const struct user_regset_view compat_riscv_user_native_view
= {
404 .e_machine
= EM_RISCV
,
405 .regsets
= compat_riscv_user_regset
,
406 .n
= ARRAY_SIZE(compat_riscv_user_regset
),
409 long compat_arch_ptrace(struct task_struct
*child
, compat_long_t request
,
410 compat_ulong_t caddr
, compat_ulong_t cdata
)
416 ret
= compat_ptrace_request(child
, request
, caddr
, cdata
);
423 static const struct user_regset_view compat_riscv_user_native_view
= {};
424 #endif /* CONFIG_COMPAT */
426 const struct user_regset_view
*task_user_regset_view(struct task_struct
*task
)
428 if (is_compat_thread(&task
->thread_info
))
429 return &compat_riscv_user_native_view
;
431 return &riscv_user_native_view
;