Linux 2.6.31.6
[linux/fpc-iii.git] / arch / mn10300 / kernel / ptrace.c
blobcf847dabc1bd3a7cd810628ea2500bbfd8b922a7
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>
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>
31 * translate ptrace register IDs into struct pt_regs offsets
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,
63 static inline int get_stack_long(struct task_struct *task, int offset)
65 return *(unsigned long *)
66 ((unsigned long) task->thread.uregs + offset);
69 static inline
70 int put_stack_long(struct task_struct *task, int offset, unsigned long data)
72 unsigned long stack;
74 stack = (unsigned long) task->thread.uregs + offset;
75 *(unsigned long *) stack = data;
76 return 0;
80 * retrieve the contents of MN10300 userspace general registers
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)
87 const struct pt_regs *regs = task_pt_regs(target);
88 int ret;
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;
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;
102 return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
103 NR_PTREGS * sizeof(long), -1);
107 * update the contents of the MN10300 userspace general registers
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)
114 struct pt_regs *regs = task_pt_regs(target);
115 unsigned long tmp;
116 int ret;
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;
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;
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;
140 if (ret < 0)
141 return ret;
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));
148 if (ret < 0)
149 return ret;
151 return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
152 NR_PTREGS * sizeof(long), -1);
156 * retrieve the contents of MN10300 userspace FPU registers
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)
163 const struct fpu_state_struct *fpregs = &target->thread.fpu_state;
164 int ret;
166 unlazy_fpu(target);
168 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
169 fpregs, 0, sizeof(*fpregs));
170 if (ret < 0)
171 return ret;
173 return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
174 sizeof(*fpregs), -1);
178 * update the contents of the MN10300 userspace FPU registers
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)
185 struct fpu_state_struct fpu_state = target->thread.fpu_state;
186 int ret;
188 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
189 &fpu_state, 0, sizeof(fpu_state));
190 if (ret < 0)
191 return ret;
193 fpu_kill_state(target);
194 target->thread.fpu_state = fpu_state;
195 set_using_fpu(target);
197 return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
198 sizeof(fpu_state), -1);
202 * determine if the FPU registers have actually been used
204 static int fpuregs_active(struct task_struct *target,
205 const struct user_regset *regset)
207 return is_using_fpu(target) ? regset->n : 0;
211 * Define the register sets available on the MN10300 under Linux
213 enum mn10300_regset {
214 REGSET_GENERAL,
215 REGSET_FPU,
218 static const struct user_regset mn10300_regsets[] = {
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
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,
234 * FPU register format is:
235 * FS0-31, FPCR
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,
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),
255 const struct user_regset_view *task_user_regset_view(struct task_struct *task)
257 return &user_mn10300_native_view;
261 * set the single-step bit
263 void user_enable_single_step(struct task_struct *child)
265 #ifndef CONFIG_MN10300_USING_JTAG
266 struct user *dummy = NULL;
267 long tmp;
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
276 * make sure the single-step bit is not set
278 void user_disable_single_step(struct task_struct *child)
280 #ifndef CONFIG_MN10300_USING_JTAG
281 struct user *dummy = NULL;
282 long tmp;
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
290 void ptrace_disable(struct task_struct *child)
292 user_disable_single_step(child);
296 * handle the arch-specific side of process tracing
298 long arch_ptrace(struct task_struct *child, long request, long addr, long data)
300 unsigned long tmp;
301 int ret;
303 switch (request) {
304 /* read the word at location addr in the USER area. */
305 case PTRACE_PEEKUSR:
306 ret = -EIO;
307 if ((addr & 3) || addr < 0 ||
308 addr > sizeof(struct user) - 3)
309 break;
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, (unsigned long *) data);
316 break;
318 /* write the word at location addr in the USER area */
319 case PTRACE_POKEUSR:
320 ret = -EIO;
321 if ((addr & 3) || addr < 0 ||
322 addr > sizeof(struct user) - 3)
323 break;
325 ret = 0;
326 if (addr < NR_PTREGS << 2)
327 ret = put_stack_long(child, ptrace_regid_to_frame[addr],
328 data);
329 break;
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 (void __user *)data);
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 (const void __user *)data);
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 (void __user *)data);
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 (const void __user *)data);
355 default:
356 ret = ptrace_request(child, request, addr, data);
357 break;
360 return ret;
364 * handle tracing of system call entry
365 * - return the revised system call number or ULONG_MAX to cause ENOSYS
367 asmlinkage unsigned long syscall_trace_entry(struct pt_regs *regs)
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
375 return ULONG_MAX;
377 return regs->orig_d0;
381 * handle tracing of system call exit
383 asmlinkage void syscall_trace_exit(struct pt_regs *regs)
385 tracehook_report_syscall_exit(regs, 0);