Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging-2.6
[linux-2.6] / arch / powerpc / kernel / ptrace32.c
1 /*
2  * ptrace for 32-bit processes running on a 64-bit kernel.
3  *
4  *  PowerPC version
5  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
6  *
7  *  Derived from "arch/m68k/kernel/ptrace.c"
8  *  Copyright (C) 1994 by Hamish Macdonald
9  *  Taken from linux/kernel/ptrace.c and modified for M680x0.
10  *  linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
11  *
12  * Modified by Cort Dougan (cort@hq.fsmlabs.com)
13  * and Paul Mackerras (paulus@samba.org).
14  *
15  * This file is subject to the terms and conditions of the GNU General
16  * Public License.  See the file COPYING in the main directory of
17  * this archive for more details.
18  */
19
20 #include <linux/kernel.h>
21 #include <linux/sched.h>
22 #include <linux/mm.h>
23 #include <linux/smp.h>
24 #include <linux/smp_lock.h>
25 #include <linux/errno.h>
26 #include <linux/ptrace.h>
27 #include <linux/regset.h>
28 #include <linux/user.h>
29 #include <linux/security.h>
30 #include <linux/signal.h>
31 #include <linux/compat.h>
32
33 #include <asm/uaccess.h>
34 #include <asm/page.h>
35 #include <asm/pgtable.h>
36 #include <asm/system.h>
37
38 /*
39  * does not yet catch signals sent when the child dies.
40  * in exit.c or in signal.c.
41  */
42
43 /*
44  * Here are the old "legacy" powerpc specific getregs/setregs ptrace calls,
45  * we mark them as obsolete now, they will be removed in a future version
46  */
47 static long compat_ptrace_old(struct task_struct *child, long request,
48                               long addr, long data)
49 {
50         switch (request) {
51         case PPC_PTRACE_GETREGS:        /* Get GPRs 0 - 31. */
52                 return copy_regset_to_user(child,
53                                            task_user_regset_view(current), 0,
54                                            0, 32 * sizeof(compat_long_t),
55                                            compat_ptr(data));
56
57         case PPC_PTRACE_SETREGS:        /* Set GPRs 0 - 31. */
58                 return copy_regset_from_user(child,
59                                              task_user_regset_view(current), 0,
60                                              0, 32 * sizeof(compat_long_t),
61                                              compat_ptr(data));
62         }
63
64         return -EPERM;
65 }
66
67 /* Macros to workout the correct index for the FPR in the thread struct */
68 #define FPRNUMBER(i) (((i) - PT_FPR0) >> 1)
69 #define FPRHALF(i) (((i) - PT_FPR0) & 1)
70 #define FPRINDEX(i) TS_FPRWIDTH * FPRNUMBER(i) * 2 + FPRHALF(i)
71 #define FPRINDEX_3264(i) (TS_FPRWIDTH * ((i) - PT_FPR0))
72
73 long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
74                         compat_ulong_t caddr, compat_ulong_t cdata)
75 {
76         unsigned long addr = caddr;
77         unsigned long data = cdata;
78         int ret;
79
80         switch (request) {
81         /*
82          * Read 4 bytes of the other process' storage
83          *  data is a pointer specifying where the user wants the
84          *      4 bytes copied into
85          *  addr is a pointer in the user's storage that contains an 8 byte
86          *      address in the other process of the 4 bytes that is to be read
87          * (this is run in a 32-bit process looking at a 64-bit process)
88          * when I and D space are separate, these will need to be fixed.
89          */
90         case PPC_PTRACE_PEEKTEXT_3264:
91         case PPC_PTRACE_PEEKDATA_3264: {
92                 u32 tmp;
93                 int copied;
94                 u32 __user * addrOthers;
95
96                 ret = -EIO;
97
98                 /* Get the addr in the other process that we want to read */
99                 if (get_user(addrOthers, (u32 __user * __user *)addr) != 0)
100                         break;
101
102                 copied = access_process_vm(child, (u64)addrOthers, &tmp,
103                                 sizeof(tmp), 0);
104                 if (copied != sizeof(tmp))
105                         break;
106                 ret = put_user(tmp, (u32 __user *)data);
107                 break;
108         }
109
110         /* Read a register (specified by ADDR) out of the "user area" */
111         case PTRACE_PEEKUSR: {
112                 int index;
113                 unsigned long tmp;
114
115                 ret = -EIO;
116                 /* convert to index and check */
117                 index = (unsigned long) addr >> 2;
118                 if ((addr & 3) || (index > PT_FPSCR32))
119                         break;
120
121                 CHECK_FULL_REGS(child->thread.regs);
122                 if (index < PT_FPR0) {
123                         tmp = ptrace_get_reg(child, index);
124                 } else {
125                         flush_fp_to_thread(child);
126                         /*
127                          * the user space code considers the floating point
128                          * to be an array of unsigned int (32 bits) - the
129                          * index passed in is based on this assumption.
130                          */
131                         tmp = ((unsigned int *)child->thread.fpr)
132                                 [FPRINDEX(index)];
133                 }
134                 ret = put_user((unsigned int)tmp, (u32 __user *)data);
135                 break;
136         }
137   
138         /*
139          * Read 4 bytes out of the other process' pt_regs area
140          *  data is a pointer specifying where the user wants the
141          *      4 bytes copied into
142          *  addr is the offset into the other process' pt_regs structure
143          *      that is to be read
144          * (this is run in a 32-bit process looking at a 64-bit process)
145          */
146         case PPC_PTRACE_PEEKUSR_3264: {
147                 u32 index;
148                 u32 reg32bits;
149                 u64 tmp;
150                 u32 numReg;
151                 u32 part;
152
153                 ret = -EIO;
154                 /* Determine which register the user wants */
155                 index = (u64)addr >> 2;
156                 numReg = index / 2;
157                 /* Determine which part of the register the user wants */
158                 if (index % 2)
159                         part = 1;  /* want the 2nd half of the register (right-most). */
160                 else
161                         part = 0;  /* want the 1st half of the register (left-most). */
162
163                 /* Validate the input - check to see if address is on the wrong boundary
164                  * or beyond the end of the user area
165                  */
166                 if ((addr & 3) || numReg > PT_FPSCR)
167                         break;
168
169                 CHECK_FULL_REGS(child->thread.regs);
170                 if (numReg >= PT_FPR0) {
171                         flush_fp_to_thread(child);
172                         /* get 64 bit FPR */
173                         tmp = ((u64 *)child->thread.fpr)
174                                 [FPRINDEX_3264(numReg)];
175                 } else { /* register within PT_REGS struct */
176                         tmp = ptrace_get_reg(child, numReg);
177                 } 
178                 reg32bits = ((u32*)&tmp)[part];
179                 ret = put_user(reg32bits, (u32 __user *)data);
180                 break;
181         }
182
183         /*
184          * Write 4 bytes into the other process' storage
185          *  data is the 4 bytes that the user wants written
186          *  addr is a pointer in the user's storage that contains an
187          *      8 byte address in the other process where the 4 bytes
188          *      that is to be written
189          * (this is run in a 32-bit process looking at a 64-bit process)
190          * when I and D space are separate, these will need to be fixed.
191          */
192         case PPC_PTRACE_POKETEXT_3264:
193         case PPC_PTRACE_POKEDATA_3264: {
194                 u32 tmp = data;
195                 u32 __user * addrOthers;
196
197                 /* Get the addr in the other process that we want to write into */
198                 ret = -EIO;
199                 if (get_user(addrOthers, (u32 __user * __user *)addr) != 0)
200                         break;
201                 ret = 0;
202                 if (access_process_vm(child, (u64)addrOthers, &tmp,
203                                         sizeof(tmp), 1) == sizeof(tmp))
204                         break;
205                 ret = -EIO;
206                 break;
207         }
208
209         /* write the word at location addr in the USER area */
210         case PTRACE_POKEUSR: {
211                 unsigned long index;
212
213                 ret = -EIO;
214                 /* convert to index and check */
215                 index = (unsigned long) addr >> 2;
216                 if ((addr & 3) || (index > PT_FPSCR32))
217                         break;
218
219                 CHECK_FULL_REGS(child->thread.regs);
220                 if (index < PT_FPR0) {
221                         ret = ptrace_put_reg(child, index, data);
222                 } else {
223                         flush_fp_to_thread(child);
224                         /*
225                          * the user space code considers the floating point
226                          * to be an array of unsigned int (32 bits) - the
227                          * index passed in is based on this assumption.
228                          */
229                         ((unsigned int *)child->thread.fpr)
230                                 [FPRINDEX(index)] = data;
231                         ret = 0;
232                 }
233                 break;
234         }
235
236         /*
237          * Write 4 bytes into the other process' pt_regs area
238          *  data is the 4 bytes that the user wants written
239          *  addr is the offset into the other process' pt_regs structure
240          *      that is to be written into
241          * (this is run in a 32-bit process looking at a 64-bit process)
242          */
243         case PPC_PTRACE_POKEUSR_3264: {
244                 u32 index;
245                 u32 numReg;
246
247                 ret = -EIO;
248                 /* Determine which register the user wants */
249                 index = (u64)addr >> 2;
250                 numReg = index / 2;
251
252                 /*
253                  * Validate the input - check to see if address is on the
254                  * wrong boundary or beyond the end of the user area
255                  */
256                 if ((addr & 3) || (numReg > PT_FPSCR))
257                         break;
258                 CHECK_FULL_REGS(child->thread.regs);
259                 if (numReg < PT_FPR0) {
260                         unsigned long freg = ptrace_get_reg(child, numReg);
261                         if (index % 2)
262                                 freg = (freg & ~0xfffffffful) | (data & 0xfffffffful);
263                         else
264                                 freg = (freg & 0xfffffffful) | (data << 32);
265                         ret = ptrace_put_reg(child, numReg, freg);
266                 } else {
267                         u64 *tmp;
268                         flush_fp_to_thread(child);
269                         /* get 64 bit FPR ... */
270                         tmp = &(((u64 *)child->thread.fpr)
271                                 [FPRINDEX_3264(numReg)]);
272                         /* ... write the 32 bit part we want */
273                         ((u32 *)tmp)[index % 2] = data;
274                         ret = 0;
275                 }
276                 break;
277         }
278
279         case PTRACE_GET_DEBUGREG: {
280                 ret = -EINVAL;
281                 /* We only support one DABR and no IABRS at the moment */
282                 if (addr > 0)
283                         break;
284                 ret = put_user(child->thread.dabr, (u32 __user *)data);
285                 break;
286         }
287
288         case PTRACE_GETREGS:    /* Get all pt_regs from the child. */
289                 return copy_regset_to_user(
290                         child, task_user_regset_view(current), 0,
291                         0, PT_REGS_COUNT * sizeof(compat_long_t),
292                         compat_ptr(data));
293
294         case PTRACE_SETREGS:    /* Set all gp regs in the child. */
295                 return copy_regset_from_user(
296                         child, task_user_regset_view(current), 0,
297                         0, PT_REGS_COUNT * sizeof(compat_long_t),
298                         compat_ptr(data));
299
300         case PTRACE_GETFPREGS:
301         case PTRACE_SETFPREGS:
302         case PTRACE_GETVRREGS:
303         case PTRACE_SETVRREGS:
304         case PTRACE_GETVSRREGS:
305         case PTRACE_SETVSRREGS:
306         case PTRACE_GETREGS64:
307         case PTRACE_SETREGS64:
308         case PPC_PTRACE_GETFPREGS:
309         case PPC_PTRACE_SETFPREGS:
310         case PTRACE_KILL:
311         case PTRACE_SINGLESTEP:
312         case PTRACE_DETACH:
313         case PTRACE_SET_DEBUGREG:
314         case PTRACE_SYSCALL:
315         case PTRACE_CONT:
316                 ret = arch_ptrace(child, request, addr, data);
317                 break;
318
319         /* Old reverse args ptrace callss */
320         case PPC_PTRACE_GETREGS: /* Get GPRs 0 - 31. */
321         case PPC_PTRACE_SETREGS: /* Set GPRs 0 - 31. */
322                 ret = compat_ptrace_old(child, request, addr, data);
323                 break;
324
325         default:
326                 ret = compat_ptrace_request(child, request, addr, data);
327                 break;
328         }
329
330         return ret;
331 }