1 /* MN10300 Process tracing
2  *
3  * Copyright (C) 2007 Matsushita Electric Industrial Co., Ltd.
4  * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
5  * Modified by David Howells (dhowells@redhat.com)
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public Licence
9  * as published by the Free Software Foundation; either version
10  * 2 of the Licence, or (at your option) any later version.
11  */
12 #include <linux/kernel.h>
13 #include <linux/sched.h>
14 #include <linux/mm.h>
15 #include <linux/smp.h>
16 #include <linux/errno.h>
17 #include <linux/ptrace.h>
18 #include <linux/user.h>
19 #include <linux/regset.h>
20 #include <linux/elf.h>
21 #include <linux/tracehook.h>
22 #include <asm/uaccess.h>
23 #include <asm/pgtable.h>
24 #include <asm/system.h>
25 #include <asm/processor.h>
26 #include <asm/cacheflush.h>
27 #include <asm/fpu.h>
28 #include <asm/asm-offsets.h>
29 
30 /*
31  * translate ptrace register IDs into struct pt_regs offsets
32  */
33 static const u8 ptrace_regid_to_frame[] = {
34 	[PT_A3 << 2]		= REG_A3,
35 	[PT_A2 << 2]		= REG_A2,
36 	[PT_D3 << 2]		= REG_D3,
37 	[PT_D2 << 2]		= REG_D2,
38 	[PT_MCVF << 2]		= REG_MCVF,
39 	[PT_MCRL << 2]		= REG_MCRL,
40 	[PT_MCRH << 2]		= REG_MCRH,
41 	[PT_MDRQ << 2]		= REG_MDRQ,
42 	[PT_E1 << 2]		= REG_E1,
43 	[PT_E0 << 2]		= REG_E0,
44 	[PT_E7 << 2]		= REG_E7,
45 	[PT_E6 << 2]		= REG_E6,
46 	[PT_E5 << 2]		= REG_E5,
47 	[PT_E4 << 2]		= REG_E4,
48 	[PT_E3 << 2]		= REG_E3,
49 	[PT_E2 << 2]		= REG_E2,
50 	[PT_SP << 2]		= REG_SP,
51 	[PT_LAR << 2]		= REG_LAR,
52 	[PT_LIR << 2]		= REG_LIR,
53 	[PT_MDR << 2]		= REG_MDR,
54 	[PT_A1 << 2]		= REG_A1,
55 	[PT_A0 << 2]		= REG_A0,
56 	[PT_D1 << 2]		= REG_D1,
57 	[PT_D0 << 2]		= REG_D0,
58 	[PT_ORIG_D0 << 2]	= REG_ORIG_D0,
59 	[PT_EPSW << 2]		= REG_EPSW,
60 	[PT_PC << 2]		= REG_PC,
61 };
62 
get_stack_long(struct task_struct * task,int offset)63 static inline int get_stack_long(struct task_struct *task, int offset)
64 {
65 	return *(unsigned long *)
66 		((unsigned long) task->thread.uregs + offset);
67 }
68 
69 static inline
put_stack_long(struct task_struct * task,int offset,unsigned long data)70 int put_stack_long(struct task_struct *task, int offset, unsigned long data)
71 {
72 	unsigned long stack;
73 
74 	stack = (unsigned long) task->thread.uregs + offset;
75 	*(unsigned long *) stack = data;
76 	return 0;
77 }
78 
79 /*
80  * retrieve the contents of MN10300 userspace general registers
81  */
genregs_get(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,void * kbuf,void __user * ubuf)82 static int genregs_get(struct task_struct *target,
83 		       const struct user_regset *regset,
84 		       unsigned int pos, unsigned int count,
85 		       void *kbuf, void __user *ubuf)
86 {
87 	const struct pt_regs *regs = task_pt_regs(target);
88 	int ret;
89 
90 	/* we need to skip regs->next */
91 	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
92 				  regs, 0, PT_ORIG_D0 * sizeof(long));
93 	if (ret < 0)
94 		return ret;
95 
96 	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
97 				  &regs->orig_d0, PT_ORIG_D0 * sizeof(long),
98 				  NR_PTREGS * sizeof(long));
99 	if (ret < 0)
100 		return ret;
101 
102 	return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
103 					NR_PTREGS * sizeof(long), -1);
104 }
105 
106 /*
107  * update the contents of the MN10300 userspace general registers
108  */
genregs_set(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,const void * kbuf,const void __user * ubuf)109 static int genregs_set(struct task_struct *target,
110 		       const struct user_regset *regset,
111 		       unsigned int pos, unsigned int count,
112 		       const void *kbuf, const void __user *ubuf)
113 {
114 	struct pt_regs *regs = task_pt_regs(target);
115 	unsigned long tmp;
116 	int ret;
117 
118 	/* we need to skip regs->next */
119 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
120 				 regs, 0, PT_ORIG_D0 * sizeof(long));
121 	if (ret < 0)
122 		return ret;
123 
124 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
125 				 &regs->orig_d0, PT_ORIG_D0 * sizeof(long),
126 				 PT_EPSW * sizeof(long));
127 	if (ret < 0)
128 		return ret;
129 
130 	/* we need to mask off changes to EPSW */
131 	tmp = regs->epsw;
132 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
133 				 &tmp, PT_EPSW * sizeof(long),
134 				 PT_PC * sizeof(long));
135 	tmp &= EPSW_FLAG_V | EPSW_FLAG_C | EPSW_FLAG_N | EPSW_FLAG_Z;
136 	tmp |= regs->epsw & ~(EPSW_FLAG_V | EPSW_FLAG_C | EPSW_FLAG_N |
137 			      EPSW_FLAG_Z);
138 	regs->epsw = tmp;
139 
140 	if (ret < 0)
141 		return ret;
142 
143 	/* and finally load the PC */
144 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
145 				 &regs->pc, PT_PC * sizeof(long),
146 				 NR_PTREGS * sizeof(long));
147 
148 	if (ret < 0)
149 		return ret;
150 
151 	return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
152 					 NR_PTREGS * sizeof(long), -1);
153 }
154 
155 /*
156  * retrieve the contents of MN10300 userspace FPU registers
157  */
fpuregs_get(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,void * kbuf,void __user * ubuf)158 static int fpuregs_get(struct task_struct *target,
159 		       const struct user_regset *regset,
160 		       unsigned int pos, unsigned int count,
161 		       void *kbuf, void __user *ubuf)
162 {
163 	const struct fpu_state_struct *fpregs = &target->thread.fpu_state;
164 	int ret;
165 
166 	unlazy_fpu(target);
167 
168 	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
169 				  fpregs, 0, sizeof(*fpregs));
170 	if (ret < 0)
171 		return ret;
172 
173 	return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
174 					sizeof(*fpregs), -1);
175 }
176 
177 /*
178  * update the contents of the MN10300 userspace FPU registers
179  */
fpuregs_set(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,const void * kbuf,const void __user * ubuf)180 static int fpuregs_set(struct task_struct *target,
181 		       const struct user_regset *regset,
182 		       unsigned int pos, unsigned int count,
183 		       const void *kbuf, const void __user *ubuf)
184 {
185 	struct fpu_state_struct fpu_state = target->thread.fpu_state;
186 	int ret;
187 
188 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
189 				 &fpu_state, 0, sizeof(fpu_state));
190 	if (ret < 0)
191 		return ret;
192 
193 	fpu_kill_state(target);
194 	target->thread.fpu_state = fpu_state;
195 	set_using_fpu(target);
196 
197 	return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
198 					 sizeof(fpu_state), -1);
199 }
200 
201 /*
202  * determine if the FPU registers have actually been used
203  */
fpuregs_active(struct task_struct * target,const struct user_regset * regset)204 static int fpuregs_active(struct task_struct *target,
205 			  const struct user_regset *regset)
206 {
207 	return is_using_fpu(target) ? regset->n : 0;
208 }
209 
210 /*
211  * Define the register sets available on the MN10300 under Linux
212  */
213 enum mn10300_regset {
214 	REGSET_GENERAL,
215 	REGSET_FPU,
216 };
217 
218 static const struct user_regset mn10300_regsets[] = {
219 	/*
220 	 * General register format is:
221 	 *	A3, A2, D3, D2, MCVF, MCRL, MCRH, MDRQ
222 	 *	E1, E0, E7...E2, SP, LAR, LIR, MDR
223 	 *	A1, A0, D1, D0, ORIG_D0, EPSW, PC
224 	 */
225 	[REGSET_GENERAL] = {
226 		.core_note_type	= NT_PRSTATUS,
227 		.n		= ELF_NGREG,
228 		.size		= sizeof(long),
229 		.align		= sizeof(long),
230 		.get		= genregs_get,
231 		.set		= genregs_set,
232 	},
233 	/*
234 	 * FPU register format is:
235 	 *	FS0-31, FPCR
236 	 */
237 	[REGSET_FPU] = {
238 		.core_note_type	= NT_PRFPREG,
239 		.n		= sizeof(struct fpu_state_struct) / sizeof(long),
240 		.size		= sizeof(long),
241 		.align		= sizeof(long),
242 		.get		= fpuregs_get,
243 		.set		= fpuregs_set,
244 		.active		= fpuregs_active,
245 	},
246 };
247 
248 static const struct user_regset_view user_mn10300_native_view = {
249 	.name		= "mn10300",
250 	.e_machine	= EM_MN10300,
251 	.regsets	= mn10300_regsets,
252 	.n		= ARRAY_SIZE(mn10300_regsets),
253 };
254 
task_user_regset_view(struct task_struct * task)255 const struct user_regset_view *task_user_regset_view(struct task_struct *task)
256 {
257 	return &user_mn10300_native_view;
258 }
259 
260 /*
261  * set the single-step bit
262  */
user_enable_single_step(struct task_struct * child)263 void user_enable_single_step(struct task_struct *child)
264 {
265 #ifndef CONFIG_MN10300_USING_JTAG
266 	struct user *dummy = NULL;
267 	long tmp;
268 
269 	tmp = get_stack_long(child, (unsigned long) &dummy->regs.epsw);
270 	tmp |= EPSW_T;
271 	put_stack_long(child, (unsigned long) &dummy->regs.epsw, tmp);
272 #endif
273 }
274 
275 /*
276  * make sure the single-step bit is not set
277  */
user_disable_single_step(struct task_struct * child)278 void user_disable_single_step(struct task_struct *child)
279 {
280 #ifndef CONFIG_MN10300_USING_JTAG
281 	struct user *dummy = NULL;
282 	long tmp;
283 
284 	tmp = get_stack_long(child, (unsigned long) &dummy->regs.epsw);
285 	tmp &= ~EPSW_T;
286 	put_stack_long(child, (unsigned long) &dummy->regs.epsw, tmp);
287 #endif
288 }
289 
ptrace_disable(struct task_struct * child)290 void ptrace_disable(struct task_struct *child)
291 {
292 	user_disable_single_step(child);
293 }
294 
295 /*
296  * handle the arch-specific side of process tracing
297  */
arch_ptrace(struct task_struct * child,long request,unsigned long addr,unsigned long data)298 long arch_ptrace(struct task_struct *child, long request,
299 		 unsigned long addr, unsigned long data)
300 {
301 	unsigned long tmp;
302 	int ret;
303 	unsigned long __user *datap = (unsigned long __user *) data;
304 
305 	switch (request) {
306 	/* read the word at location addr in the USER area. */
307 	case PTRACE_PEEKUSR:
308 		ret = -EIO;
309 		if ((addr & 3) || addr > sizeof(struct user) - 3)
310 			break;
311 
312 		tmp = 0;  /* Default return condition */
313 		if (addr < NR_PTREGS << 2)
314 			tmp = get_stack_long(child,
315 					     ptrace_regid_to_frame[addr]);
316 		ret = put_user(tmp, datap);
317 		break;
318 
319 		/* write the word at location addr in the USER area */
320 	case PTRACE_POKEUSR:
321 		ret = -EIO;
322 		if ((addr & 3) || addr > sizeof(struct user) - 3)
323 			break;
324 
325 		ret = 0;
326 		if (addr < NR_PTREGS << 2)
327 			ret = put_stack_long(child, ptrace_regid_to_frame[addr],
328 					     data);
329 		break;
330 
331 	case PTRACE_GETREGS:	/* Get all integer regs from the child. */
332 		return copy_regset_to_user(child, &user_mn10300_native_view,
333 					   REGSET_GENERAL,
334 					   0, NR_PTREGS * sizeof(long),
335 					   datap);
336 
337 	case PTRACE_SETREGS:	/* Set all integer regs in the child. */
338 		return copy_regset_from_user(child, &user_mn10300_native_view,
339 					     REGSET_GENERAL,
340 					     0, NR_PTREGS * sizeof(long),
341 					     datap);
342 
343 	case PTRACE_GETFPREGS:	/* Get the child FPU state. */
344 		return copy_regset_to_user(child, &user_mn10300_native_view,
345 					   REGSET_FPU,
346 					   0, sizeof(struct fpu_state_struct),
347 					   datap);
348 
349 	case PTRACE_SETFPREGS:	/* Set the child FPU state. */
350 		return copy_regset_from_user(child, &user_mn10300_native_view,
351 					     REGSET_FPU,
352 					     0, sizeof(struct fpu_state_struct),
353 					     datap);
354 
355 	default:
356 		ret = ptrace_request(child, request, addr, data);
357 		break;
358 	}
359 
360 	return ret;
361 }
362 
363 /*
364  * handle tracing of system call entry
365  * - return the revised system call number or ULONG_MAX to cause ENOSYS
366  */
syscall_trace_entry(struct pt_regs * regs)367 asmlinkage unsigned long syscall_trace_entry(struct pt_regs *regs)
368 {
369 	if (tracehook_report_syscall_entry(regs))
370 		/* tracing decided this syscall should not happen, so
371 		 * We'll return a bogus call number to get an ENOSYS
372 		 * error, but leave the original number in
373 		 * regs->orig_d0
374 		 */
375 		return ULONG_MAX;
376 
377 	return regs->orig_d0;
378 }
379 
380 /*
381  * handle tracing of system call exit
382  */
syscall_trace_exit(struct pt_regs * regs)383 asmlinkage void syscall_trace_exit(struct pt_regs *regs)
384 {
385 	tracehook_report_syscall_exit(regs, 0);
386 }
387