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