Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
[linux-2.6] / arch / mn10300 / kernel / ptrace.c
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/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>
28 #include <asm/fpu.h>
29 #include <asm/asm-offsets.h>
30
31 /*
32  * translate ptrace register IDs into struct pt_regs offsets
33  */
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,
62 };
63
64 static inline int get_stack_long(struct task_struct *task, int offset)
65 {
66         return *(unsigned long *)
67                 ((unsigned long) task->thread.uregs + offset);
68 }
69
70 static inline
71 int put_stack_long(struct task_struct *task, int offset, unsigned long data)
72 {
73         unsigned long stack;
74
75         stack = (unsigned long) task->thread.uregs + offset;
76         *(unsigned long *) stack = data;
77         return 0;
78 }
79
80 /*
81  * retrieve the contents of MN10300 userspace general registers
82  */
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)
87 {
88         const struct pt_regs *regs = task_pt_regs(target);
89         int ret;
90
91         /* we need to skip regs->next */
92         ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
93                                   regs, 0, PT_ORIG_D0 * sizeof(long));
94         if (ret < 0)
95                 return ret;
96
97         ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
98                                   &regs->orig_d0, PT_ORIG_D0 * sizeof(long),
99                                   NR_PTREGS * sizeof(long));
100         if (ret < 0)
101                 return ret;
102
103         return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
104                                         NR_PTREGS * sizeof(long), -1);
105 }
106
107 /*
108  * update the contents of the MN10300 userspace general registers
109  */
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)
114 {
115         struct pt_regs *regs = task_pt_regs(target);
116         unsigned long tmp;
117         int ret;
118
119         /* we need to skip regs->next */
120         ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
121                                  regs, 0, PT_ORIG_D0 * sizeof(long));
122         if (ret < 0)
123                 return ret;
124
125         ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
126                                  &regs->orig_d0, PT_ORIG_D0 * sizeof(long),
127                                  PT_EPSW * sizeof(long));
128         if (ret < 0)
129                 return ret;
130
131         /* we need to mask off changes to EPSW */
132         tmp = regs->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 |
138                               EPSW_FLAG_Z);
139         regs->epsw = tmp;
140
141         if (ret < 0)
142                 return ret;
143
144         /* and finally load the PC */
145         ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
146                                  &regs->pc, PT_PC * sizeof(long),
147                                  NR_PTREGS * sizeof(long));
148
149         if (ret < 0)
150                 return ret;
151
152         return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
153                                          NR_PTREGS * sizeof(long), -1);
154 }
155
156 /*
157  * retrieve the contents of MN10300 userspace FPU registers
158  */
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)
163 {
164         const struct fpu_state_struct *fpregs = &target->thread.fpu_state;
165         int ret;
166
167         unlazy_fpu(target);
168
169         ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
170                                   fpregs, 0, sizeof(*fpregs));
171         if (ret < 0)
172                 return ret;
173
174         return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
175                                         sizeof(*fpregs), -1);
176 }
177
178 /*
179  * update the contents of the MN10300 userspace FPU registers
180  */
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)
185 {
186         struct fpu_state_struct fpu_state = target->thread.fpu_state;
187         int ret;
188
189         ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
190                                  &fpu_state, 0, sizeof(fpu_state));
191         if (ret < 0)
192                 return ret;
193
194         fpu_kill_state(target);
195         target->thread.fpu_state = fpu_state;
196         set_using_fpu(target);
197
198         return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
199                                          sizeof(fpu_state), -1);
200 }
201
202 /*
203  * determine if the FPU registers have actually been used
204  */
205 static int fpuregs_active(struct task_struct *target,
206                           const struct user_regset *regset)
207 {
208         return is_using_fpu(target) ? regset->n : 0;
209 }
210
211 /*
212  * Define the register sets available on the MN10300 under Linux
213  */
214 enum mn10300_regset {
215         REGSET_GENERAL,
216         REGSET_FPU,
217 };
218
219 static const struct user_regset mn10300_regsets[] = {
220         /*
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
225          */
226         [REGSET_GENERAL] = {
227                 .core_note_type = NT_PRSTATUS,
228                 .n              = ELF_NGREG,
229                 .size           = sizeof(long),
230                 .align          = sizeof(long),
231                 .get            = genregs_get,
232                 .set            = genregs_set,
233         },
234         /*
235          * FPU register format is:
236          *      FS0-31, FPCR
237          */
238         [REGSET_FPU] = {
239                 .core_note_type = NT_PRFPREG,
240                 .n              = sizeof(struct fpu_state_struct) / sizeof(long),
241                 .size           = sizeof(long),
242                 .align          = sizeof(long),
243                 .get            = fpuregs_get,
244                 .set            = fpuregs_set,
245                 .active         = fpuregs_active,
246         },
247 };
248
249 static const struct user_regset_view user_mn10300_native_view = {
250         .name           = "mn10300",
251         .e_machine      = EM_MN10300,
252         .regsets        = mn10300_regsets,
253         .n              = ARRAY_SIZE(mn10300_regsets),
254 };
255
256 const struct user_regset_view *task_user_regset_view(struct task_struct *task)
257 {
258         return &user_mn10300_native_view;
259 }
260
261 /*
262  * set the single-step bit
263  */
264 void user_enable_single_step(struct task_struct *child)
265 {
266 #ifndef CONFIG_MN10300_USING_JTAG
267         struct user *dummy = NULL;
268         long tmp;
269
270         tmp = get_stack_long(child, (unsigned long) &dummy->regs.epsw);
271         tmp |= EPSW_T;
272         put_stack_long(child, (unsigned long) &dummy->regs.epsw, tmp);
273 #endif
274 }
275
276 /*
277  * make sure the single-step bit is not set
278  */
279 void user_disable_single_step(struct task_struct *child)
280 {
281 #ifndef CONFIG_MN10300_USING_JTAG
282         struct user *dummy = NULL;
283         long tmp;
284
285         tmp = get_stack_long(child, (unsigned long) &dummy->regs.epsw);
286         tmp &= ~EPSW_T;
287         put_stack_long(child, (unsigned long) &dummy->regs.epsw, tmp);
288 #endif
289 }
290
291 void ptrace_disable(struct task_struct *child)
292 {
293         user_disable_single_step(child);
294 }
295
296 /*
297  * handle the arch-specific side of process tracing
298  */
299 long arch_ptrace(struct task_struct *child, long request, long addr, long data)
300 {
301         unsigned long tmp;
302         int ret;
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 < 0 ||
309                     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, (unsigned long *) data);
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 < 0 ||
323                     addr > sizeof(struct user) - 3)
324                         break;
325
326                 ret = 0;
327                 if (addr < NR_PTREGS << 2)
328                         ret = put_stack_long(child, ptrace_regid_to_frame[addr],
329                                              data);
330                 break;
331
332         case PTRACE_GETREGS:    /* Get all integer regs from the child. */
333                 return copy_regset_to_user(child, &user_mn10300_native_view,
334                                            REGSET_GENERAL,
335                                            0, NR_PTREGS * sizeof(long),
336                                            (void __user *)data);
337
338         case PTRACE_SETREGS:    /* Set all integer regs in the child. */
339                 return copy_regset_from_user(child, &user_mn10300_native_view,
340                                              REGSET_GENERAL,
341                                              0, NR_PTREGS * sizeof(long),
342                                              (const void __user *)data);
343
344         case PTRACE_GETFPREGS:  /* Get the child FPU state. */
345                 return copy_regset_to_user(child, &user_mn10300_native_view,
346                                            REGSET_FPU,
347                                            0, sizeof(struct fpu_state_struct),
348                                            (void __user *)data);
349
350         case PTRACE_SETFPREGS:  /* Set the child FPU state. */
351                 return copy_regset_from_user(child, &user_mn10300_native_view,
352                                              REGSET_FPU,
353                                              0, sizeof(struct fpu_state_struct),
354                                              (const void __user *)data);
355
356         default:
357                 ret = ptrace_request(child, request, addr, data);
358                 break;
359         }
360
361         return ret;
362 }
363
364 /*
365  * handle tracing of system call entry
366  * - return the revised system call number or ULONG_MAX to cause ENOSYS
367  */
368 asmlinkage unsigned long syscall_trace_entry(struct pt_regs *regs)
369 {
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
374                  * regs->orig_d0
375                  */
376                 return ULONG_MAX;
377
378         return regs->orig_d0;
379 }
380
381 /*
382  * handle tracing of system call exit
383  */
384 asmlinkage void syscall_trace_exit(struct pt_regs *regs)
385 {
386         tracehook_report_syscall_exit(regs, 0);
387 }