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