ptrace: change signature of arch_ptrace()
[sfrench/cifs-2.6.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                 reg_window -= 16;
496                 if (target == current) {
497                         for (; count > 0 && pos < 32; count--) {
498                                 if (get_user(*k++, &reg_window[pos++]))
499                                         return -EFAULT;
500                         }
501                 } else {
502                         for (; count > 0 && pos < 32; count--) {
503                                 if (access_process_vm(target,
504                                                       (unsigned long)
505                                                       &reg_window[pos],
506                                                       k, sizeof(*k), 0)
507                                     != sizeof(*k))
508                                         return -EFAULT;
509                                 k++;
510                                 pos++;
511                         }
512                 }
513         } else {
514                 for (; count > 0 && pos < 16; count--) {
515                         if (put_user((compat_ulong_t) regs->u_regs[pos++], u++))
516                                 return -EFAULT;
517                 }
518
519                 reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6];
520                 reg_window -= 16;
521                 if (target == current) {
522                         for (; count > 0 && pos < 32; count--) {
523                                 if (get_user(reg, &reg_window[pos++]) ||
524                                     put_user(reg, u++))
525                                         return -EFAULT;
526                         }
527                 } else {
528                         for (; count > 0 && pos < 32; count--) {
529                                 if (access_process_vm(target,
530                                                       (unsigned long)
531                                                       &reg_window[pos],
532                                                       &reg, sizeof(reg), 0)
533                                     != sizeof(reg))
534                                         return -EFAULT;
535                                 if (access_process_vm(target,
536                                                       (unsigned long) u,
537                                                       &reg, sizeof(reg), 1)
538                                     != sizeof(reg))
539                                         return -EFAULT;
540                                 pos++;
541                                 u++;
542                         }
543                 }
544         }
545         while (count > 0) {
546                 switch (pos) {
547                 case 32: /* PSR */
548                         reg = tstate_to_psr(regs->tstate);
549                         break;
550                 case 33: /* PC */
551                         reg = regs->tpc;
552                         break;
553                 case 34: /* NPC */
554                         reg = regs->tnpc;
555                         break;
556                 case 35: /* Y */
557                         reg = regs->y;
558                         break;
559                 case 36: /* WIM */
560                 case 37: /* TBR */
561                         reg = 0;
562                         break;
563                 default:
564                         goto finish;
565                 }
566
567                 if (kbuf)
568                         *k++ = reg;
569                 else if (put_user(reg, u++))
570                         return -EFAULT;
571                 pos++;
572                 count--;
573         }
574 finish:
575         pos *= sizeof(reg);
576         count *= sizeof(reg);
577
578         return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
579                                         38 * sizeof(reg), -1);
580 }
581
582 static int genregs32_set(struct task_struct *target,
583                          const struct user_regset *regset,
584                          unsigned int pos, unsigned int count,
585                          const void *kbuf, const void __user *ubuf)
586 {
587         struct pt_regs *regs = task_pt_regs(target);
588         compat_ulong_t __user *reg_window;
589         const compat_ulong_t *k = kbuf;
590         const compat_ulong_t __user *u = ubuf;
591         compat_ulong_t reg;
592
593         if (target == current)
594                 flushw_user();
595
596         pos /= sizeof(reg);
597         count /= sizeof(reg);
598
599         if (kbuf) {
600                 for (; count > 0 && pos < 16; count--)
601                         regs->u_regs[pos++] = *k++;
602
603                 reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6];
604                 reg_window -= 16;
605                 if (target == current) {
606                         for (; count > 0 && pos < 32; count--) {
607                                 if (put_user(*k++, &reg_window[pos++]))
608                                         return -EFAULT;
609                         }
610                 } else {
611                         for (; count > 0 && pos < 32; count--) {
612                                 if (access_process_vm(target,
613                                                       (unsigned long)
614                                                       &reg_window[pos],
615                                                       (void *) k,
616                                                       sizeof(*k), 1)
617                                     != sizeof(*k))
618                                         return -EFAULT;
619                                 k++;
620                                 pos++;
621                         }
622                 }
623         } else {
624                 for (; count > 0 && pos < 16; count--) {
625                         if (get_user(reg, u++))
626                                 return -EFAULT;
627                         regs->u_regs[pos++] = reg;
628                 }
629
630                 reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6];
631                 reg_window -= 16;
632                 if (target == current) {
633                         for (; count > 0 && pos < 32; count--) {
634                                 if (get_user(reg, u++) ||
635                                     put_user(reg, &reg_window[pos++]))
636                                         return -EFAULT;
637                         }
638                 } else {
639                         for (; count > 0 && pos < 32; count--) {
640                                 if (access_process_vm(target,
641                                                       (unsigned long)
642                                                       u,
643                                                       &reg, sizeof(reg), 0)
644                                     != sizeof(reg))
645                                         return -EFAULT;
646                                 if (access_process_vm(target,
647                                                       (unsigned long)
648                                                       &reg_window[pos],
649                                                       &reg, sizeof(reg), 1)
650                                     != sizeof(reg))
651                                         return -EFAULT;
652                                 pos++;
653                                 u++;
654                         }
655                 }
656         }
657         while (count > 0) {
658                 unsigned long tstate;
659
660                 if (kbuf)
661                         reg = *k++;
662                 else if (get_user(reg, u++))
663                         return -EFAULT;
664
665                 switch (pos) {
666                 case 32: /* PSR */
667                         tstate = regs->tstate;
668                         tstate &= ~(TSTATE_ICC | TSTATE_XCC | TSTATE_SYSCALL);
669                         tstate |= psr_to_tstate_icc(reg);
670                         if (reg & PSR_SYSCALL)
671                                 tstate |= TSTATE_SYSCALL;
672                         regs->tstate = tstate;
673                         break;
674                 case 33: /* PC */
675                         regs->tpc = reg;
676                         break;
677                 case 34: /* NPC */
678                         regs->tnpc = reg;
679                         break;
680                 case 35: /* Y */
681                         regs->y = reg;
682                         break;
683                 case 36: /* WIM */
684                 case 37: /* TBR */
685                         break;
686                 default:
687                         goto finish;
688                 }
689
690                 pos++;
691                 count--;
692         }
693 finish:
694         pos *= sizeof(reg);
695         count *= sizeof(reg);
696
697         return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
698                                          38 * sizeof(reg), -1);
699 }
700
701 static int fpregs32_get(struct task_struct *target,
702                         const struct user_regset *regset,
703                         unsigned int pos, unsigned int count,
704                         void *kbuf, void __user *ubuf)
705 {
706         const unsigned long *fpregs = task_thread_info(target)->fpregs;
707         compat_ulong_t enabled;
708         unsigned long fprs;
709         compat_ulong_t fsr;
710         int ret = 0;
711
712         if (target == current)
713                 save_and_clear_fpu();
714
715         fprs = task_thread_info(target)->fpsaved[0];
716         if (fprs & FPRS_FEF) {
717                 fsr = task_thread_info(target)->xfsr[0];
718                 enabled = 1;
719         } else {
720                 fsr = 0;
721                 enabled = 0;
722         }
723
724         ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
725                                   fpregs,
726                                   0, 32 * sizeof(u32));
727
728         if (!ret)
729                 ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
730                                                32 * sizeof(u32),
731                                                33 * sizeof(u32));
732         if (!ret)
733                 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
734                                           &fsr,
735                                           33 * sizeof(u32),
736                                           34 * sizeof(u32));
737
738         if (!ret) {
739                 compat_ulong_t val;
740
741                 val = (enabled << 8) | (8 << 16);
742                 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
743                                           &val,
744                                           34 * sizeof(u32),
745                                           35 * sizeof(u32));
746         }
747
748         if (!ret)
749                 ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
750                                                35 * sizeof(u32), -1);
751
752         return ret;
753 }
754
755 static int fpregs32_set(struct task_struct *target,
756                         const struct user_regset *regset,
757                         unsigned int pos, unsigned int count,
758                         const void *kbuf, const void __user *ubuf)
759 {
760         unsigned long *fpregs = task_thread_info(target)->fpregs;
761         unsigned long fprs;
762         int ret;
763
764         if (target == current)
765                 save_and_clear_fpu();
766
767         fprs = task_thread_info(target)->fpsaved[0];
768
769         ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
770                                  fpregs,
771                                  0, 32 * sizeof(u32));
772         if (!ret)
773                 user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
774                                           32 * sizeof(u32),
775                                           33 * sizeof(u32));
776         if (!ret && count > 0) {
777                 compat_ulong_t fsr;
778                 unsigned long val;
779
780                 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
781                                          &fsr,
782                                          33 * sizeof(u32),
783                                          34 * sizeof(u32));
784                 if (!ret) {
785                         val = task_thread_info(target)->xfsr[0];
786                         val &= 0xffffffff00000000UL;
787                         val |= fsr;
788                         task_thread_info(target)->xfsr[0] = val;
789                 }
790         }
791
792         fprs |= (FPRS_FEF | FPRS_DL);
793         task_thread_info(target)->fpsaved[0] = fprs;
794
795         if (!ret)
796                 ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
797                                                 34 * sizeof(u32), -1);
798         return ret;
799 }
800
801 static const struct user_regset sparc32_regsets[] = {
802         /* Format is:
803          *      G0 --> G7
804          *      O0 --> O7
805          *      L0 --> L7
806          *      I0 --> I7
807          *      PSR, PC, nPC, Y, WIM, TBR
808          */
809         [REGSET_GENERAL] = {
810                 .core_note_type = NT_PRSTATUS,
811                 .n = 38,
812                 .size = sizeof(u32), .align = sizeof(u32),
813                 .get = genregs32_get, .set = genregs32_set
814         },
815         /* Format is:
816          *      F0 --> F31
817          *      empty 32-bit word
818          *      FSR (32--bit word)
819          *      FPU QUEUE COUNT (8-bit char)
820          *      FPU QUEUE ENTRYSIZE (8-bit char)
821          *      FPU ENABLED (8-bit char)
822          *      empty 8-bit char
823          *      FPU QUEUE (64 32-bit ints)
824          */
825         [REGSET_FP] = {
826                 .core_note_type = NT_PRFPREG,
827                 .n = 99,
828                 .size = sizeof(u32), .align = sizeof(u32),
829                 .get = fpregs32_get, .set = fpregs32_set
830         },
831 };
832
833 static const struct user_regset_view user_sparc32_view = {
834         .name = "sparc", .e_machine = EM_SPARC,
835         .regsets = sparc32_regsets, .n = ARRAY_SIZE(sparc32_regsets)
836 };
837 #endif /* CONFIG_COMPAT */
838
839 const struct user_regset_view *task_user_regset_view(struct task_struct *task)
840 {
841 #ifdef CONFIG_COMPAT
842         if (test_tsk_thread_flag(task, TIF_32BIT))
843                 return &user_sparc32_view;
844 #endif
845         return &user_sparc64_view;
846 }
847
848 #ifdef CONFIG_COMPAT
849 struct compat_fps {
850         unsigned int regs[32];
851         unsigned int fsr;
852         unsigned int flags;
853         unsigned int extra;
854         unsigned int fpqd;
855         struct compat_fq {
856                 unsigned int insnaddr;
857                 unsigned int insn;
858         } fpq[16];
859 };
860
861 long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
862                         compat_ulong_t caddr, compat_ulong_t cdata)
863 {
864         const struct user_regset_view *view = task_user_regset_view(current);
865         compat_ulong_t caddr2 = task_pt_regs(current)->u_regs[UREG_I4];
866         struct pt_regs32 __user *pregs;
867         struct compat_fps __user *fps;
868         unsigned long addr2 = caddr2;
869         unsigned long addr = caddr;
870         unsigned long data = cdata;
871         int ret;
872
873         pregs = (struct pt_regs32 __user *) addr;
874         fps = (struct compat_fps __user *) addr;
875
876         switch (request) {
877         case PTRACE_PEEKUSR:
878                 ret = (addr != 0) ? -EIO : 0;
879                 break;
880
881         case PTRACE_GETREGS:
882                 ret = copy_regset_to_user(child, view, REGSET_GENERAL,
883                                           32 * sizeof(u32),
884                                           4 * sizeof(u32),
885                                           &pregs->psr);
886                 if (!ret)
887                         ret = copy_regset_to_user(child, view, REGSET_GENERAL,
888                                                   1 * sizeof(u32),
889                                                   15 * sizeof(u32),
890                                                   &pregs->u_regs[0]);
891                 break;
892
893         case PTRACE_SETREGS:
894                 ret = copy_regset_from_user(child, view, REGSET_GENERAL,
895                                             32 * sizeof(u32),
896                                             4 * sizeof(u32),
897                                             &pregs->psr);
898                 if (!ret)
899                         ret = copy_regset_from_user(child, view, REGSET_GENERAL,
900                                                     1 * sizeof(u32),
901                                                     15 * sizeof(u32),
902                                                     &pregs->u_regs[0]);
903                 break;
904
905         case PTRACE_GETFPREGS:
906                 ret = copy_regset_to_user(child, view, REGSET_FP,
907                                           0 * sizeof(u32),
908                                           32 * sizeof(u32),
909                                           &fps->regs[0]);
910                 if (!ret)
911                         ret = copy_regset_to_user(child, view, REGSET_FP,
912                                                   33 * sizeof(u32),
913                                                   1 * sizeof(u32),
914                                                   &fps->fsr);
915                 if (!ret) {
916                         if (__put_user(0, &fps->flags) ||
917                             __put_user(0, &fps->extra) ||
918                             __put_user(0, &fps->fpqd) ||
919                             clear_user(&fps->fpq[0], 32 * sizeof(unsigned int)))
920                                 ret = -EFAULT;
921                 }
922                 break;
923
924         case PTRACE_SETFPREGS:
925                 ret = copy_regset_from_user(child, view, REGSET_FP,
926                                             0 * sizeof(u32),
927                                             32 * sizeof(u32),
928                                             &fps->regs[0]);
929                 if (!ret)
930                         ret = copy_regset_from_user(child, view, REGSET_FP,
931                                                     33 * sizeof(u32),
932                                                     1 * sizeof(u32),
933                                                     &fps->fsr);
934                 break;
935
936         case PTRACE_READTEXT:
937         case PTRACE_READDATA:
938                 ret = ptrace_readdata(child, addr,
939                                       (char __user *)addr2, data);
940                 if (ret == data)
941                         ret = 0;
942                 else if (ret >= 0)
943                         ret = -EIO;
944                 break;
945
946         case PTRACE_WRITETEXT:
947         case PTRACE_WRITEDATA:
948                 ret = ptrace_writedata(child, (char __user *) addr2,
949                                        addr, data);
950                 if (ret == data)
951                         ret = 0;
952                 else if (ret >= 0)
953                         ret = -EIO;
954                 break;
955
956         default:
957                 if (request == PTRACE_SPARC_DETACH)
958                         request = PTRACE_DETACH;
959                 ret = compat_ptrace_request(child, request, addr, data);
960                 break;
961         }
962
963         return ret;
964 }
965 #endif /* CONFIG_COMPAT */
966
967 struct fps {
968         unsigned int regs[64];
969         unsigned long fsr;
970 };
971
972 long arch_ptrace(struct task_struct *child, long request,
973                  unsigned long addr, unsigned long data)
974 {
975         const struct user_regset_view *view = task_user_regset_view(current);
976         unsigned long addr2 = task_pt_regs(current)->u_regs[UREG_I4];
977         struct pt_regs __user *pregs;
978         struct fps __user *fps;
979         int ret;
980
981         pregs = (struct pt_regs __user *) addr;
982         fps = (struct fps __user *) addr;
983
984         switch (request) {
985         case PTRACE_PEEKUSR:
986                 ret = (addr != 0) ? -EIO : 0;
987                 break;
988
989         case PTRACE_GETREGS64:
990                 ret = copy_regset_to_user(child, view, REGSET_GENERAL,
991                                           1 * sizeof(u64),
992                                           15 * sizeof(u64),
993                                           &pregs->u_regs[0]);
994                 if (!ret) {
995                         /* XXX doesn't handle 'y' register correctly XXX */
996                         ret = copy_regset_to_user(child, view, REGSET_GENERAL,
997                                                   32 * sizeof(u64),
998                                                   4 * sizeof(u64),
999                                                   &pregs->tstate);
1000                 }
1001                 break;
1002
1003         case PTRACE_SETREGS64:
1004                 ret = copy_regset_from_user(child, view, REGSET_GENERAL,
1005                                             1 * sizeof(u64),
1006                                             15 * sizeof(u64),
1007                                             &pregs->u_regs[0]);
1008                 if (!ret) {
1009                         /* XXX doesn't handle 'y' register correctly XXX */
1010                         ret = copy_regset_from_user(child, view, REGSET_GENERAL,
1011                                                     32 * sizeof(u64),
1012                                                     4 * sizeof(u64),
1013                                                     &pregs->tstate);
1014                 }
1015                 break;
1016
1017         case PTRACE_GETFPREGS64:
1018                 ret = copy_regset_to_user(child, view, REGSET_FP,
1019                                           0 * sizeof(u64),
1020                                           33 * sizeof(u64),
1021                                           fps);
1022                 break;
1023
1024         case PTRACE_SETFPREGS64:
1025                 ret = copy_regset_from_user(child, view, REGSET_FP,
1026                                           0 * sizeof(u64),
1027                                           33 * sizeof(u64),
1028                                           fps);
1029                 break;
1030
1031         case PTRACE_READTEXT:
1032         case PTRACE_READDATA:
1033                 ret = ptrace_readdata(child, addr,
1034                                       (char __user *)addr2, data);
1035                 if (ret == data)
1036                         ret = 0;
1037                 else if (ret >= 0)
1038                         ret = -EIO;
1039                 break;
1040
1041         case PTRACE_WRITETEXT:
1042         case PTRACE_WRITEDATA:
1043                 ret = ptrace_writedata(child, (char __user *) addr2,
1044                                        addr, data);
1045                 if (ret == data)
1046                         ret = 0;
1047                 else if (ret >= 0)
1048                         ret = -EIO;
1049                 break;
1050
1051         default:
1052                 if (request == PTRACE_SPARC_DETACH)
1053                         request = PTRACE_DETACH;
1054                 ret = ptrace_request(child, request, addr, data);
1055                 break;
1056         }
1057
1058         return ret;
1059 }
1060
1061 asmlinkage int syscall_trace_enter(struct pt_regs *regs)
1062 {
1063         int ret = 0;
1064
1065         /* do the secure computing check first */
1066         secure_computing(regs->u_regs[UREG_G1]);
1067
1068         if (test_thread_flag(TIF_SYSCALL_TRACE))
1069                 ret = tracehook_report_syscall_entry(regs);
1070
1071         if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
1072                 trace_sys_enter(regs, regs->u_regs[UREG_G1]);
1073
1074         if (unlikely(current->audit_context) && !ret)
1075                 audit_syscall_entry((test_thread_flag(TIF_32BIT) ?
1076                                      AUDIT_ARCH_SPARC :
1077                                      AUDIT_ARCH_SPARC64),
1078                                     regs->u_regs[UREG_G1],
1079                                     regs->u_regs[UREG_I0],
1080                                     regs->u_regs[UREG_I1],
1081                                     regs->u_regs[UREG_I2],
1082                                     regs->u_regs[UREG_I3]);
1083
1084         return ret;
1085 }
1086
1087 asmlinkage void syscall_trace_leave(struct pt_regs *regs)
1088 {
1089         if (unlikely(current->audit_context)) {
1090                 unsigned long tstate = regs->tstate;
1091                 int result = AUDITSC_SUCCESS;
1092
1093                 if (unlikely(tstate & (TSTATE_XCARRY | TSTATE_ICARRY)))
1094                         result = AUDITSC_FAILURE;
1095
1096                 audit_syscall_exit(result, regs->u_regs[UREG_I0]);
1097         }
1098
1099         if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
1100                 trace_sys_exit(regs, regs->u_regs[UREG_G1]);
1101
1102         if (test_thread_flag(TIF_SYSCALL_TRACE))
1103                 tracehook_report_syscall_exit(regs, 0);
1104 }