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