Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
[pandora-kernel.git] / arch / blackfin / kernel / ptrace.c
1 /*
2  * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
3  * these modifications are Copyright 2004-2010 Analog Devices Inc.
4  *
5  * Licensed under the GPL-2
6  */
7
8 #include <linux/kernel.h>
9 #include <linux/sched.h>
10 #include <linux/mm.h>
11 #include <linux/smp.h>
12 #include <linux/elf.h>
13 #include <linux/errno.h>
14 #include <linux/ptrace.h>
15 #include <linux/user.h>
16 #include <linux/regset.h>
17 #include <linux/signal.h>
18 #include <linux/tracehook.h>
19 #include <linux/uaccess.h>
20
21 #include <asm/page.h>
22 #include <asm/pgtable.h>
23 #include <asm/system.h>
24 #include <asm/processor.h>
25 #include <asm/asm-offsets.h>
26 #include <asm/dma.h>
27 #include <asm/fixed_code.h>
28 #include <asm/cacheflush.h>
29 #include <asm/mem_map.h>
30 #include <asm/mmu_context.h>
31
32 /*
33  * does not yet catch signals sent when the child dies.
34  * in exit.c or in signal.c.
35  */
36
37 /*
38  * Get contents of register REGNO in task TASK.
39  */
40 static inline long
41 get_reg(struct task_struct *task, unsigned long regno,
42         unsigned long __user *datap)
43 {
44         long tmp;
45         struct pt_regs *regs = task_pt_regs(task);
46
47         if (regno & 3 || regno > PT_LAST_PSEUDO)
48                 return -EIO;
49
50         switch (regno) {
51         case PT_TEXT_ADDR:
52                 tmp = task->mm->start_code;
53                 break;
54         case PT_TEXT_END_ADDR:
55                 tmp = task->mm->end_code;
56                 break;
57         case PT_DATA_ADDR:
58                 tmp = task->mm->start_data;
59                 break;
60         case PT_USP:
61                 tmp = task->thread.usp;
62                 break;
63         default:
64                 if (regno < sizeof(*regs)) {
65                         void *reg_ptr = regs;
66                         tmp = *(long *)(reg_ptr + regno);
67                 } else
68                         return -EIO;
69         }
70
71         return put_user(tmp, datap);
72 }
73
74 /*
75  * Write contents of register REGNO in task TASK.
76  */
77 static inline int
78 put_reg(struct task_struct *task, unsigned long regno, unsigned long data)
79 {
80         struct pt_regs *regs = task_pt_regs(task);
81
82         if (regno & 3 || regno > PT_LAST_PSEUDO)
83                 return -EIO;
84
85         switch (regno) {
86         case PT_PC:
87                 /*********************************************************************/
88                 /* At this point the kernel is most likely in exception.             */
89                 /* The RETX register will be used to populate the pc of the process. */
90                 /*********************************************************************/
91                 regs->retx = data;
92                 regs->pc = data;
93                 break;
94         case PT_RETX:
95                 break;          /* regs->retx = data; break; */
96         case PT_USP:
97                 regs->usp = data;
98                 task->thread.usp = data;
99                 break;
100         case PT_SYSCFG: /* don't let userspace screw with this */
101                 if ((data & ~1) != 0x6)
102                         pr_warning("ptrace: ignore syscfg write of %#lx\n", data);
103                 break;          /* regs->syscfg = data; break; */
104         default:
105                 if (regno < sizeof(*regs)) {
106                         void *reg_offset = regs;
107                         *(long *)(reg_offset + regno) = data;
108                 }
109                 /* Ignore writes to pseudo registers */
110         }
111
112         return 0;
113 }
114
115 /*
116  * check that an address falls within the bounds of the target process's memory mappings
117  */
118 int
119 is_user_addr_valid(struct task_struct *child, unsigned long start, unsigned long len)
120 {
121         struct vm_area_struct *vma;
122         struct sram_list_struct *sraml;
123
124         /* overflow */
125         if (start + len < start)
126                 return -EIO;
127
128         vma = find_vma(child->mm, start);
129         if (vma && start >= vma->vm_start && start + len <= vma->vm_end)
130                         return 0;
131
132         for (sraml = child->mm->context.sram_list; sraml; sraml = sraml->next)
133                 if (start >= (unsigned long)sraml->addr
134                     && start + len < (unsigned long)sraml->addr + sraml->length)
135                         return 0;
136
137         if (start >= FIXED_CODE_START && start + len < FIXED_CODE_END)
138                 return 0;
139
140 #ifdef CONFIG_APP_STACK_L1
141         if (child->mm->context.l1_stack_save)
142                 if (start >= (unsigned long)l1_stack_base &&
143                         start + len < (unsigned long)l1_stack_base + l1_stack_len)
144                         return 0;
145 #endif
146
147         return -EIO;
148 }
149
150 /*
151  * retrieve the contents of Blackfin userspace general registers
152  */
153 static int genregs_get(struct task_struct *target,
154                        const struct user_regset *regset,
155                        unsigned int pos, unsigned int count,
156                        void *kbuf, void __user *ubuf)
157 {
158         struct pt_regs *regs = task_pt_regs(target);
159         int ret;
160
161         /* This sucks ... */
162         regs->usp = target->thread.usp;
163
164         ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
165                                   regs, 0, sizeof(*regs));
166         if (ret < 0)
167                 return ret;
168
169         return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
170                                         sizeof(*regs), -1);
171 }
172
173 /*
174  * update the contents of the Blackfin userspace general registers
175  */
176 static int genregs_set(struct task_struct *target,
177                        const struct user_regset *regset,
178                        unsigned int pos, unsigned int count,
179                        const void *kbuf, const void __user *ubuf)
180 {
181         struct pt_regs *regs = task_pt_regs(target);
182         int ret;
183
184         /* Don't let people set SYSCFG (it's at the end of pt_regs) */
185         ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
186                                  regs, 0, PT_SYSCFG);
187         if (ret < 0)
188                 return ret;
189
190         /* This sucks ... */
191         target->thread.usp = regs->usp;
192         /* regs->retx = regs->pc; */
193
194         return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
195                                         PT_SYSCFG, -1);
196 }
197
198 /*
199  * Define the register sets available on the Blackfin under Linux
200  */
201 enum bfin_regset {
202         REGSET_GENERAL,
203 };
204
205 static const struct user_regset bfin_regsets[] = {
206         [REGSET_GENERAL] = {
207                 .core_note_type = NT_PRSTATUS,
208                 .n              = sizeof(struct pt_regs) / sizeof(long),
209                 .size           = sizeof(long),
210                 .align          = sizeof(long),
211                 .get            = genregs_get,
212                 .set            = genregs_set,
213         },
214 };
215
216 static const struct user_regset_view user_bfin_native_view = {
217         .name      = "Blackfin",
218         .e_machine = EM_BLACKFIN,
219         .regsets   = bfin_regsets,
220         .n         = ARRAY_SIZE(bfin_regsets),
221 };
222
223 const struct user_regset_view *task_user_regset_view(struct task_struct *task)
224 {
225         return &user_bfin_native_view;
226 }
227
228 void user_enable_single_step(struct task_struct *child)
229 {
230         struct pt_regs *regs = task_pt_regs(child);
231         regs->syscfg |= SYSCFG_SSSTEP;
232
233         set_tsk_thread_flag(child, TIF_SINGLESTEP);
234 }
235
236 void user_disable_single_step(struct task_struct *child)
237 {
238         struct pt_regs *regs = task_pt_regs(child);
239         regs->syscfg &= ~SYSCFG_SSSTEP;
240
241         clear_tsk_thread_flag(child, TIF_SINGLESTEP);
242 }
243
244 long arch_ptrace(struct task_struct *child, long request,
245                  unsigned long addr, unsigned long data)
246 {
247         int ret;
248         unsigned long __user *datap = (unsigned long __user *)data;
249         void *paddr = (void *)addr;
250
251         switch (request) {
252                 /* when I and D space are separate, these will need to be fixed. */
253         case PTRACE_PEEKDATA:
254                 pr_debug("ptrace: PEEKDATA\n");
255                 /* fall through */
256         case PTRACE_PEEKTEXT:   /* read word at location addr. */
257                 {
258                         unsigned long tmp = 0;
259                         int copied = 0, to_copy = sizeof(tmp);
260
261                         ret = -EIO;
262                         pr_debug("ptrace: PEEKTEXT at addr 0x%08lx + %i\n", addr, to_copy);
263                         if (is_user_addr_valid(child, addr, to_copy) < 0)
264                                 break;
265                         pr_debug("ptrace: user address is valid\n");
266
267                         switch (bfin_mem_access_type(addr, to_copy)) {
268                         case BFIN_MEM_ACCESS_CORE:
269                         case BFIN_MEM_ACCESS_CORE_ONLY:
270                                 copied = access_process_vm(child, addr, &tmp,
271                                                            to_copy, 0);
272                                 if (copied)
273                                         break;
274
275                                 /* hrm, why didn't that work ... maybe no mapping */
276                                 if (addr >= FIXED_CODE_START &&
277                                     addr + to_copy <= FIXED_CODE_END) {
278                                         copy_from_user_page(0, 0, 0, &tmp, paddr, to_copy);
279                                         copied = to_copy;
280                                 } else if (addr >= BOOT_ROM_START) {
281                                         memcpy(&tmp, paddr, to_copy);
282                                         copied = to_copy;
283                                 }
284
285                                 break;
286                         case BFIN_MEM_ACCESS_DMA:
287                                 if (safe_dma_memcpy(&tmp, paddr, to_copy))
288                                         copied = to_copy;
289                                 break;
290                         case BFIN_MEM_ACCESS_ITEST:
291                                 if (isram_memcpy(&tmp, paddr, to_copy))
292                                         copied = to_copy;
293                                 break;
294                         default:
295                                 copied = 0;
296                                 break;
297                         }
298
299                         pr_debug("ptrace: copied size %d [0x%08lx]\n", copied, tmp);
300                         if (copied == to_copy)
301                                 ret = put_user(tmp, datap);
302                         break;
303                 }
304
305                 /* when I and D space are separate, this will have to be fixed. */
306         case PTRACE_POKEDATA:
307                 pr_debug("ptrace: PTRACE_PEEKDATA\n");
308                 /* fall through */
309         case PTRACE_POKETEXT:   /* write the word at location addr. */
310                 {
311                         int copied = 0, to_copy = sizeof(data);
312
313                         ret = -EIO;
314                         pr_debug("ptrace: POKETEXT at addr 0x%08lx + %i bytes %lx\n",
315                                  addr, to_copy, data);
316                         if (is_user_addr_valid(child, addr, to_copy) < 0)
317                                 break;
318                         pr_debug("ptrace: user address is valid\n");
319
320                         switch (bfin_mem_access_type(addr, to_copy)) {
321                         case BFIN_MEM_ACCESS_CORE:
322                         case BFIN_MEM_ACCESS_CORE_ONLY:
323                                 copied = access_process_vm(child, addr, &data,
324                                                            to_copy, 1);
325                                 break;
326                         case BFIN_MEM_ACCESS_DMA:
327                                 if (safe_dma_memcpy(paddr, &data, to_copy))
328                                         copied = to_copy;
329                                 break;
330                         case BFIN_MEM_ACCESS_ITEST:
331                                 if (isram_memcpy(paddr, &data, to_copy))
332                                         copied = to_copy;
333                                 break;
334                         default:
335                                 copied = 0;
336                                 break;
337                         }
338
339                         pr_debug("ptrace: copied size %d\n", copied);
340                         if (copied == to_copy)
341                                 ret = 0;
342                         break;
343                 }
344
345         case PTRACE_PEEKUSR:
346                 switch (addr) {
347 #ifdef CONFIG_BINFMT_ELF_FDPIC  /* backwards compat */
348                 case PT_FDPIC_EXEC:
349                         request = PTRACE_GETFDPIC;
350                         addr = PTRACE_GETFDPIC_EXEC;
351                         goto case_default;
352                 case PT_FDPIC_INTERP:
353                         request = PTRACE_GETFDPIC;
354                         addr = PTRACE_GETFDPIC_INTERP;
355                         goto case_default;
356 #endif
357                 default:
358                         ret = get_reg(child, addr, datap);
359                 }
360                 pr_debug("ptrace: PEEKUSR reg %li with %#lx = %i\n", addr, data, ret);
361                 break;
362
363         case PTRACE_POKEUSR:
364                 ret = put_reg(child, addr, data);
365                 pr_debug("ptrace: POKEUSR reg %li with %li = %i\n", addr, data, ret);
366                 break;
367
368         case PTRACE_GETREGS:
369                 pr_debug("ptrace: PTRACE_GETREGS\n");
370                 return copy_regset_to_user(child, &user_bfin_native_view,
371                                            REGSET_GENERAL,
372                                            0, sizeof(struct pt_regs),
373                                            datap);
374
375         case PTRACE_SETREGS:
376                 pr_debug("ptrace: PTRACE_SETREGS\n");
377                 return copy_regset_from_user(child, &user_bfin_native_view,
378                                              REGSET_GENERAL,
379                                              0, sizeof(struct pt_regs),
380                                              datap);
381
382         case_default:
383         default:
384                 ret = ptrace_request(child, request, addr, data);
385                 break;
386         }
387
388         return ret;
389 }
390
391 asmlinkage int syscall_trace_enter(struct pt_regs *regs)
392 {
393         int ret = 0;
394
395         if (test_thread_flag(TIF_SYSCALL_TRACE))
396                 ret = tracehook_report_syscall_entry(regs);
397
398         return ret;
399 }
400
401 asmlinkage void syscall_trace_leave(struct pt_regs *regs)
402 {
403         int step;
404
405         step = test_thread_flag(TIF_SINGLESTEP);
406         if (step || test_thread_flag(TIF_SYSCALL_TRACE))
407                 tracehook_report_syscall_exit(regs, step);
408 }