xref: /linux/arch/riscv/kernel/ptrace.c (revision 79790b6818e96c58fe2bffee1b418c16e64e7b80)
150acfb2bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2e2c0cdfbSPalmer Dabbelt /*
3e2c0cdfbSPalmer Dabbelt  * Copyright 2010 Tilera Corporation. All Rights Reserved.
4e2c0cdfbSPalmer Dabbelt  * Copyright 2015 Regents of the University of California
5e2c0cdfbSPalmer Dabbelt  * Copyright 2017 SiFive
6e2c0cdfbSPalmer Dabbelt  *
7e2c0cdfbSPalmer Dabbelt  * Copied from arch/tile/kernel/ptrace.c
8e2c0cdfbSPalmer Dabbelt  */
9e2c0cdfbSPalmer Dabbelt 
100c59922cSGreentime Hu #include <asm/vector.h>
11e2c0cdfbSPalmer Dabbelt #include <asm/ptrace.h>
12e2c0cdfbSPalmer Dabbelt #include <asm/syscall.h>
13e2c0cdfbSPalmer Dabbelt #include <asm/thread_info.h>
14379eb01cSVincent Chen #include <asm/switch_to.h>
150aea8943SDavid Abdurachmanov #include <linux/audit.h>
164608c159SGuo Ren #include <linux/compat.h>
17e2c0cdfbSPalmer Dabbelt #include <linux/ptrace.h>
18e2c0cdfbSPalmer Dabbelt #include <linux/elf.h>
19e2c0cdfbSPalmer Dabbelt #include <linux/regset.h>
20e2c0cdfbSPalmer Dabbelt #include <linux/sched.h>
21e2c0cdfbSPalmer Dabbelt #include <linux/sched/task_stack.h>
22008e901bSDavid Abdurachmanov 
23e2c0cdfbSPalmer Dabbelt enum riscv_regset {
24e2c0cdfbSPalmer Dabbelt 	REGSET_X,
25b8c8a959SJim Wilson #ifdef CONFIG_FPU
26b8c8a959SJim Wilson 	REGSET_F,
27b8c8a959SJim Wilson #endif
289300f004SAndy Chiu #ifdef CONFIG_RISCV_ISA_V
299300f004SAndy Chiu 	REGSET_V,
309300f004SAndy Chiu #endif
31e2c0cdfbSPalmer Dabbelt };
32e2c0cdfbSPalmer Dabbelt 
riscv_gpr_get(struct task_struct * target,const struct user_regset * regset,struct membuf to)33e2c0cdfbSPalmer Dabbelt static int riscv_gpr_get(struct task_struct *target,
34e2c0cdfbSPalmer Dabbelt 			 const struct user_regset *regset,
352cb6cd49SAl Viro 			 struct membuf to)
36e2c0cdfbSPalmer Dabbelt {
372cb6cd49SAl Viro 	return membuf_write(&to, task_pt_regs(target),
382cb6cd49SAl Viro 			    sizeof(struct user_regs_struct));
39e2c0cdfbSPalmer Dabbelt }
40e2c0cdfbSPalmer Dabbelt 
riscv_gpr_set(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,const void * kbuf,const void __user * ubuf)41e2c0cdfbSPalmer Dabbelt static int riscv_gpr_set(struct task_struct *target,
42e2c0cdfbSPalmer Dabbelt 			 const struct user_regset *regset,
43e2c0cdfbSPalmer Dabbelt 			 unsigned int pos, unsigned int count,
44e2c0cdfbSPalmer Dabbelt 			 const void *kbuf, const void __user *ubuf)
45e2c0cdfbSPalmer Dabbelt {
46e2c0cdfbSPalmer Dabbelt 	struct pt_regs *regs;
47e2c0cdfbSPalmer Dabbelt 
48e2c0cdfbSPalmer Dabbelt 	regs = task_pt_regs(target);
498da46c0fSMinghao Chi 	return user_regset_copyin(&pos, &count, &kbuf, &ubuf, regs, 0, -1);
50e2c0cdfbSPalmer Dabbelt }
51e2c0cdfbSPalmer Dabbelt 
52b8c8a959SJim Wilson #ifdef CONFIG_FPU
riscv_fpr_get(struct task_struct * target,const struct user_regset * regset,struct membuf to)53b8c8a959SJim Wilson static int riscv_fpr_get(struct task_struct *target,
54b8c8a959SJim Wilson 			 const struct user_regset *regset,
552cb6cd49SAl Viro 			 struct membuf to)
56b8c8a959SJim Wilson {
57b8c8a959SJim Wilson 	struct __riscv_d_ext_state *fstate = &target->thread.fstate;
58b8c8a959SJim Wilson 
59379eb01cSVincent Chen 	if (target == current)
60379eb01cSVincent Chen 		fstate_save(current, task_pt_regs(current));
61379eb01cSVincent Chen 
622cb6cd49SAl Viro 	membuf_write(&to, fstate, offsetof(struct __riscv_d_ext_state, fcsr));
632cb6cd49SAl Viro 	membuf_store(&to, fstate->fcsr);
642cb6cd49SAl Viro 	return membuf_zero(&to, 4);	// explicitly pad
65b8c8a959SJim Wilson }
66b8c8a959SJim Wilson 
riscv_fpr_set(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,const void * kbuf,const void __user * ubuf)67b8c8a959SJim Wilson static int riscv_fpr_set(struct task_struct *target,
68b8c8a959SJim Wilson 			 const struct user_regset *regset,
69b8c8a959SJim Wilson 			 unsigned int pos, unsigned int count,
70b8c8a959SJim Wilson 			 const void *kbuf, const void __user *ubuf)
71b8c8a959SJim Wilson {
72b8c8a959SJim Wilson 	int ret;
73b8c8a959SJim Wilson 	struct __riscv_d_ext_state *fstate = &target->thread.fstate;
74b8c8a959SJim Wilson 
75b8c8a959SJim Wilson 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, fstate, 0,
76b8c8a959SJim Wilson 				 offsetof(struct __riscv_d_ext_state, fcsr));
77b8c8a959SJim Wilson 	if (!ret) {
78b8c8a959SJim Wilson 		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, fstate, 0,
79b8c8a959SJim Wilson 					 offsetof(struct __riscv_d_ext_state, fcsr) +
80b8c8a959SJim Wilson 					 sizeof(fstate->fcsr));
81b8c8a959SJim Wilson 	}
82b8c8a959SJim Wilson 
83b8c8a959SJim Wilson 	return ret;
84b8c8a959SJim Wilson }
85b8c8a959SJim Wilson #endif
86e2c0cdfbSPalmer Dabbelt 
879300f004SAndy Chiu #ifdef CONFIG_RISCV_ISA_V
riscv_vr_get(struct task_struct * target,const struct user_regset * regset,struct membuf to)889300f004SAndy Chiu static int riscv_vr_get(struct task_struct *target,
899300f004SAndy Chiu 			const struct user_regset *regset,
909300f004SAndy Chiu 			struct membuf to)
919300f004SAndy Chiu {
929300f004SAndy Chiu 	struct __riscv_v_ext_state *vstate = &target->thread.vstate;
939300f004SAndy Chiu 	struct __riscv_v_regset_state ptrace_vstate;
949300f004SAndy Chiu 
959300f004SAndy Chiu 	if (!riscv_v_vstate_query(task_pt_regs(target)))
969300f004SAndy Chiu 		return -EINVAL;
979300f004SAndy Chiu 
989300f004SAndy Chiu 	/*
999300f004SAndy Chiu 	 * Ensure the vector registers have been saved to the memory before
1009300f004SAndy Chiu 	 * copying them to membuf.
1019300f004SAndy Chiu 	 */
1027df56cbcSAndy Chiu 	if (target == current) {
1037df56cbcSAndy Chiu 		get_cpu_vector_context();
104d6c78f1cSAndy Chiu 		riscv_v_vstate_save(&current->thread.vstate, task_pt_regs(current));
1057df56cbcSAndy Chiu 		put_cpu_vector_context();
1067df56cbcSAndy Chiu 	}
1079300f004SAndy Chiu 
1089300f004SAndy Chiu 	ptrace_vstate.vstart = vstate->vstart;
1099300f004SAndy Chiu 	ptrace_vstate.vl = vstate->vl;
1109300f004SAndy Chiu 	ptrace_vstate.vtype = vstate->vtype;
1119300f004SAndy Chiu 	ptrace_vstate.vcsr = vstate->vcsr;
1129300f004SAndy Chiu 	ptrace_vstate.vlenb = vstate->vlenb;
1139300f004SAndy Chiu 
1149300f004SAndy Chiu 	/* Copy vector header from vstate. */
1159300f004SAndy Chiu 	membuf_write(&to, &ptrace_vstate, sizeof(struct __riscv_v_regset_state));
1169300f004SAndy Chiu 
1179300f004SAndy Chiu 	/* Copy all the vector registers from vstate. */
1189300f004SAndy Chiu 	return membuf_write(&to, vstate->datap, riscv_v_vsize);
1199300f004SAndy Chiu }
1209300f004SAndy Chiu 
riscv_vr_set(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,const void * kbuf,const void __user * ubuf)1219300f004SAndy Chiu static int riscv_vr_set(struct task_struct *target,
1229300f004SAndy Chiu 			const struct user_regset *regset,
1239300f004SAndy Chiu 			unsigned int pos, unsigned int count,
1249300f004SAndy Chiu 			const void *kbuf, const void __user *ubuf)
1259300f004SAndy Chiu {
1269300f004SAndy Chiu 	int ret;
1279300f004SAndy Chiu 	struct __riscv_v_ext_state *vstate = &target->thread.vstate;
1289300f004SAndy Chiu 	struct __riscv_v_regset_state ptrace_vstate;
1299300f004SAndy Chiu 
1309300f004SAndy Chiu 	if (!riscv_v_vstate_query(task_pt_regs(target)))
1319300f004SAndy Chiu 		return -EINVAL;
1329300f004SAndy Chiu 
1339300f004SAndy Chiu 	/* Copy rest of the vstate except datap */
1349300f004SAndy Chiu 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &ptrace_vstate, 0,
1359300f004SAndy Chiu 				 sizeof(struct __riscv_v_regset_state));
1369300f004SAndy Chiu 	if (unlikely(ret))
1379300f004SAndy Chiu 		return ret;
1389300f004SAndy Chiu 
1399300f004SAndy Chiu 	if (vstate->vlenb != ptrace_vstate.vlenb)
1409300f004SAndy Chiu 		return -EINVAL;
1419300f004SAndy Chiu 
1429300f004SAndy Chiu 	vstate->vstart = ptrace_vstate.vstart;
1439300f004SAndy Chiu 	vstate->vl = ptrace_vstate.vl;
1449300f004SAndy Chiu 	vstate->vtype = ptrace_vstate.vtype;
1459300f004SAndy Chiu 	vstate->vcsr = ptrace_vstate.vcsr;
1469300f004SAndy Chiu 
1479300f004SAndy Chiu 	/* Copy all the vector registers. */
1489300f004SAndy Chiu 	pos = 0;
1499300f004SAndy Chiu 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, vstate->datap,
1509300f004SAndy Chiu 				 0, riscv_v_vsize);
1519300f004SAndy Chiu 	return ret;
1529300f004SAndy Chiu }
1539300f004SAndy Chiu #endif
1549300f004SAndy Chiu 
155e2c0cdfbSPalmer Dabbelt static const struct user_regset riscv_user_regset[] = {
156e2c0cdfbSPalmer Dabbelt 	[REGSET_X] = {
157e2c0cdfbSPalmer Dabbelt 		.core_note_type = NT_PRSTATUS,
158e2c0cdfbSPalmer Dabbelt 		.n = ELF_NGREG,
159e2c0cdfbSPalmer Dabbelt 		.size = sizeof(elf_greg_t),
160e2c0cdfbSPalmer Dabbelt 		.align = sizeof(elf_greg_t),
1612cb6cd49SAl Viro 		.regset_get = riscv_gpr_get,
1622cb6cd49SAl Viro 		.set = riscv_gpr_set,
163e2c0cdfbSPalmer Dabbelt 	},
164b8c8a959SJim Wilson #ifdef CONFIG_FPU
165b8c8a959SJim Wilson 	[REGSET_F] = {
166b8c8a959SJim Wilson 		.core_note_type = NT_PRFPREG,
167b8c8a959SJim Wilson 		.n = ELF_NFPREG,
168b8c8a959SJim Wilson 		.size = sizeof(elf_fpreg_t),
169b8c8a959SJim Wilson 		.align = sizeof(elf_fpreg_t),
1702cb6cd49SAl Viro 		.regset_get = riscv_fpr_get,
1712cb6cd49SAl Viro 		.set = riscv_fpr_set,
172b8c8a959SJim Wilson 	},
173b8c8a959SJim Wilson #endif
1749300f004SAndy Chiu #ifdef CONFIG_RISCV_ISA_V
1759300f004SAndy Chiu 	[REGSET_V] = {
1769300f004SAndy Chiu 		.core_note_type = NT_RISCV_VECTOR,
1779300f004SAndy Chiu 		.align = 16,
1789300f004SAndy Chiu 		.n = ((32 * RISCV_MAX_VLENB) +
1799300f004SAndy Chiu 		      sizeof(struct __riscv_v_regset_state)) / sizeof(__u32),
1809300f004SAndy Chiu 		.size = sizeof(__u32),
1819300f004SAndy Chiu 		.regset_get = riscv_vr_get,
1829300f004SAndy Chiu 		.set = riscv_vr_set,
1839300f004SAndy Chiu 	},
1849300f004SAndy Chiu #endif
185e2c0cdfbSPalmer Dabbelt };
186e2c0cdfbSPalmer Dabbelt 
187e2c0cdfbSPalmer Dabbelt static const struct user_regset_view riscv_user_native_view = {
188e2c0cdfbSPalmer Dabbelt 	.name = "riscv",
189e2c0cdfbSPalmer Dabbelt 	.e_machine = EM_RISCV,
190e2c0cdfbSPalmer Dabbelt 	.regsets = riscv_user_regset,
191e2c0cdfbSPalmer Dabbelt 	.n = ARRAY_SIZE(riscv_user_regset),
192e2c0cdfbSPalmer Dabbelt };
193e2c0cdfbSPalmer Dabbelt 
194dcdc7a53SPatrick Stählin struct pt_regs_offset {
195dcdc7a53SPatrick Stählin 	const char *name;
196dcdc7a53SPatrick Stählin 	int offset;
197dcdc7a53SPatrick Stählin };
198dcdc7a53SPatrick Stählin 
199dcdc7a53SPatrick Stählin #define REG_OFFSET_NAME(r) {.name = #r, .offset = offsetof(struct pt_regs, r)}
200dcdc7a53SPatrick Stählin #define REG_OFFSET_END {.name = NULL, .offset = 0}
201dcdc7a53SPatrick Stählin 
202dcdc7a53SPatrick Stählin static const struct pt_regs_offset regoffset_table[] = {
203dcdc7a53SPatrick Stählin 	REG_OFFSET_NAME(epc),
204dcdc7a53SPatrick Stählin 	REG_OFFSET_NAME(ra),
205dcdc7a53SPatrick Stählin 	REG_OFFSET_NAME(sp),
206dcdc7a53SPatrick Stählin 	REG_OFFSET_NAME(gp),
207dcdc7a53SPatrick Stählin 	REG_OFFSET_NAME(tp),
208dcdc7a53SPatrick Stählin 	REG_OFFSET_NAME(t0),
209dcdc7a53SPatrick Stählin 	REG_OFFSET_NAME(t1),
210dcdc7a53SPatrick Stählin 	REG_OFFSET_NAME(t2),
211dcdc7a53SPatrick Stählin 	REG_OFFSET_NAME(s0),
212dcdc7a53SPatrick Stählin 	REG_OFFSET_NAME(s1),
213dcdc7a53SPatrick Stählin 	REG_OFFSET_NAME(a0),
214dcdc7a53SPatrick Stählin 	REG_OFFSET_NAME(a1),
215dcdc7a53SPatrick Stählin 	REG_OFFSET_NAME(a2),
216dcdc7a53SPatrick Stählin 	REG_OFFSET_NAME(a3),
217dcdc7a53SPatrick Stählin 	REG_OFFSET_NAME(a4),
218dcdc7a53SPatrick Stählin 	REG_OFFSET_NAME(a5),
219dcdc7a53SPatrick Stählin 	REG_OFFSET_NAME(a6),
220dcdc7a53SPatrick Stählin 	REG_OFFSET_NAME(a7),
221dcdc7a53SPatrick Stählin 	REG_OFFSET_NAME(s2),
222dcdc7a53SPatrick Stählin 	REG_OFFSET_NAME(s3),
223dcdc7a53SPatrick Stählin 	REG_OFFSET_NAME(s4),
224dcdc7a53SPatrick Stählin 	REG_OFFSET_NAME(s5),
225dcdc7a53SPatrick Stählin 	REG_OFFSET_NAME(s6),
226dcdc7a53SPatrick Stählin 	REG_OFFSET_NAME(s7),
227dcdc7a53SPatrick Stählin 	REG_OFFSET_NAME(s8),
228dcdc7a53SPatrick Stählin 	REG_OFFSET_NAME(s9),
229dcdc7a53SPatrick Stählin 	REG_OFFSET_NAME(s10),
230dcdc7a53SPatrick Stählin 	REG_OFFSET_NAME(s11),
231dcdc7a53SPatrick Stählin 	REG_OFFSET_NAME(t3),
232dcdc7a53SPatrick Stählin 	REG_OFFSET_NAME(t4),
233dcdc7a53SPatrick Stählin 	REG_OFFSET_NAME(t5),
234dcdc7a53SPatrick Stählin 	REG_OFFSET_NAME(t6),
235dcdc7a53SPatrick Stählin 	REG_OFFSET_NAME(status),
236dcdc7a53SPatrick Stählin 	REG_OFFSET_NAME(badaddr),
237dcdc7a53SPatrick Stählin 	REG_OFFSET_NAME(cause),
238dcdc7a53SPatrick Stählin 	REG_OFFSET_NAME(orig_a0),
239dcdc7a53SPatrick Stählin 	REG_OFFSET_END,
240dcdc7a53SPatrick Stählin };
241dcdc7a53SPatrick Stählin 
242dcdc7a53SPatrick Stählin /**
243dcdc7a53SPatrick Stählin  * regs_query_register_offset() - query register offset from its name
244dcdc7a53SPatrick Stählin  * @name:	the name of a register
245dcdc7a53SPatrick Stählin  *
246dcdc7a53SPatrick Stählin  * regs_query_register_offset() returns the offset of a register in struct
247dcdc7a53SPatrick Stählin  * pt_regs from its name. If the name is invalid, this returns -EINVAL;
248dcdc7a53SPatrick Stählin  */
regs_query_register_offset(const char * name)249dcdc7a53SPatrick Stählin int regs_query_register_offset(const char *name)
250dcdc7a53SPatrick Stählin {
251dcdc7a53SPatrick Stählin 	const struct pt_regs_offset *roff;
252dcdc7a53SPatrick Stählin 
253dcdc7a53SPatrick Stählin 	for (roff = regoffset_table; roff->name != NULL; roff++)
254dcdc7a53SPatrick Stählin 		if (!strcmp(roff->name, name))
255dcdc7a53SPatrick Stählin 			return roff->offset;
256dcdc7a53SPatrick Stählin 	return -EINVAL;
257dcdc7a53SPatrick Stählin }
258dcdc7a53SPatrick Stählin 
259dcdc7a53SPatrick Stählin /**
260dcdc7a53SPatrick Stählin  * regs_within_kernel_stack() - check the address in the stack
261dcdc7a53SPatrick Stählin  * @regs:      pt_regs which contains kernel stack pointer.
262dcdc7a53SPatrick Stählin  * @addr:      address which is checked.
263dcdc7a53SPatrick Stählin  *
264dcdc7a53SPatrick Stählin  * regs_within_kernel_stack() checks @addr is within the kernel stack page(s).
265dcdc7a53SPatrick Stählin  * If @addr is within the kernel stack, it returns true. If not, returns false.
266dcdc7a53SPatrick Stählin  */
regs_within_kernel_stack(struct pt_regs * regs,unsigned long addr)267dcdc7a53SPatrick Stählin static bool regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr)
268dcdc7a53SPatrick Stählin {
269dcdc7a53SPatrick Stählin 	return (addr & ~(THREAD_SIZE - 1))  ==
270dcdc7a53SPatrick Stählin 		(kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1));
271dcdc7a53SPatrick Stählin }
272dcdc7a53SPatrick Stählin 
273dcdc7a53SPatrick Stählin /**
274dcdc7a53SPatrick Stählin  * regs_get_kernel_stack_nth() - get Nth entry of the stack
275dcdc7a53SPatrick Stählin  * @regs:	pt_regs which contains kernel stack pointer.
276dcdc7a53SPatrick Stählin  * @n:		stack entry number.
277dcdc7a53SPatrick Stählin  *
278dcdc7a53SPatrick Stählin  * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which
279dcdc7a53SPatrick Stählin  * is specified by @regs. If the @n th entry is NOT in the kernel stack,
280dcdc7a53SPatrick Stählin  * this returns 0.
281dcdc7a53SPatrick Stählin  */
regs_get_kernel_stack_nth(struct pt_regs * regs,unsigned int n)282dcdc7a53SPatrick Stählin unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n)
283dcdc7a53SPatrick Stählin {
284dcdc7a53SPatrick Stählin 	unsigned long *addr = (unsigned long *)kernel_stack_pointer(regs);
285dcdc7a53SPatrick Stählin 
286dcdc7a53SPatrick Stählin 	addr += n;
287dcdc7a53SPatrick Stählin 	if (regs_within_kernel_stack(regs, (unsigned long)addr))
288dcdc7a53SPatrick Stählin 		return *addr;
289dcdc7a53SPatrick Stählin 	else
290dcdc7a53SPatrick Stählin 		return 0;
291dcdc7a53SPatrick Stählin }
292dcdc7a53SPatrick Stählin 
ptrace_disable(struct task_struct * child)293e2c0cdfbSPalmer Dabbelt void ptrace_disable(struct task_struct *child)
294e2c0cdfbSPalmer Dabbelt {
295e2c0cdfbSPalmer Dabbelt }
296e2c0cdfbSPalmer Dabbelt 
arch_ptrace(struct task_struct * child,long request,unsigned long addr,unsigned long data)297e2c0cdfbSPalmer Dabbelt long arch_ptrace(struct task_struct *child, long request,
298e2c0cdfbSPalmer Dabbelt 		 unsigned long addr, unsigned long data)
299e2c0cdfbSPalmer Dabbelt {
300e2c0cdfbSPalmer Dabbelt 	long ret = -EIO;
301e2c0cdfbSPalmer Dabbelt 
302e2c0cdfbSPalmer Dabbelt 	switch (request) {
303e2c0cdfbSPalmer Dabbelt 	default:
304e2c0cdfbSPalmer Dabbelt 		ret = ptrace_request(child, request, addr, data);
305e2c0cdfbSPalmer Dabbelt 		break;
306e2c0cdfbSPalmer Dabbelt 	}
307e2c0cdfbSPalmer Dabbelt 
308e2c0cdfbSPalmer Dabbelt 	return ret;
309e2c0cdfbSPalmer Dabbelt }
310e2c0cdfbSPalmer Dabbelt 
3114608c159SGuo Ren #ifdef CONFIG_COMPAT
compat_riscv_gpr_get(struct task_struct * target,const struct user_regset * regset,struct membuf to)3124608c159SGuo Ren static int compat_riscv_gpr_get(struct task_struct *target,
3134608c159SGuo Ren 				const struct user_regset *regset,
3144608c159SGuo Ren 				struct membuf to)
3154608c159SGuo Ren {
3164608c159SGuo Ren 	struct compat_user_regs_struct cregs;
3174608c159SGuo Ren 
3184608c159SGuo Ren 	regs_to_cregs(&cregs, task_pt_regs(target));
3194608c159SGuo Ren 
3204608c159SGuo Ren 	return membuf_write(&to, &cregs,
3214608c159SGuo Ren 			    sizeof(struct compat_user_regs_struct));
3224608c159SGuo Ren }
3234608c159SGuo Ren 
compat_riscv_gpr_set(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,const void * kbuf,const void __user * ubuf)3244608c159SGuo Ren static int compat_riscv_gpr_set(struct task_struct *target,
3254608c159SGuo Ren 				const struct user_regset *regset,
3264608c159SGuo Ren 				unsigned int pos, unsigned int count,
3274608c159SGuo Ren 				const void *kbuf, const void __user *ubuf)
3284608c159SGuo Ren {
3294608c159SGuo Ren 	int ret;
3304608c159SGuo Ren 	struct compat_user_regs_struct cregs;
3314608c159SGuo Ren 
3324608c159SGuo Ren 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &cregs, 0, -1);
3334608c159SGuo Ren 
3344608c159SGuo Ren 	cregs_to_regs(&cregs, task_pt_regs(target));
3354608c159SGuo Ren 
3364608c159SGuo Ren 	return ret;
3374608c159SGuo Ren }
3384608c159SGuo Ren 
3394608c159SGuo Ren static const struct user_regset compat_riscv_user_regset[] = {
3404608c159SGuo Ren 	[REGSET_X] = {
3414608c159SGuo Ren 		.core_note_type = NT_PRSTATUS,
3424608c159SGuo Ren 		.n = ELF_NGREG,
3434608c159SGuo Ren 		.size = sizeof(compat_elf_greg_t),
3444608c159SGuo Ren 		.align = sizeof(compat_elf_greg_t),
3454608c159SGuo Ren 		.regset_get = compat_riscv_gpr_get,
3464608c159SGuo Ren 		.set = compat_riscv_gpr_set,
3474608c159SGuo Ren 	},
3484608c159SGuo Ren #ifdef CONFIG_FPU
3494608c159SGuo Ren 	[REGSET_F] = {
3504608c159SGuo Ren 		.core_note_type = NT_PRFPREG,
3514608c159SGuo Ren 		.n = ELF_NFPREG,
3524608c159SGuo Ren 		.size = sizeof(elf_fpreg_t),
3534608c159SGuo Ren 		.align = sizeof(elf_fpreg_t),
3544608c159SGuo Ren 		.regset_get = riscv_fpr_get,
3554608c159SGuo Ren 		.set = riscv_fpr_set,
3564608c159SGuo Ren 	},
3574608c159SGuo Ren #endif
3584608c159SGuo Ren };
3594608c159SGuo Ren 
3604608c159SGuo Ren static const struct user_regset_view compat_riscv_user_native_view = {
3614608c159SGuo Ren 	.name = "riscv",
3624608c159SGuo Ren 	.e_machine = EM_RISCV,
3634608c159SGuo Ren 	.regsets = compat_riscv_user_regset,
3644608c159SGuo Ren 	.n = ARRAY_SIZE(compat_riscv_user_regset),
3654608c159SGuo Ren };
3664608c159SGuo Ren 
compat_arch_ptrace(struct task_struct * child,compat_long_t request,compat_ulong_t caddr,compat_ulong_t cdata)3674608c159SGuo Ren long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
3684608c159SGuo Ren 			compat_ulong_t caddr, compat_ulong_t cdata)
3694608c159SGuo Ren {
3704608c159SGuo Ren 	long ret = -EIO;
3714608c159SGuo Ren 
3724608c159SGuo Ren 	switch (request) {
3734608c159SGuo Ren 	default:
3744608c159SGuo Ren 		ret = compat_ptrace_request(child, request, caddr, cdata);
3754608c159SGuo Ren 		break;
3764608c159SGuo Ren 	}
3774608c159SGuo Ren 
3784608c159SGuo Ren 	return ret;
3794608c159SGuo Ren }
380*5917ea17SLeonardo Bras #else
381*5917ea17SLeonardo Bras static const struct user_regset_view compat_riscv_user_native_view = {};
3824608c159SGuo Ren #endif /* CONFIG_COMPAT */
3834608c159SGuo Ren 
task_user_regset_view(struct task_struct * task)3844608c159SGuo Ren const struct user_regset_view *task_user_regset_view(struct task_struct *task)
3854608c159SGuo Ren {
386*5917ea17SLeonardo Bras 	if (is_compat_thread(&task->thread_info))
3874608c159SGuo Ren 		return &compat_riscv_user_native_view;
3884608c159SGuo Ren 	else
3894608c159SGuo Ren 		return &riscv_user_native_view;
3904608c159SGuo Ren }
391