xref: /openbmc/linux/arch/sparc/kernel/ptrace_64.c (revision 089a49b6)
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 }
1097