OSDN Git Service

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