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