]> git.karo-electronics.de Git - karo-tx-linux.git/blob - arch/mn10300/kernel/ptrace.c
Replace <asm/uaccess.h> with <linux/uaccess.h> globally
[karo-tx-linux.git] / 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/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 <linux/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  */
32 static 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
62 static 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
68 static inline
69 int 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  */
81 static 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  */
108 static 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  */
157 static 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  */
179 static 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  */
203 static 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  */
212 enum mn10300_regset {
213         REGSET_GENERAL,
214         REGSET_FPU,
215 };
216
217 static 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
247 static 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
254 const 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  */
262 void 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  */
277 void 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
289 void 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  */
297 long 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  */
366 asmlinkage 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  */
382 asmlinkage void syscall_trace_exit(struct pt_regs *regs)
383 {
384         tracehook_report_syscall_exit(regs, 0);
385 }