1 /* MN10300 Process tracing
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)
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.
12 #include <linux/kernel.h>
13 #include <linux/sched.h>
15 #include <linux/smp.h>
16 #include <linux/smp_lock.h>
17 #include <linux/errno.h>
18 #include <linux/ptrace.h>
19 #include <linux/user.h>
20 #include <linux/regset.h>
21 #include <linux/elf.h>
22 #include <linux/tracehook.h>
23 #include <asm/uaccess.h>
24 #include <asm/pgtable.h>
25 #include <asm/system.h>
26 #include <asm/processor.h>
27 #include <asm/cacheflush.h>
29 #include <asm/asm-offsets.h>
32 * translate ptrace register IDs into struct pt_regs offsets
34 static const u8 ptrace_regid_to_frame[] = {
35 [PT_A3 << 2] = REG_A3,
36 [PT_A2 << 2] = REG_A2,
37 [PT_D3 << 2] = REG_D3,
38 [PT_D2 << 2] = REG_D2,
39 [PT_MCVF << 2] = REG_MCVF,
40 [PT_MCRL << 2] = REG_MCRL,
41 [PT_MCRH << 2] = REG_MCRH,
42 [PT_MDRQ << 2] = REG_MDRQ,
43 [PT_E1 << 2] = REG_E1,
44 [PT_E0 << 2] = REG_E0,
45 [PT_E7 << 2] = REG_E7,
46 [PT_E6 << 2] = REG_E6,
47 [PT_E5 << 2] = REG_E5,
48 [PT_E4 << 2] = REG_E4,
49 [PT_E3 << 2] = REG_E3,
50 [PT_E2 << 2] = REG_E2,
51 [PT_SP << 2] = REG_SP,
52 [PT_LAR << 2] = REG_LAR,
53 [PT_LIR << 2] = REG_LIR,
54 [PT_MDR << 2] = REG_MDR,
55 [PT_A1 << 2] = REG_A1,
56 [PT_A0 << 2] = REG_A0,
57 [PT_D1 << 2] = REG_D1,
58 [PT_D0 << 2] = REG_D0,
59 [PT_ORIG_D0 << 2] = REG_ORIG_D0,
60 [PT_EPSW << 2] = REG_EPSW,
61 [PT_PC << 2] = REG_PC,
64 static inline int get_stack_long(struct task_struct *task, int offset)
66 return *(unsigned long *)
67 ((unsigned long) task->thread.uregs + offset);
71 int put_stack_long(struct task_struct *task, int offset, unsigned long data)
75 stack = (unsigned long) task->thread.uregs + offset;
76 *(unsigned long *) stack = data;
81 * retrieve the contents of MN10300 userspace general registers
83 static int genregs_get(struct task_struct *target,
84 const struct user_regset *regset,
85 unsigned int pos, unsigned int count,
86 void *kbuf, void __user *ubuf)
88 const struct pt_regs *regs = task_pt_regs(target);
91 /* we need to skip regs->next */
92 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
93 regs, 0, PT_ORIG_D0 * sizeof(long));
97 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
98 ®s->orig_d0, PT_ORIG_D0 * sizeof(long),
99 NR_PTREGS * sizeof(long));
103 return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
104 NR_PTREGS * sizeof(long), -1);
108 * update the contents of the MN10300 userspace general registers
110 static int genregs_set(struct task_struct *target,
111 const struct user_regset *regset,
112 unsigned int pos, unsigned int count,
113 const void *kbuf, const void __user *ubuf)
115 struct pt_regs *regs = task_pt_regs(target);
119 /* we need to skip regs->next */
120 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
121 regs, 0, PT_ORIG_D0 * sizeof(long));
125 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
126 ®s->orig_d0, PT_ORIG_D0 * sizeof(long),
127 PT_EPSW * sizeof(long));
131 /* we need to mask off changes to EPSW */
133 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
134 &tmp, PT_EPSW * sizeof(long),
135 PT_PC * sizeof(long));
136 tmp &= EPSW_FLAG_V | EPSW_FLAG_C | EPSW_FLAG_N | EPSW_FLAG_Z;
137 tmp |= regs->epsw & ~(EPSW_FLAG_V | EPSW_FLAG_C | EPSW_FLAG_N |
144 /* and finally load the PC */
145 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
146 ®s->pc, PT_PC * sizeof(long),
147 NR_PTREGS * sizeof(long));
152 return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
153 NR_PTREGS * sizeof(long), -1);
157 * retrieve the contents of MN10300 userspace FPU registers
159 static int fpuregs_get(struct task_struct *target,
160 const struct user_regset *regset,
161 unsigned int pos, unsigned int count,
162 void *kbuf, void __user *ubuf)
164 const struct fpu_state_struct *fpregs = &target->thread.fpu_state;
169 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
170 fpregs, 0, sizeof(*fpregs));
174 return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
175 sizeof(*fpregs), -1);
179 * update the contents of the MN10300 userspace FPU registers
181 static int fpuregs_set(struct task_struct *target,
182 const struct user_regset *regset,
183 unsigned int pos, unsigned int count,
184 const void *kbuf, const void __user *ubuf)
186 struct fpu_state_struct fpu_state = target->thread.fpu_state;
189 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
190 &fpu_state, 0, sizeof(fpu_state));
194 fpu_kill_state(target);
195 target->thread.fpu_state = fpu_state;
196 set_using_fpu(target);
198 return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
199 sizeof(fpu_state), -1);
203 * determine if the FPU registers have actually been used
205 static int fpuregs_active(struct task_struct *target,
206 const struct user_regset *regset)
208 return is_using_fpu(target) ? regset->n : 0;
212 * Define the register sets available on the MN10300 under Linux
214 enum mn10300_regset {
219 static const struct user_regset mn10300_regsets[] = {
221 * General register format is:
222 * A3, A2, D3, D2, MCVF, MCRL, MCRH, MDRQ
223 * E1, E0, E7...E2, SP, LAR, LIR, MDR
224 * A1, A0, D1, D0, ORIG_D0, EPSW, PC
227 .core_note_type = NT_PRSTATUS,
229 .size = sizeof(long),
230 .align = sizeof(long),
235 * FPU register format is:
239 .core_note_type = NT_PRFPREG,
240 .n = sizeof(struct fpu_state_struct) / sizeof(long),
241 .size = sizeof(long),
242 .align = sizeof(long),
245 .active = fpuregs_active,
249 static const struct user_regset_view user_mn10300_native_view = {
251 .e_machine = EM_MN10300,
252 .regsets = mn10300_regsets,
253 .n = ARRAY_SIZE(mn10300_regsets),
256 const struct user_regset_view *task_user_regset_view(struct task_struct *task)
258 return &user_mn10300_native_view;
262 * set the single-step bit
264 void user_enable_single_step(struct task_struct *child)
266 #ifndef CONFIG_MN10300_USING_JTAG
267 struct user *dummy = NULL;
270 tmp = get_stack_long(child, (unsigned long) &dummy->regs.epsw);
272 put_stack_long(child, (unsigned long) &dummy->regs.epsw, tmp);
277 * make sure the single-step bit is not set
279 void user_disable_single_step(struct task_struct *child)
281 #ifndef CONFIG_MN10300_USING_JTAG
282 struct user *dummy = NULL;
285 tmp = get_stack_long(child, (unsigned long) &dummy->regs.epsw);
287 put_stack_long(child, (unsigned long) &dummy->regs.epsw, tmp);
291 void ptrace_disable(struct task_struct *child)
293 user_disable_single_step(child);
297 * handle the arch-specific side of process tracing
299 long arch_ptrace(struct task_struct *child, long request, long addr, long data)
305 /* read the word at location addr in the USER area. */
308 if ((addr & 3) || addr < 0 ||
309 addr > sizeof(struct user) - 3)
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, (unsigned long *) data);
319 /* write the word at location addr in the USER area */
322 if ((addr & 3) || addr < 0 ||
323 addr > sizeof(struct user) - 3)
327 if (addr < NR_PTREGS << 2)
328 ret = put_stack_long(child, ptrace_regid_to_frame[addr],
332 case PTRACE_GETREGS: /* Get all integer regs from the child. */
333 return copy_regset_to_user(child, &user_mn10300_native_view,
335 0, NR_PTREGS * sizeof(long),
336 (void __user *)data);
338 case PTRACE_SETREGS: /* Set all integer regs in the child. */
339 return copy_regset_from_user(child, &user_mn10300_native_view,
341 0, NR_PTREGS * sizeof(long),
342 (const void __user *)data);
344 case PTRACE_GETFPREGS: /* Get the child FPU state. */
345 return copy_regset_to_user(child, &user_mn10300_native_view,
347 0, sizeof(struct fpu_state_struct),
348 (void __user *)data);
350 case PTRACE_SETFPREGS: /* Set the child FPU state. */
351 return copy_regset_from_user(child, &user_mn10300_native_view,
353 0, sizeof(struct fpu_state_struct),
354 (const void __user *)data);
357 ret = ptrace_request(child, request, addr, data);
365 * handle tracing of system call entry
366 * - return the revised system call number or ULONG_MAX to cause ENOSYS
368 asmlinkage unsigned long syscall_trace_entry(struct pt_regs *regs)
370 if (tracehook_report_syscall_entry(regs))
371 /* tracing decided this syscall should not happen, so
372 * We'll return a bogus call number to get an ENOSYS
373 * error, but leave the original number in
378 return regs->orig_d0;
382 * handle tracing of system call exit
384 asmlinkage void syscall_trace_exit(struct pt_regs *regs)
386 tracehook_report_syscall_exit(regs, 0);