2f6524d1a817a3906f99109edfb953217bb16c1a
[pandora-kernel.git] / arch / sparc / kernel / ptrace_64.c
1 /* ptrace.c: Sparc process tracing support.
2  *
3  * Copyright (C) 1996, 2008 David S. Miller (davem@davemloft.net)
4  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
5  *
6  * Based upon code written by Ross Biro, Linus Torvalds, Bob Manson,
7  * and David Mosberger.
8  *
9  * Added Linux support -miguel (weird, eh?, the original code was meant
10  * to emulate SunOS).
11  */
12
13 #include <linux/kernel.h>
14 #include <linux/sched.h>
15 #include <linux/mm.h>
16 #include <linux/errno.h>
17 #include <linux/ptrace.h>
18 #include <linux/user.h>
19 #include <linux/smp.h>
20 #include <linux/security.h>
21 #include <linux/seccomp.h>
22 #include <linux/audit.h>
23 #include <linux/signal.h>
24 #include <linux/regset.h>
25 #include <linux/tracehook.h>
26 #include <trace/syscall.h>
27 #include <linux/compat.h>
28 #include <linux/elf.h>
29
30 #include <asm/asi.h>
31 #include <asm/pgtable.h>
32 #include <asm/system.h>
33 #include <asm/uaccess.h>
34 #include <asm/psrcompat.h>
35 #include <asm/visasm.h>
36 #include <asm/spitfire.h>
37 #include <asm/page.h>
38 #include <asm/cpudata.h>
39 #include <asm/cacheflush.h>
40
41 #define CREATE_TRACE_POINTS
42 #include <trace/events/syscalls.h>
43
44 #include "entry.h"
45
46 /* #define ALLOW_INIT_TRACING */
47
48 /*
49  * Called by kernel/ptrace.c when detaching..
50  *
51  * Make sure single step bits etc are not set.
52  */
53 void ptrace_disable(struct task_struct *child)
54 {
55         /* nothing to do */
56 }
57
58 /* To get the necessary page struct, access_process_vm() first calls
59  * get_user_pages().  This has done a flush_dcache_page() on the
60  * accessed page.  Then our caller (copy_{to,from}_user_page()) did
61  * to memcpy to read/write the data from that page.
62  *
63  * Now, the only thing we have to do is:
64  * 1) flush the D-cache if it's possible than an illegal alias
65  *    has been created
66  * 2) flush the I-cache if this is pre-cheetah and we did a write
67  */
68 void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
69                          unsigned long uaddr, void *kaddr,
70                          unsigned long len, int write)
71 {
72         BUG_ON(len > PAGE_SIZE);
73
74         if (tlb_type == hypervisor)
75                 return;
76
77         preempt_disable();
78
79 #ifdef DCACHE_ALIASING_POSSIBLE
80         /* If bit 13 of the kernel address we used to access the
81          * user page is the same as the virtual address that page
82          * is mapped to in the user's address space, we can skip the
83          * D-cache flush.
84          */
85         if ((uaddr ^ (unsigned long) kaddr) & (1UL << 13)) {
86                 unsigned long start = __pa(kaddr);
87                 unsigned long end = start + len;
88                 unsigned long dcache_line_size;
89
90                 dcache_line_size = local_cpu_data().dcache_line_size;
91
92                 if (tlb_type == spitfire) {
93                         for (; start < end; start += dcache_line_size)
94                                 spitfire_put_dcache_tag(start & 0x3fe0, 0x0);
95                 } else {
96                         start &= ~(dcache_line_size - 1);
97                         for (; start < end; start += dcache_line_size)
98                                 __asm__ __volatile__(
99                                         "stxa %%g0, [%0] %1\n\t"
100                                         "membar #Sync"
101                                         : /* no outputs */
102                                         : "r" (start),
103                                         "i" (ASI_DCACHE_INVALIDATE));
104                 }
105         }
106 #endif
107         if (write && tlb_type == spitfire) {
108                 unsigned long start = (unsigned long) kaddr;
109                 unsigned long end = start + len;
110                 unsigned long icache_line_size;
111
112                 icache_line_size = local_cpu_data().icache_line_size;
113
114                 for (; start < end; start += icache_line_size)
115                         flushi(start);
116         }
117
118         preempt_enable();
119 }
120
121 static int get_from_target(struct task_struct *target, unsigned long uaddr,
122                            void *kbuf, int len)
123 {
124         if (target == current) {
125                 if (copy_from_user(kbuf, (void __user *) uaddr, len))
126                         return -EFAULT;
127         } else {
128                 int len2 = access_process_vm(target, uaddr, kbuf, len, 0);
129                 if (len2 != len)
130                         return -EFAULT;
131         }
132         return 0;
133 }
134
135 static int set_to_target(struct task_struct *target, unsigned long uaddr,
136                          void *kbuf, int len)
137 {
138         if (target == current) {
139                 if (copy_to_user((void __user *) uaddr, kbuf, len))
140                         return -EFAULT;
141         } else {
142                 int len2 = access_process_vm(target, uaddr, kbuf, len, 1);
143                 if (len2 != len)
144                         return -EFAULT;
145         }
146         return 0;
147 }
148
149 static int regwindow64_get(struct task_struct *target,
150                            const struct pt_regs *regs,
151                            struct reg_window *wbuf)
152 {
153         unsigned long rw_addr = regs->u_regs[UREG_I6];
154
155         if (test_tsk_thread_flag(current, TIF_32BIT)) {
156                 struct reg_window32 win32;
157                 int i;
158
159                 if (get_from_target(target, rw_addr, &win32, sizeof(win32)))
160                         return -EFAULT;
161                 for (i = 0; i < 8; i++)
162                         wbuf->locals[i] = win32.locals[i];
163                 for (i = 0; i < 8; i++)
164                         wbuf->ins[i] = win32.ins[i];
165         } else {
166                 rw_addr += STACK_BIAS;
167                 if (get_from_target(target, rw_addr, wbuf, sizeof(*wbuf)))
168                         return -EFAULT;
169         }
170
171         return 0;
172 }
173
174 static int regwindow64_set(struct task_struct *target,
175                            const struct pt_regs *regs,
176                            struct reg_window *wbuf)
177 {
178         unsigned long rw_addr = regs->u_regs[UREG_I6];
179
180         if (test_tsk_thread_flag(current, TIF_32BIT)) {
181                 struct reg_window32 win32;
182                 int i;
183
184                 for (i = 0; i < 8; i++)
185                         win32.locals[i] = wbuf->locals[i];
186                 for (i = 0; i < 8; i++)
187                         win32.ins[i] = wbuf->ins[i];
188
189                 if (set_to_target(target, rw_addr, &win32, sizeof(win32)))
190                         return -EFAULT;
191         } else {
192                 rw_addr += STACK_BIAS;
193                 if (set_to_target(target, rw_addr, wbuf, sizeof(*wbuf)))
194                         return -EFAULT;
195         }
196
197         return 0;
198 }
199
200 enum sparc_regset {
201         REGSET_GENERAL,
202         REGSET_FP,
203 };
204
205 static int genregs64_get(struct task_struct *target,
206                          const struct user_regset *regset,
207                          unsigned int pos, unsigned int count,
208                          void *kbuf, void __user *ubuf)
209 {
210         const struct pt_regs *regs = task_pt_regs(target);
211         int ret;
212
213         if (target == current)
214                 flushw_user();
215
216         ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
217                                   regs->u_regs,
218                                   0, 16 * sizeof(u64));
219         if (!ret && count && pos < (32 * sizeof(u64))) {
220                 struct reg_window window;
221
222                 if (regwindow64_get(target, regs, &window))
223                         return -EFAULT;
224                 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
225                                           &window,
226                                           16 * sizeof(u64),
227                                           32 * sizeof(u64));
228         }
229
230         if (!ret) {
231                 /* TSTATE, TPC, TNPC */
232                 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
233                                           &regs->tstate,
234                                           32 * sizeof(u64),
235                                           35 * sizeof(u64));
236         }
237
238         if (!ret) {
239                 unsigned long y = regs->y;
240
241                 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
242                                           &y,
243                                           35 * sizeof(u64),
244                                           36 * sizeof(u64));
245         }
246
247         if (!ret) {
248                 ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
249                                                36 * sizeof(u64), -1);
250
251         }
252         return ret;
253 }
254
255 static int genregs64_set(struct task_struct *target,
256                          const struct user_regset *regset,
257                          unsigned int pos, unsigned int count,
258                          const void *kbuf, const void __user *ubuf)
259 {
260         struct pt_regs *regs = task_pt_regs(target);
261         int ret;
262
263         if (target == current)
264                 flushw_user();
265
266         ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
267                                  regs->u_regs,
268                                  0, 16 * sizeof(u64));
269         if (!ret && count && pos < (32 * sizeof(u64))) {
270                 struct reg_window window;
271
272                 if (regwindow64_get(target, regs, &window))
273                         return -EFAULT;
274
275                 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
276                                          &window,
277                                          16 * sizeof(u64),
278                                          32 * sizeof(u64));
279
280                 if (!ret &&
281                     regwindow64_set(target, regs, &window))
282                         return -EFAULT;
283         }
284
285         if (!ret && count > 0) {
286                 unsigned long tstate;
287
288                 /* TSTATE */
289                 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
290                                          &tstate,
291                                          32 * sizeof(u64),
292                                          33 * sizeof(u64));
293                 if (!ret) {
294                         /* Only the condition codes and the "in syscall"
295                          * state can be modified in the %tstate register.
296                          */
297                         tstate &= (TSTATE_ICC | TSTATE_XCC | TSTATE_SYSCALL);
298                         regs->tstate &= ~(TSTATE_ICC | TSTATE_XCC | TSTATE_SYSCALL);
299                         regs->tstate |= tstate;
300                 }
301         }
302
303         if (!ret) {
304                 /* TPC, TNPC */
305                 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
306                                          &regs->tpc,
307                                          33 * sizeof(u64),
308                                          35 * sizeof(u64));
309         }
310
311         if (!ret) {
312                 unsigned long y;
313
314                 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
315                                          &y,
316                                          35 * sizeof(u64),
317                                          36 * sizeof(u64));
318                 if (!ret)
319                         regs->y = y;
320         }
321
322         if (!ret)
323                 ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
324                                                 36 * sizeof(u64), -1);
325
326         return ret;
327 }
328
329 static int fpregs64_get(struct task_struct *target,
330                         const struct user_regset *regset,
331                         unsigned int pos, unsigned int count,
332                         void *kbuf, void __user *ubuf)
333 {
334         const unsigned long *fpregs = task_thread_info(target)->fpregs;
335         unsigned long fprs, fsr, gsr;
336         int ret;
337
338         if (target == current)
339                 save_and_clear_fpu();
340
341         fprs = task_thread_info(target)->fpsaved[0];
342
343         if (fprs & FPRS_DL)
344                 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
345                                           fpregs,
346                                           0, 16 * sizeof(u64));
347         else
348                 ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
349                                                0,
350                                                16 * sizeof(u64));
351
352         if (!ret) {
353                 if (fprs & FPRS_DU)
354                         ret = user_regset_copyout(&pos, &count,
355                                                   &kbuf, &ubuf,
356                                                   fpregs + 16,
357                                                   16 * sizeof(u64),
358                                                   32 * sizeof(u64));
359                 else
360                         ret = user_regset_copyout_zero(&pos, &count,
361                                                        &kbuf, &ubuf,
362                                                        16 * sizeof(u64),
363                                                        32 * sizeof(u64));
364         }
365
366         if (fprs & FPRS_FEF) {
367                 fsr = task_thread_info(target)->xfsr[0];
368                 gsr = task_thread_info(target)->gsr[0];
369         } else {
370                 fsr = gsr = 0;
371         }
372
373         if (!ret)
374                 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
375                                           &fsr,
376                                           32 * sizeof(u64),
377                                           33 * sizeof(u64));
378         if (!ret)
379                 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
380                                           &gsr,
381                                           33 * sizeof(u64),
382                                           34 * sizeof(u64));
383         if (!ret)
384                 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
385                                           &fprs,
386                                           34 * sizeof(u64),
387                                           35 * sizeof(u64));
388
389         if (!ret)
390                 ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
391                                                35 * sizeof(u64), -1);
392
393         return ret;
394 }
395
396 static int fpregs64_set(struct task_struct *target,
397                         const struct user_regset *regset,
398                         unsigned int pos, unsigned int count,
399                         const void *kbuf, const void __user *ubuf)
400 {
401         unsigned long *fpregs = task_thread_info(target)->fpregs;
402         unsigned long fprs;
403         int ret;
404
405         if (target == current)
406                 save_and_clear_fpu();
407
408         ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
409                                  fpregs,
410                                  0, 32 * sizeof(u64));
411         if (!ret)
412                 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
413                                          task_thread_info(target)->xfsr,
414                                          32 * sizeof(u64),
415                                          33 * sizeof(u64));
416         if (!ret)
417                 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
418                                          task_thread_info(target)->gsr,
419                                          33 * sizeof(u64),
420                                          34 * sizeof(u64));
421
422         fprs = task_thread_info(target)->fpsaved[0];
423         if (!ret && count > 0) {
424                 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
425                                          &fprs,
426                                          34 * sizeof(u64),
427                                          35 * sizeof(u64));
428         }
429
430         fprs |= (FPRS_FEF | FPRS_DL | FPRS_DU);
431         task_thread_info(target)->fpsaved[0] = fprs;
432
433         if (!ret)
434                 ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
435                                                 35 * sizeof(u64), -1);
436         return ret;
437 }
438
439 static const struct user_regset sparc64_regsets[] = {
440         /* Format is:
441          *      G0 --> G7
442          *      O0 --> O7
443          *      L0 --> L7
444          *      I0 --> I7
445          *      TSTATE, TPC, TNPC, Y
446          */
447         [REGSET_GENERAL] = {
448                 .core_note_type = NT_PRSTATUS,
449                 .n = 36,
450                 .size = sizeof(u64), .align = sizeof(u64),
451                 .get = genregs64_get, .set = genregs64_set
452         },
453         /* Format is:
454          *      F0 --> F63
455          *      FSR
456          *      GSR
457          *      FPRS
458          */
459         [REGSET_FP] = {
460                 .core_note_type = NT_PRFPREG,
461                 .n = 35,
462                 .size = sizeof(u64), .align = sizeof(u64),
463                 .get = fpregs64_get, .set = fpregs64_set
464         },
465 };
466
467 static const struct user_regset_view user_sparc64_view = {
468         .name = "sparc64", .e_machine = EM_SPARCV9,
469         .regsets = sparc64_regsets, .n = ARRAY_SIZE(sparc64_regsets)
470 };
471
472 #ifdef CONFIG_COMPAT
473 static int genregs32_get(struct task_struct *target,
474                          const struct user_regset *regset,
475                          unsigned int pos, unsigned int count,
476                          void *kbuf, void __user *ubuf)
477 {
478         const struct pt_regs *regs = task_pt_regs(target);
479         compat_ulong_t __user *reg_window;
480         compat_ulong_t *k = kbuf;
481         compat_ulong_t __user *u = ubuf;
482         compat_ulong_t reg;
483
484         if (target == current)
485                 flushw_user();
486
487         pos /= sizeof(reg);
488         count /= sizeof(reg);
489
490         if (kbuf) {
491                 for (; count > 0 && pos < 16; count--)
492                         *k++ = regs->u_regs[pos++];
493
494                 reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6];
495                 if (target == current) {
496                         for (; count > 0 && pos < 32; count--) {
497                                 if (get_user(*k++, &reg_window[pos++]))
498                                         return -EFAULT;
499                         }
500                 } else {
501                         for (; count > 0 && pos < 32; count--) {
502                                 if (access_process_vm(target,
503                                                       (unsigned long)
504                                                       &reg_window[pos],
505                                                       k, sizeof(*k), 0)
506                                     != sizeof(*k))
507                                         return -EFAULT;
508                                 k++;
509                                 pos++;
510                         }
511                 }
512         } else {
513                 for (; count > 0 && pos < 16; count--) {
514                         if (put_user((compat_ulong_t) regs->u_regs[pos++], u++))
515                                 return -EFAULT;
516                 }
517
518                 reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6];
519                 if (target == current) {
520                         for (; count > 0 && pos < 32; count--) {
521                                 if (get_user(reg, &reg_window[pos++]) ||
522                                     put_user(reg, u++))
523                                         return -EFAULT;
524                         }
525                 } else {
526                         for (; count > 0 && pos < 32; count--) {
527                                 if (access_process_vm(target,
528                                                       (unsigned long)
529                                                       &reg_window[pos],
530                                                       &reg, sizeof(reg), 0)
531                                     != sizeof(reg))
532                                         return -EFAULT;
533                                 if (access_process_vm(target,
534                                                       (unsigned long) u,
535                                                       &reg, sizeof(reg), 1)
536                                     != sizeof(reg))
537                                         return -EFAULT;
538                                 pos++;
539                                 u++;
540                         }
541                 }
542         }
543         while (count > 0) {
544                 switch (pos) {
545                 case 32: /* PSR */
546                         reg = tstate_to_psr(regs->tstate);
547                         break;
548                 case 33: /* PC */
549                         reg = regs->tpc;
550                         break;
551                 case 34: /* NPC */
552                         reg = regs->tnpc;
553                         break;
554                 case 35: /* Y */
555                         reg = regs->y;
556                         break;
557                 case 36: /* WIM */
558                 case 37: /* TBR */
559                         reg = 0;
560                         break;
561                 default:
562                         goto finish;
563                 }
564
565                 if (kbuf)
566                         *k++ = reg;
567                 else if (put_user(reg, u++))
568                         return -EFAULT;
569                 pos++;
570                 count--;
571         }
572 finish:
573         pos *= sizeof(reg);
574         count *= sizeof(reg);
575
576         return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
577                                         38 * sizeof(reg), -1);
578 }
579
580 static int genregs32_set(struct task_struct *target,
581                          const struct user_regset *regset,
582                          unsigned int pos, unsigned int count,
583                          const void *kbuf, const void __user *ubuf)
584 {
585         struct pt_regs *regs = task_pt_regs(target);
586         compat_ulong_t __user *reg_window;
587         const compat_ulong_t *k = kbuf;
588         const compat_ulong_t __user *u = ubuf;
589         compat_ulong_t reg;
590
591         if (target == current)
592                 flushw_user();
593
594         pos /= sizeof(reg);
595         count /= sizeof(reg);
596
597         if (kbuf) {
598                 for (; count > 0 && pos < 16; count--)
599                         regs->u_regs[pos++] = *k++;
600
601                 reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6];
602                 if (target == current) {
603                         for (; count > 0 && pos < 32; count--) {
604                                 if (put_user(*k++, &reg_window[pos++]))
605                                         return -EFAULT;
606                         }
607                 } else {
608                         for (; count > 0 && pos < 32; count--) {
609                                 if (access_process_vm(target,
610                                                       (unsigned long)
611                                                       &reg_window[pos],
612                                                       (void *) k,
613                                                       sizeof(*k), 1)
614                                     != sizeof(*k))
615                                         return -EFAULT;
616                                 k++;
617                                 pos++;
618                         }
619                 }
620         } else {
621                 for (; count > 0 && pos < 16; count--) {
622                         if (get_user(reg, u++))
623                                 return -EFAULT;
624                         regs->u_regs[pos++] = reg;
625                 }
626
627                 reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6];
628                 if (target == current) {
629                         for (; count > 0 && pos < 32; count--) {
630                                 if (get_user(reg, u++) ||
631                                     put_user(reg, &reg_window[pos++]))
632                                         return -EFAULT;
633                         }
634                 } else {
635                         for (; count > 0 && pos < 32; count--) {
636                                 if (access_process_vm(target,
637                                                       (unsigned long)
638                                                       u,
639                                                       &reg, sizeof(reg), 0)
640                                     != sizeof(reg))
641                                         return -EFAULT;
642                                 if (access_process_vm(target,
643                                                       (unsigned long)
644                                                       &reg_window[pos],
645                                                       &reg, sizeof(reg), 1)
646                                     != sizeof(reg))
647                                         return -EFAULT;
648                                 pos++;
649                                 u++;
650                         }
651                 }
652         }
653         while (count > 0) {
654                 unsigned long tstate;
655
656                 if (kbuf)
657                         reg = *k++;
658                 else if (get_user(reg, u++))
659                         return -EFAULT;
660
661                 switch (pos) {
662                 case 32: /* PSR */
663                         tstate = regs->tstate;
664                         tstate &= ~(TSTATE_ICC | TSTATE_XCC | TSTATE_SYSCALL);
665                         tstate |= psr_to_tstate_icc(reg);
666                         if (reg & PSR_SYSCALL)
667                                 tstate |= TSTATE_SYSCALL;
668                         regs->tstate = tstate;
669                         break;
670                 case 33: /* PC */
671                         regs->tpc = reg;
672                         break;
673                 case 34: /* NPC */
674                         regs->tnpc = reg;
675                         break;
676                 case 35: /* Y */
677                         regs->y = reg;
678                         break;
679                 case 36: /* WIM */
680                 case 37: /* TBR */
681                         break;
682                 default:
683                         goto finish;
684                 }
685
686                 pos++;
687                 count--;
688         }
689 finish:
690         pos *= sizeof(reg);
691         count *= sizeof(reg);
692
693         return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
694                                          38 * sizeof(reg), -1);
695 }
696
697 static int fpregs32_get(struct task_struct *target,
698                         const struct user_regset *regset,
699                         unsigned int pos, unsigned int count,
700                         void *kbuf, void __user *ubuf)
701 {
702         const unsigned long *fpregs = task_thread_info(target)->fpregs;
703         compat_ulong_t enabled;
704         unsigned long fprs;
705         compat_ulong_t fsr;
706         int ret = 0;
707
708         if (target == current)
709                 save_and_clear_fpu();
710
711         fprs = task_thread_info(target)->fpsaved[0];
712         if (fprs & FPRS_FEF) {
713                 fsr = task_thread_info(target)->xfsr[0];
714                 enabled = 1;
715         } else {
716                 fsr = 0;
717                 enabled = 0;
718         }
719
720         ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
721                                   fpregs,
722                                   0, 32 * sizeof(u32));
723
724         if (!ret)
725                 ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
726                                                32 * sizeof(u32),
727                                                33 * sizeof(u32));
728         if (!ret)
729                 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
730                                           &fsr,
731                                           33 * sizeof(u32),
732                                           34 * sizeof(u32));
733
734         if (!ret) {
735                 compat_ulong_t val;
736
737                 val = (enabled << 8) | (8 << 16);
738                 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
739                                           &val,
740                                           34 * sizeof(u32),
741                                           35 * sizeof(u32));
742         }
743
744         if (!ret)
745                 ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
746                                                35 * sizeof(u32), -1);
747
748         return ret;
749 }
750
751 static int fpregs32_set(struct task_struct *target,
752                         const struct user_regset *regset,
753                         unsigned int pos, unsigned int count,
754                         const void *kbuf, const void __user *ubuf)
755 {
756         unsigned long *fpregs = task_thread_info(target)->fpregs;
757         unsigned long fprs;
758         int ret;
759
760         if (target == current)
761                 save_and_clear_fpu();
762
763         fprs = task_thread_info(target)->fpsaved[0];
764
765         ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
766                                  fpregs,
767                                  0, 32 * sizeof(u32));
768         if (!ret)
769                 user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
770                                           32 * sizeof(u32),
771                                           33 * sizeof(u32));
772         if (!ret && count > 0) {
773                 compat_ulong_t fsr;
774                 unsigned long val;
775
776                 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
777                                          &fsr,
778                                          33 * sizeof(u32),
779                                          34 * sizeof(u32));
780                 if (!ret) {
781                         val = task_thread_info(target)->xfsr[0];
782                         val &= 0xffffffff00000000UL;
783                         val |= fsr;
784                         task_thread_info(target)->xfsr[0] = val;
785                 }
786         }
787
788         fprs |= (FPRS_FEF | FPRS_DL);
789         task_thread_info(target)->fpsaved[0] = fprs;
790
791         if (!ret)
792                 ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
793                                                 34 * sizeof(u32), -1);
794         return ret;
795 }
796
797 static const struct user_regset sparc32_regsets[] = {
798         /* Format is:
799          *      G0 --> G7
800          *      O0 --> O7
801          *      L0 --> L7
802          *      I0 --> I7
803          *      PSR, PC, nPC, Y, WIM, TBR
804          */
805         [REGSET_GENERAL] = {
806                 .core_note_type = NT_PRSTATUS,
807                 .n = 38,
808                 .size = sizeof(u32), .align = sizeof(u32),
809                 .get = genregs32_get, .set = genregs32_set
810         },
811         /* Format is:
812          *      F0 --> F31
813          *      empty 32-bit word
814          *      FSR (32--bit word)
815          *      FPU QUEUE COUNT (8-bit char)
816          *      FPU QUEUE ENTRYSIZE (8-bit char)
817          *      FPU ENABLED (8-bit char)
818          *      empty 8-bit char
819          *      FPU QUEUE (64 32-bit ints)
820          */
821         [REGSET_FP] = {
822                 .core_note_type = NT_PRFPREG,
823                 .n = 99,
824                 .size = sizeof(u32), .align = sizeof(u32),
825                 .get = fpregs32_get, .set = fpregs32_set
826         },
827 };
828
829 static const struct user_regset_view user_sparc32_view = {
830         .name = "sparc", .e_machine = EM_SPARC,
831         .regsets = sparc32_regsets, .n = ARRAY_SIZE(sparc32_regsets)
832 };
833 #endif /* CONFIG_COMPAT */
834
835 const struct user_regset_view *task_user_regset_view(struct task_struct *task)
836 {
837 #ifdef CONFIG_COMPAT
838         if (test_tsk_thread_flag(task, TIF_32BIT))
839                 return &user_sparc32_view;
840 #endif
841         return &user_sparc64_view;
842 }
843
844 #ifdef CONFIG_COMPAT
845 struct compat_fps {
846         unsigned int regs[32];
847         unsigned int fsr;
848         unsigned int flags;
849         unsigned int extra;
850         unsigned int fpqd;
851         struct compat_fq {
852                 unsigned int insnaddr;
853                 unsigned int insn;
854         } fpq[16];
855 };
856
857 long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
858                         compat_ulong_t caddr, compat_ulong_t cdata)
859 {
860         const struct user_regset_view *view = task_user_regset_view(current);
861         compat_ulong_t caddr2 = task_pt_regs(current)->u_regs[UREG_I4];
862         struct pt_regs32 __user *pregs;
863         struct compat_fps __user *fps;
864         unsigned long addr2 = caddr2;
865         unsigned long addr = caddr;
866         unsigned long data = cdata;
867         int ret;
868
869         pregs = (struct pt_regs32 __user *) addr;
870         fps = (struct compat_fps __user *) addr;
871
872         switch (request) {
873         case PTRACE_PEEKUSR:
874                 ret = (addr != 0) ? -EIO : 0;
875                 break;
876
877         case PTRACE_GETREGS:
878                 ret = copy_regset_to_user(child, view, REGSET_GENERAL,
879                                           32 * sizeof(u32),
880                                           4 * sizeof(u32),
881                                           &pregs->psr);
882                 if (!ret)
883                         ret = copy_regset_to_user(child, view, REGSET_GENERAL,
884                                                   1 * sizeof(u32),
885                                                   15 * sizeof(u32),
886                                                   &pregs->u_regs[0]);
887                 break;
888
889         case PTRACE_SETREGS:
890                 ret = copy_regset_from_user(child, view, REGSET_GENERAL,
891                                             32 * sizeof(u32),
892                                             4 * sizeof(u32),
893                                             &pregs->psr);
894                 if (!ret)
895                         ret = copy_regset_from_user(child, view, REGSET_GENERAL,
896                                                     1 * sizeof(u32),
897                                                     15 * sizeof(u32),
898                                                     &pregs->u_regs[0]);
899                 break;
900
901         case PTRACE_GETFPREGS:
902                 ret = copy_regset_to_user(child, view, REGSET_FP,
903                                           0 * sizeof(u32),
904                                           32 * sizeof(u32),
905                                           &fps->regs[0]);
906                 if (!ret)
907                         ret = copy_regset_to_user(child, view, REGSET_FP,
908                                                   33 * sizeof(u32),
909                                                   1 * sizeof(u32),
910                                                   &fps->fsr);
911                 if (!ret) {
912                         if (__put_user(0, &fps->flags) ||
913                             __put_user(0, &fps->extra) ||
914                             __put_user(0, &fps->fpqd) ||
915                             clear_user(&fps->fpq[0], 32 * sizeof(unsigned int)))
916                                 ret = -EFAULT;
917                 }
918                 break;
919
920         case PTRACE_SETFPREGS:
921                 ret = copy_regset_from_user(child, view, REGSET_FP,
922                                             0 * sizeof(u32),
923                                             32 * sizeof(u32),
924                                             &fps->regs[0]);
925                 if (!ret)
926                         ret = copy_regset_from_user(child, view, REGSET_FP,
927                                                     33 * sizeof(u32),
928                                                     1 * sizeof(u32),
929                                                     &fps->fsr);
930                 break;
931
932         case PTRACE_READTEXT:
933         case PTRACE_READDATA:
934                 ret = ptrace_readdata(child, addr,
935                                       (char __user *)addr2, data);
936                 if (ret == data)
937                         ret = 0;
938                 else if (ret >= 0)
939                         ret = -EIO;
940                 break;
941
942         case PTRACE_WRITETEXT:
943         case PTRACE_WRITEDATA:
944                 ret = ptrace_writedata(child, (char __user *) addr2,
945                                        addr, data);
946                 if (ret == data)
947                         ret = 0;
948                 else if (ret >= 0)
949                         ret = -EIO;
950                 break;
951
952         default:
953                 if (request == PTRACE_SPARC_DETACH)
954                         request = PTRACE_DETACH;
955                 ret = compat_ptrace_request(child, request, addr, data);
956                 break;
957         }
958
959         return ret;
960 }
961 #endif /* CONFIG_COMPAT */
962
963 struct fps {
964         unsigned int regs[64];
965         unsigned long fsr;
966 };
967
968 long arch_ptrace(struct task_struct *child, long request, long addr, long data)
969 {
970         const struct user_regset_view *view = task_user_regset_view(current);
971         unsigned long addr2 = task_pt_regs(current)->u_regs[UREG_I4];
972         struct pt_regs __user *pregs;
973         struct fps __user *fps;
974         int ret;
975
976         pregs = (struct pt_regs __user *) (unsigned long) addr;
977         fps = (struct fps __user *) (unsigned long) addr;
978
979         switch (request) {
980         case PTRACE_PEEKUSR:
981                 ret = (addr != 0) ? -EIO : 0;
982                 break;
983
984         case PTRACE_GETREGS64:
985                 ret = copy_regset_to_user(child, view, REGSET_GENERAL,
986                                           1 * sizeof(u64),
987                                           15 * sizeof(u64),
988                                           &pregs->u_regs[0]);
989                 if (!ret) {
990                         /* XXX doesn't handle 'y' register correctly XXX */
991                         ret = copy_regset_to_user(child, view, REGSET_GENERAL,
992                                                   32 * sizeof(u64),
993                                                   4 * sizeof(u64),
994                                                   &pregs->tstate);
995                 }
996                 break;
997
998         case PTRACE_SETREGS64:
999                 ret = copy_regset_from_user(child, view, REGSET_GENERAL,
1000                                             1 * sizeof(u64),
1001                                             15 * sizeof(u64),
1002                                             &pregs->u_regs[0]);
1003                 if (!ret) {
1004                         /* XXX doesn't handle 'y' register correctly XXX */
1005                         ret = copy_regset_from_user(child, view, REGSET_GENERAL,
1006                                                     32 * sizeof(u64),
1007                                                     4 * sizeof(u64),
1008                                                     &pregs->tstate);
1009                 }
1010                 break;
1011
1012         case PTRACE_GETFPREGS64:
1013                 ret = copy_regset_to_user(child, view, REGSET_FP,
1014                                           0 * sizeof(u64),
1015                                           33 * sizeof(u64),
1016                                           fps);
1017                 break;
1018
1019         case PTRACE_SETFPREGS64:
1020                 ret = copy_regset_from_user(child, view, REGSET_FP,
1021                                           0 * sizeof(u64),
1022                                           33 * sizeof(u64),
1023                                           fps);
1024                 break;
1025
1026         case PTRACE_READTEXT:
1027         case PTRACE_READDATA:
1028                 ret = ptrace_readdata(child, addr,
1029                                       (char __user *)addr2, data);
1030                 if (ret == data)
1031                         ret = 0;
1032                 else if (ret >= 0)
1033                         ret = -EIO;
1034                 break;
1035
1036         case PTRACE_WRITETEXT:
1037         case PTRACE_WRITEDATA:
1038                 ret = ptrace_writedata(child, (char __user *) addr2,
1039                                        addr, data);
1040                 if (ret == data)
1041                         ret = 0;
1042                 else if (ret >= 0)
1043                         ret = -EIO;
1044                 break;
1045
1046         default:
1047                 if (request == PTRACE_SPARC_DETACH)
1048                         request = PTRACE_DETACH;
1049                 ret = ptrace_request(child, request, addr, data);
1050                 break;
1051         }
1052
1053         return ret;
1054 }
1055
1056 asmlinkage int syscall_trace_enter(struct pt_regs *regs)
1057 {
1058         int ret = 0;
1059
1060         /* do the secure computing check first */
1061         secure_computing(regs->u_regs[UREG_G1]);
1062
1063         if (test_thread_flag(TIF_SYSCALL_TRACE))
1064                 ret = tracehook_report_syscall_entry(regs);
1065
1066         if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
1067                 trace_sys_enter(regs, regs->u_regs[UREG_G1]);
1068
1069         if (unlikely(current->audit_context) && !ret)
1070                 audit_syscall_entry((test_thread_flag(TIF_32BIT) ?
1071                                      AUDIT_ARCH_SPARC :
1072                                      AUDIT_ARCH_SPARC64),
1073                                     regs->u_regs[UREG_G1],
1074                                     regs->u_regs[UREG_I0],
1075                                     regs->u_regs[UREG_I1],
1076                                     regs->u_regs[UREG_I2],
1077                                     regs->u_regs[UREG_I3]);
1078
1079         return ret;
1080 }
1081
1082 asmlinkage void syscall_trace_leave(struct pt_regs *regs)
1083 {
1084         if (unlikely(current->audit_context)) {
1085                 unsigned long tstate = regs->tstate;
1086                 int result = AUDITSC_SUCCESS;
1087
1088                 if (unlikely(tstate & (TSTATE_XCARRY | TSTATE_ICARRY)))
1089                         result = AUDITSC_FAILURE;
1090
1091                 audit_syscall_exit(result, regs->u_regs[UREG_I0]);
1092         }
1093
1094         if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
1095                 trace_sys_exit(regs, regs->u_regs[UREG_G1]);
1096
1097         if (test_thread_flag(TIF_SYSCALL_TRACE))
1098                 tracehook_report_syscall_exit(regs, 0);
1099 }