eeepc-laptop: Register as a pci-hotplug device
[linux-2.6/linux-acpi-2.6.git] / arch / sparc / kernel / ptrace_64.c
bloba941c610e7ce0cdf8c38c38c5e3d46c32419114f
1 /* ptrace.c: Sparc process tracing support.
3 * Copyright (C) 1996, 2008 David S. Miller (davem@davemloft.net)
4 * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
6 * Based upon code written by Ross Biro, Linus Torvalds, Bob Manson,
7 * and David Mosberger.
9 * Added Linux support -miguel (weird, eh?, the original code was meant
10 * to emulate SunOS).
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>
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>
41 #include "entry.h"
43 /* #define ALLOW_INIT_TRACING */
46 * Called by kernel/ptrace.c when detaching..
48 * Make sure single step bits etc are not set.
50 void ptrace_disable(struct task_struct *child)
52 /* nothing to do */
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.
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
65 void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
66 unsigned long uaddr, void *kaddr,
67 unsigned long len, int write)
69 BUG_ON(len > PAGE_SIZE);
71 if (tlb_type == hypervisor)
72 return;
74 preempt_disable();
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.
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;
87 dcache_line_size = local_cpu_data().dcache_line_size;
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));
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;
109 icache_line_size = local_cpu_data().icache_line_size;
111 for (; start < end; start += icache_line_size)
112 flushi(start);
115 preempt_enable();
118 static int get_from_target(struct task_struct *target, unsigned long uaddr,
119 void *kbuf, int len)
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;
129 return 0;
132 static int set_to_target(struct task_struct *target, unsigned long uaddr,
133 void *kbuf, int len)
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;
143 return 0;
146 static int regwindow64_get(struct task_struct *target,
147 const struct pt_regs *regs,
148 struct reg_window *wbuf)
150 unsigned long rw_addr = regs->u_regs[UREG_I6];
152 if (test_tsk_thread_flag(current, TIF_32BIT)) {
153 struct reg_window32 win32;
154 int i;
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;
168 return 0;
171 static int regwindow64_set(struct task_struct *target,
172 const struct pt_regs *regs,
173 struct reg_window *wbuf)
175 unsigned long rw_addr = regs->u_regs[UREG_I6];
177 if (test_tsk_thread_flag(current, TIF_32BIT)) {
178 struct reg_window32 win32;
179 int i;
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];
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;
194 return 0;
197 enum sparc_regset {
198 REGSET_GENERAL,
199 REGSET_FP,
202 static 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)
207 const struct pt_regs *regs = task_pt_regs(target);
208 int ret;
210 if (target == current)
211 flushw_user();
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;
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));
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));
235 if (!ret) {
236 unsigned long y = regs->y;
238 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
240 35 * sizeof(u64),
241 36 * sizeof(u64));
244 if (!ret) {
245 ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
246 36 * sizeof(u64), -1);
249 return ret;
252 static 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)
257 struct pt_regs *regs = task_pt_regs(target);
258 int ret;
260 if (target == current)
261 flushw_user();
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;
269 if (regwindow64_get(target, regs, &window))
270 return -EFAULT;
272 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
273 &window,
274 16 * sizeof(u64),
275 32 * sizeof(u64));
277 if (!ret &&
278 regwindow64_set(target, regs, &window))
279 return -EFAULT;
282 if (!ret && count > 0) {
283 unsigned long tstate;
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.
294 tstate &= (TSTATE_ICC | TSTATE_XCC | TSTATE_SYSCALL);
295 regs->tstate &= ~(TSTATE_ICC | TSTATE_XCC | TSTATE_SYSCALL);
296 regs->tstate |= tstate;
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));
308 if (!ret) {
309 unsigned long y;
311 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
313 35 * sizeof(u64),
314 36 * sizeof(u64));
315 if (!ret)
316 regs->y = y;
319 if (!ret)
320 ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
321 36 * sizeof(u64), -1);
323 return ret;
326 static 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)
331 const unsigned long *fpregs = task_thread_info(target)->fpregs;
332 unsigned long fprs, fsr, gsr;
333 int ret;
335 if (target == current)
336 save_and_clear_fpu();
338 fprs = task_thread_info(target)->fpsaved[0];
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,
347 16 * sizeof(u64));
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));
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;
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));
386 if (!ret)
387 ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
388 35 * sizeof(u64), -1);
390 return ret;
393 static 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)
398 unsigned long *fpregs = task_thread_info(target)->fpregs;
399 unsigned long fprs;
400 int ret;
402 if (target == current)
403 save_and_clear_fpu();
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));
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));
427 fprs |= (FPRS_FEF | FPRS_DL | FPRS_DU);
428 task_thread_info(target)->fpsaved[0] = fprs;
430 if (!ret)
431 ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
432 35 * sizeof(u64), -1);
433 return ret;
436 static 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
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
450 /* Format is:
451 * F0 --> F63
452 * FSR
453 * GSR
454 * FPRS
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
464 static const struct user_regset_view user_sparc64_view = {
465 .name = "sparc64", .e_machine = EM_SPARCV9,
466 .regsets = sparc64_regsets, .n = ARRAY_SIZE(sparc64_regsets)
469 #ifdef CONFIG_COMPAT
470 static 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)
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;
481 if (target == current)
482 flushw_user();
484 pos /= sizeof(reg);
485 count /= sizeof(reg);
487 if (kbuf) {
488 for (; count > 0 && pos < 16; count--)
489 *k++ = regs->u_regs[pos++];
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;
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++;
509 } else {
510 for (; count > 0 && pos < 16; count--) {
511 if (put_user((compat_ulong_t) regs->u_regs[pos++], u++))
512 return -EFAULT;
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;
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++;
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;
562 if (kbuf)
563 *k++ = reg;
564 else if (put_user(reg, u++))
565 return -EFAULT;
566 pos++;
567 count--;
569 finish:
570 pos *= sizeof(reg);
571 count *= sizeof(reg);
573 return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
574 38 * sizeof(reg), -1);
577 static 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)
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;
588 if (target == current)
589 flushw_user();
591 pos /= sizeof(reg);
592 count /= sizeof(reg);
594 if (kbuf) {
595 for (; count > 0 && pos < 16; count--)
596 regs->u_regs[pos++] = *k++;
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;
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++;
617 } else {
618 for (; count > 0 && pos < 16; count--) {
619 if (get_user(reg, u++))
620 return -EFAULT;
621 regs->u_regs[pos++] = reg;
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;
631 } else {
632 for (; count > 0 && pos < 32; count--) {
633 if (access_process_vm(target,
634 (unsigned long)
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++;
650 while (count > 0) {
651 unsigned long tstate;
653 if (kbuf)
654 reg = *k++;
655 else if (get_user(reg, u++))
656 return -EFAULT;
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;
683 pos++;
684 count--;
686 finish:
687 pos *= sizeof(reg);
688 count *= sizeof(reg);
690 return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
691 38 * sizeof(reg), -1);
694 static 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)
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;
705 if (target == current)
706 save_and_clear_fpu();
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;
717 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
718 fpregs,
719 0, 32 * sizeof(u32));
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));
731 if (!ret) {
732 compat_ulong_t val;
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));
741 if (!ret)
742 ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
743 35 * sizeof(u32), -1);
745 return ret;
748 static 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)
753 unsigned long *fpregs = task_thread_info(target)->fpregs;
754 unsigned long fprs;
755 int ret;
757 if (target == current)
758 save_and_clear_fpu();
760 fprs = task_thread_info(target)->fpsaved[0];
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;
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;
785 fprs |= (FPRS_FEF | FPRS_DL);
786 task_thread_info(target)->fpsaved[0] = fprs;
788 if (!ret)
789 ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
790 34 * sizeof(u32), -1);
791 return ret;
794 static 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
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
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)
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
826 static const struct user_regset_view user_sparc32_view = {
827 .name = "sparc", .e_machine = EM_SPARC,
828 .regsets = sparc32_regsets, .n = ARRAY_SIZE(sparc32_regsets)
830 #endif /* CONFIG_COMPAT */
832 const struct user_regset_view *task_user_regset_view(struct task_struct *task)
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;
841 #ifdef CONFIG_COMPAT
842 struct 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];
854 long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
855 compat_ulong_t caddr, compat_ulong_t cdata)
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;
866 pregs = (struct pt_regs32 __user *) addr;
867 fps = (struct compat_fps __user *) addr;
869 switch (request) {
870 case PTRACE_PEEKUSR:
871 ret = (addr != 0) ? -EIO : 0;
872 break;
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;
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;
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;
915 break;
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;
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;
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;
949 default:
950 if (request == PTRACE_SPARC_DETACH)
951 request = PTRACE_DETACH;
952 ret = compat_ptrace_request(child, request, addr, data);
953 break;
956 return ret;
958 #endif /* CONFIG_COMPAT */
960 struct fps {
961 unsigned int regs[64];
962 unsigned long fsr;
965 long arch_ptrace(struct task_struct *child, long request, long addr, long data)
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;
973 pregs = (struct pt_regs __user *) (unsigned long) addr;
974 fps = (struct fps __user *) (unsigned long) addr;
976 switch (request) {
977 case PTRACE_PEEKUSR:
978 ret = (addr != 0) ? -EIO : 0;
979 break;
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);
993 break;
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);
1007 break;
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;
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;
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;
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;
1043 default:
1044 if (request == PTRACE_SPARC_DETACH)
1045 request = PTRACE_DETACH;
1046 ret = ptrace_request(child, request, addr, data);
1047 break;
1050 return ret;
1053 asmlinkage int syscall_trace_enter(struct pt_regs *regs)
1055 int ret = 0;
1057 /* do the secure computing check first */
1058 secure_computing(regs->u_regs[UREG_G1]);
1060 if (test_thread_flag(TIF_SYSCALL_TRACE))
1061 ret = tracehook_report_syscall_entry(regs);
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]);
1073 return ret;
1076 asmlinkage void syscall_trace_leave(struct pt_regs *regs)
1078 if (unlikely(current->audit_context)) {
1079 unsigned long tstate = regs->tstate;
1080 int result = AUDITSC_SUCCESS;
1082 if (unlikely(tstate & (TSTATE_XCARRY | TSTATE_ICARRY)))
1083 result = AUDITSC_FAILURE;
1085 audit_syscall_exit(result, regs->u_regs[UREG_I0]);
1088 if (test_thread_flag(TIF_SYSCALL_TRACE))
1089 tracehook_report_syscall_exit(regs, 0);