xref: /linux/arch/arm64/kernel/ptrace.c (revision c4c11dd160a8cc98f402c4e12f94b1572e822ffd)
1 /*
2  * Based on arch/arm/kernel/ptrace.c
3  *
4  * By Ross Biro 1/23/92
5  * edited by Linus Torvalds
6  * ARM modifications Copyright (C) 2000 Russell King
7  * Copyright (C) 2012 ARM Ltd.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License version 2 as
11  * published by the Free Software Foundation.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #include <linux/kernel.h>
23 #include <linux/sched.h>
24 #include <linux/mm.h>
25 #include <linux/smp.h>
26 #include <linux/ptrace.h>
27 #include <linux/user.h>
28 #include <linux/security.h>
29 #include <linux/init.h>
30 #include <linux/signal.h>
31 #include <linux/uaccess.h>
32 #include <linux/perf_event.h>
33 #include <linux/hw_breakpoint.h>
34 #include <linux/regset.h>
35 #include <linux/tracehook.h>
36 #include <linux/elf.h>
37 
38 #include <asm/compat.h>
39 #include <asm/debug-monitors.h>
40 #include <asm/pgtable.h>
41 #include <asm/traps.h>
42 #include <asm/system_misc.h>
43 
44 /*
45  * TODO: does not yet catch signals sent when the child dies.
46  * in exit.c or in signal.c.
47  */
48 
49 /*
50  * Called by kernel/ptrace.c when detaching..
51  */
52 void ptrace_disable(struct task_struct *child)
53 {
54 }
55 
56 #ifdef CONFIG_HAVE_HW_BREAKPOINT
57 /*
58  * Handle hitting a HW-breakpoint.
59  */
60 static void ptrace_hbptriggered(struct perf_event *bp,
61 				struct perf_sample_data *data,
62 				struct pt_regs *regs)
63 {
64 	struct arch_hw_breakpoint *bkpt = counter_arch_bp(bp);
65 	siginfo_t info = {
66 		.si_signo	= SIGTRAP,
67 		.si_errno	= 0,
68 		.si_code	= TRAP_HWBKPT,
69 		.si_addr	= (void __user *)(bkpt->trigger),
70 	};
71 
72 #ifdef CONFIG_COMPAT
73 	int i;
74 
75 	if (!is_compat_task())
76 		goto send_sig;
77 
78 	for (i = 0; i < ARM_MAX_BRP; ++i) {
79 		if (current->thread.debug.hbp_break[i] == bp) {
80 			info.si_errno = (i << 1) + 1;
81 			break;
82 		}
83 	}
84 	for (i = ARM_MAX_BRP; i < ARM_MAX_HBP_SLOTS && !bp; ++i) {
85 		if (current->thread.debug.hbp_watch[i] == bp) {
86 			info.si_errno = -((i << 1) + 1);
87 			break;
88 		}
89 	}
90 
91 send_sig:
92 #endif
93 	force_sig_info(SIGTRAP, &info, current);
94 }
95 
96 /*
97  * Unregister breakpoints from this task and reset the pointers in
98  * the thread_struct.
99  */
100 void flush_ptrace_hw_breakpoint(struct task_struct *tsk)
101 {
102 	int i;
103 	struct thread_struct *t = &tsk->thread;
104 
105 	for (i = 0; i < ARM_MAX_BRP; i++) {
106 		if (t->debug.hbp_break[i]) {
107 			unregister_hw_breakpoint(t->debug.hbp_break[i]);
108 			t->debug.hbp_break[i] = NULL;
109 		}
110 	}
111 
112 	for (i = 0; i < ARM_MAX_WRP; i++) {
113 		if (t->debug.hbp_watch[i]) {
114 			unregister_hw_breakpoint(t->debug.hbp_watch[i]);
115 			t->debug.hbp_watch[i] = NULL;
116 		}
117 	}
118 }
119 
120 void ptrace_hw_copy_thread(struct task_struct *tsk)
121 {
122 	memset(&tsk->thread.debug, 0, sizeof(struct debug_info));
123 }
124 
125 static struct perf_event *ptrace_hbp_get_event(unsigned int note_type,
126 					       struct task_struct *tsk,
127 					       unsigned long idx)
128 {
129 	struct perf_event *bp = ERR_PTR(-EINVAL);
130 
131 	switch (note_type) {
132 	case NT_ARM_HW_BREAK:
133 		if (idx < ARM_MAX_BRP)
134 			bp = tsk->thread.debug.hbp_break[idx];
135 		break;
136 	case NT_ARM_HW_WATCH:
137 		if (idx < ARM_MAX_WRP)
138 			bp = tsk->thread.debug.hbp_watch[idx];
139 		break;
140 	}
141 
142 	return bp;
143 }
144 
145 static int ptrace_hbp_set_event(unsigned int note_type,
146 				struct task_struct *tsk,
147 				unsigned long idx,
148 				struct perf_event *bp)
149 {
150 	int err = -EINVAL;
151 
152 	switch (note_type) {
153 	case NT_ARM_HW_BREAK:
154 		if (idx < ARM_MAX_BRP) {
155 			tsk->thread.debug.hbp_break[idx] = bp;
156 			err = 0;
157 		}
158 		break;
159 	case NT_ARM_HW_WATCH:
160 		if (idx < ARM_MAX_WRP) {
161 			tsk->thread.debug.hbp_watch[idx] = bp;
162 			err = 0;
163 		}
164 		break;
165 	}
166 
167 	return err;
168 }
169 
170 static struct perf_event *ptrace_hbp_create(unsigned int note_type,
171 					    struct task_struct *tsk,
172 					    unsigned long idx)
173 {
174 	struct perf_event *bp;
175 	struct perf_event_attr attr;
176 	int err, type;
177 
178 	switch (note_type) {
179 	case NT_ARM_HW_BREAK:
180 		type = HW_BREAKPOINT_X;
181 		break;
182 	case NT_ARM_HW_WATCH:
183 		type = HW_BREAKPOINT_RW;
184 		break;
185 	default:
186 		return ERR_PTR(-EINVAL);
187 	}
188 
189 	ptrace_breakpoint_init(&attr);
190 
191 	/*
192 	 * Initialise fields to sane defaults
193 	 * (i.e. values that will pass validation).
194 	 */
195 	attr.bp_addr	= 0;
196 	attr.bp_len	= HW_BREAKPOINT_LEN_4;
197 	attr.bp_type	= type;
198 	attr.disabled	= 1;
199 
200 	bp = register_user_hw_breakpoint(&attr, ptrace_hbptriggered, NULL, tsk);
201 	if (IS_ERR(bp))
202 		return bp;
203 
204 	err = ptrace_hbp_set_event(note_type, tsk, idx, bp);
205 	if (err)
206 		return ERR_PTR(err);
207 
208 	return bp;
209 }
210 
211 static int ptrace_hbp_fill_attr_ctrl(unsigned int note_type,
212 				     struct arch_hw_breakpoint_ctrl ctrl,
213 				     struct perf_event_attr *attr)
214 {
215 	int err, len, type, disabled = !ctrl.enabled;
216 
217 	if (disabled) {
218 		len = 0;
219 		type = HW_BREAKPOINT_EMPTY;
220 	} else {
221 		err = arch_bp_generic_fields(ctrl, &len, &type);
222 		if (err)
223 			return err;
224 
225 		switch (note_type) {
226 		case NT_ARM_HW_BREAK:
227 			if ((type & HW_BREAKPOINT_X) != type)
228 				return -EINVAL;
229 			break;
230 		case NT_ARM_HW_WATCH:
231 			if ((type & HW_BREAKPOINT_RW) != type)
232 				return -EINVAL;
233 			break;
234 		default:
235 			return -EINVAL;
236 		}
237 	}
238 
239 	attr->bp_len	= len;
240 	attr->bp_type	= type;
241 	attr->disabled	= disabled;
242 
243 	return 0;
244 }
245 
246 static int ptrace_hbp_get_resource_info(unsigned int note_type, u32 *info)
247 {
248 	u8 num;
249 	u32 reg = 0;
250 
251 	switch (note_type) {
252 	case NT_ARM_HW_BREAK:
253 		num = hw_breakpoint_slots(TYPE_INST);
254 		break;
255 	case NT_ARM_HW_WATCH:
256 		num = hw_breakpoint_slots(TYPE_DATA);
257 		break;
258 	default:
259 		return -EINVAL;
260 	}
261 
262 	reg |= debug_monitors_arch();
263 	reg <<= 8;
264 	reg |= num;
265 
266 	*info = reg;
267 	return 0;
268 }
269 
270 static int ptrace_hbp_get_ctrl(unsigned int note_type,
271 			       struct task_struct *tsk,
272 			       unsigned long idx,
273 			       u32 *ctrl)
274 {
275 	struct perf_event *bp = ptrace_hbp_get_event(note_type, tsk, idx);
276 
277 	if (IS_ERR(bp))
278 		return PTR_ERR(bp);
279 
280 	*ctrl = bp ? encode_ctrl_reg(counter_arch_bp(bp)->ctrl) : 0;
281 	return 0;
282 }
283 
284 static int ptrace_hbp_get_addr(unsigned int note_type,
285 			       struct task_struct *tsk,
286 			       unsigned long idx,
287 			       u64 *addr)
288 {
289 	struct perf_event *bp = ptrace_hbp_get_event(note_type, tsk, idx);
290 
291 	if (IS_ERR(bp))
292 		return PTR_ERR(bp);
293 
294 	*addr = bp ? bp->attr.bp_addr : 0;
295 	return 0;
296 }
297 
298 static struct perf_event *ptrace_hbp_get_initialised_bp(unsigned int note_type,
299 							struct task_struct *tsk,
300 							unsigned long idx)
301 {
302 	struct perf_event *bp = ptrace_hbp_get_event(note_type, tsk, idx);
303 
304 	if (!bp)
305 		bp = ptrace_hbp_create(note_type, tsk, idx);
306 
307 	return bp;
308 }
309 
310 static int ptrace_hbp_set_ctrl(unsigned int note_type,
311 			       struct task_struct *tsk,
312 			       unsigned long idx,
313 			       u32 uctrl)
314 {
315 	int err;
316 	struct perf_event *bp;
317 	struct perf_event_attr attr;
318 	struct arch_hw_breakpoint_ctrl ctrl;
319 
320 	bp = ptrace_hbp_get_initialised_bp(note_type, tsk, idx);
321 	if (IS_ERR(bp)) {
322 		err = PTR_ERR(bp);
323 		return err;
324 	}
325 
326 	attr = bp->attr;
327 	decode_ctrl_reg(uctrl, &ctrl);
328 	err = ptrace_hbp_fill_attr_ctrl(note_type, ctrl, &attr);
329 	if (err)
330 		return err;
331 
332 	return modify_user_hw_breakpoint(bp, &attr);
333 }
334 
335 static int ptrace_hbp_set_addr(unsigned int note_type,
336 			       struct task_struct *tsk,
337 			       unsigned long idx,
338 			       u64 addr)
339 {
340 	int err;
341 	struct perf_event *bp;
342 	struct perf_event_attr attr;
343 
344 	bp = ptrace_hbp_get_initialised_bp(note_type, tsk, idx);
345 	if (IS_ERR(bp)) {
346 		err = PTR_ERR(bp);
347 		return err;
348 	}
349 
350 	attr = bp->attr;
351 	attr.bp_addr = addr;
352 	err = modify_user_hw_breakpoint(bp, &attr);
353 	return err;
354 }
355 
356 #define PTRACE_HBP_ADDR_SZ	sizeof(u64)
357 #define PTRACE_HBP_CTRL_SZ	sizeof(u32)
358 #define PTRACE_HBP_PAD_SZ	sizeof(u32)
359 
360 static int hw_break_get(struct task_struct *target,
361 			const struct user_regset *regset,
362 			unsigned int pos, unsigned int count,
363 			void *kbuf, void __user *ubuf)
364 {
365 	unsigned int note_type = regset->core_note_type;
366 	int ret, idx = 0, offset, limit;
367 	u32 info, ctrl;
368 	u64 addr;
369 
370 	/* Resource info */
371 	ret = ptrace_hbp_get_resource_info(note_type, &info);
372 	if (ret)
373 		return ret;
374 
375 	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &info, 0,
376 				  sizeof(info));
377 	if (ret)
378 		return ret;
379 
380 	/* Pad */
381 	offset = offsetof(struct user_hwdebug_state, pad);
382 	ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, offset,
383 				       offset + PTRACE_HBP_PAD_SZ);
384 	if (ret)
385 		return ret;
386 
387 	/* (address, ctrl) registers */
388 	offset = offsetof(struct user_hwdebug_state, dbg_regs);
389 	limit = regset->n * regset->size;
390 	while (count && offset < limit) {
391 		ret = ptrace_hbp_get_addr(note_type, target, idx, &addr);
392 		if (ret)
393 			return ret;
394 		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &addr,
395 					  offset, offset + PTRACE_HBP_ADDR_SZ);
396 		if (ret)
397 			return ret;
398 		offset += PTRACE_HBP_ADDR_SZ;
399 
400 		ret = ptrace_hbp_get_ctrl(note_type, target, idx, &ctrl);
401 		if (ret)
402 			return ret;
403 		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &ctrl,
404 					  offset, offset + PTRACE_HBP_CTRL_SZ);
405 		if (ret)
406 			return ret;
407 		offset += PTRACE_HBP_CTRL_SZ;
408 
409 		ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
410 					       offset,
411 					       offset + PTRACE_HBP_PAD_SZ);
412 		if (ret)
413 			return ret;
414 		offset += PTRACE_HBP_PAD_SZ;
415 		idx++;
416 	}
417 
418 	return 0;
419 }
420 
421 static int hw_break_set(struct task_struct *target,
422 			const struct user_regset *regset,
423 			unsigned int pos, unsigned int count,
424 			const void *kbuf, const void __user *ubuf)
425 {
426 	unsigned int note_type = regset->core_note_type;
427 	int ret, idx = 0, offset, limit;
428 	u32 ctrl;
429 	u64 addr;
430 
431 	/* Resource info and pad */
432 	offset = offsetof(struct user_hwdebug_state, dbg_regs);
433 	ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, 0, offset);
434 	if (ret)
435 		return ret;
436 
437 	/* (address, ctrl) registers */
438 	limit = regset->n * regset->size;
439 	while (count && offset < limit) {
440 		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &addr,
441 					 offset, offset + PTRACE_HBP_ADDR_SZ);
442 		if (ret)
443 			return ret;
444 		ret = ptrace_hbp_set_addr(note_type, target, idx, addr);
445 		if (ret)
446 			return ret;
447 		offset += PTRACE_HBP_ADDR_SZ;
448 
449 		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &ctrl,
450 					 offset, offset + PTRACE_HBP_CTRL_SZ);
451 		if (ret)
452 			return ret;
453 		ret = ptrace_hbp_set_ctrl(note_type, target, idx, ctrl);
454 		if (ret)
455 			return ret;
456 		offset += PTRACE_HBP_CTRL_SZ;
457 
458 		ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
459 						offset,
460 						offset + PTRACE_HBP_PAD_SZ);
461 		if (ret)
462 			return ret;
463 		offset += PTRACE_HBP_PAD_SZ;
464 		idx++;
465 	}
466 
467 	return 0;
468 }
469 #endif	/* CONFIG_HAVE_HW_BREAKPOINT */
470 
471 static int gpr_get(struct task_struct *target,
472 		   const struct user_regset *regset,
473 		   unsigned int pos, unsigned int count,
474 		   void *kbuf, void __user *ubuf)
475 {
476 	struct user_pt_regs *uregs = &task_pt_regs(target)->user_regs;
477 	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0, -1);
478 }
479 
480 static int gpr_set(struct task_struct *target, const struct user_regset *regset,
481 		   unsigned int pos, unsigned int count,
482 		   const void *kbuf, const void __user *ubuf)
483 {
484 	int ret;
485 	struct user_pt_regs newregs;
486 
487 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &newregs, 0, -1);
488 	if (ret)
489 		return ret;
490 
491 	if (!valid_user_regs(&newregs))
492 		return -EINVAL;
493 
494 	task_pt_regs(target)->user_regs = newregs;
495 	return 0;
496 }
497 
498 /*
499  * TODO: update fp accessors for lazy context switching (sync/flush hwstate)
500  */
501 static int fpr_get(struct task_struct *target, const struct user_regset *regset,
502 		   unsigned int pos, unsigned int count,
503 		   void *kbuf, void __user *ubuf)
504 {
505 	struct user_fpsimd_state *uregs;
506 	uregs = &target->thread.fpsimd_state.user_fpsimd;
507 	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0, -1);
508 }
509 
510 static int fpr_set(struct task_struct *target, const struct user_regset *regset,
511 		   unsigned int pos, unsigned int count,
512 		   const void *kbuf, const void __user *ubuf)
513 {
514 	int ret;
515 	struct user_fpsimd_state newstate;
516 
517 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &newstate, 0, -1);
518 	if (ret)
519 		return ret;
520 
521 	target->thread.fpsimd_state.user_fpsimd = newstate;
522 	return ret;
523 }
524 
525 static int tls_get(struct task_struct *target, const struct user_regset *regset,
526 		   unsigned int pos, unsigned int count,
527 		   void *kbuf, void __user *ubuf)
528 {
529 	unsigned long *tls = &target->thread.tp_value;
530 	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, tls, 0, -1);
531 }
532 
533 static int tls_set(struct task_struct *target, const struct user_regset *regset,
534 		   unsigned int pos, unsigned int count,
535 		   const void *kbuf, const void __user *ubuf)
536 {
537 	int ret;
538 	unsigned long tls;
539 
540 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &tls, 0, -1);
541 	if (ret)
542 		return ret;
543 
544 	target->thread.tp_value = tls;
545 	return ret;
546 }
547 
548 enum aarch64_regset {
549 	REGSET_GPR,
550 	REGSET_FPR,
551 	REGSET_TLS,
552 #ifdef CONFIG_HAVE_HW_BREAKPOINT
553 	REGSET_HW_BREAK,
554 	REGSET_HW_WATCH,
555 #endif
556 };
557 
558 static const struct user_regset aarch64_regsets[] = {
559 	[REGSET_GPR] = {
560 		.core_note_type = NT_PRSTATUS,
561 		.n = sizeof(struct user_pt_regs) / sizeof(u64),
562 		.size = sizeof(u64),
563 		.align = sizeof(u64),
564 		.get = gpr_get,
565 		.set = gpr_set
566 	},
567 	[REGSET_FPR] = {
568 		.core_note_type = NT_PRFPREG,
569 		.n = sizeof(struct user_fpsimd_state) / sizeof(u32),
570 		/*
571 		 * We pretend we have 32-bit registers because the fpsr and
572 		 * fpcr are 32-bits wide.
573 		 */
574 		.size = sizeof(u32),
575 		.align = sizeof(u32),
576 		.get = fpr_get,
577 		.set = fpr_set
578 	},
579 	[REGSET_TLS] = {
580 		.core_note_type = NT_ARM_TLS,
581 		.n = 1,
582 		.size = sizeof(void *),
583 		.align = sizeof(void *),
584 		.get = tls_get,
585 		.set = tls_set,
586 	},
587 #ifdef CONFIG_HAVE_HW_BREAKPOINT
588 	[REGSET_HW_BREAK] = {
589 		.core_note_type = NT_ARM_HW_BREAK,
590 		.n = sizeof(struct user_hwdebug_state) / sizeof(u32),
591 		.size = sizeof(u32),
592 		.align = sizeof(u32),
593 		.get = hw_break_get,
594 		.set = hw_break_set,
595 	},
596 	[REGSET_HW_WATCH] = {
597 		.core_note_type = NT_ARM_HW_WATCH,
598 		.n = sizeof(struct user_hwdebug_state) / sizeof(u32),
599 		.size = sizeof(u32),
600 		.align = sizeof(u32),
601 		.get = hw_break_get,
602 		.set = hw_break_set,
603 	},
604 #endif
605 };
606 
607 static const struct user_regset_view user_aarch64_view = {
608 	.name = "aarch64", .e_machine = EM_AARCH64,
609 	.regsets = aarch64_regsets, .n = ARRAY_SIZE(aarch64_regsets)
610 };
611 
612 #ifdef CONFIG_COMPAT
613 #include <linux/compat.h>
614 
615 enum compat_regset {
616 	REGSET_COMPAT_GPR,
617 	REGSET_COMPAT_VFP,
618 };
619 
620 static int compat_gpr_get(struct task_struct *target,
621 			  const struct user_regset *regset,
622 			  unsigned int pos, unsigned int count,
623 			  void *kbuf, void __user *ubuf)
624 {
625 	int ret = 0;
626 	unsigned int i, start, num_regs;
627 
628 	/* Calculate the number of AArch32 registers contained in count */
629 	num_regs = count / regset->size;
630 
631 	/* Convert pos into an register number */
632 	start = pos / regset->size;
633 
634 	if (start + num_regs > regset->n)
635 		return -EIO;
636 
637 	for (i = 0; i < num_regs; ++i) {
638 		unsigned int idx = start + i;
639 		void *reg;
640 
641 		switch (idx) {
642 		case 15:
643 			reg = (void *)&task_pt_regs(target)->pc;
644 			break;
645 		case 16:
646 			reg = (void *)&task_pt_regs(target)->pstate;
647 			break;
648 		case 17:
649 			reg = (void *)&task_pt_regs(target)->orig_x0;
650 			break;
651 		default:
652 			reg = (void *)&task_pt_regs(target)->regs[idx];
653 		}
654 
655 		ret = copy_to_user(ubuf, reg, sizeof(compat_ulong_t));
656 
657 		if (ret)
658 			break;
659 		else
660 			ubuf += sizeof(compat_ulong_t);
661 	}
662 
663 	return ret;
664 }
665 
666 static int compat_gpr_set(struct task_struct *target,
667 			  const struct user_regset *regset,
668 			  unsigned int pos, unsigned int count,
669 			  const void *kbuf, const void __user *ubuf)
670 {
671 	struct pt_regs newregs;
672 	int ret = 0;
673 	unsigned int i, start, num_regs;
674 
675 	/* Calculate the number of AArch32 registers contained in count */
676 	num_regs = count / regset->size;
677 
678 	/* Convert pos into an register number */
679 	start = pos / regset->size;
680 
681 	if (start + num_regs > regset->n)
682 		return -EIO;
683 
684 	newregs = *task_pt_regs(target);
685 
686 	for (i = 0; i < num_regs; ++i) {
687 		unsigned int idx = start + i;
688 		void *reg;
689 
690 		switch (idx) {
691 		case 15:
692 			reg = (void *)&newregs.pc;
693 			break;
694 		case 16:
695 			reg = (void *)&newregs.pstate;
696 			break;
697 		case 17:
698 			reg = (void *)&newregs.orig_x0;
699 			break;
700 		default:
701 			reg = (void *)&newregs.regs[idx];
702 		}
703 
704 		ret = copy_from_user(reg, ubuf, sizeof(compat_ulong_t));
705 
706 		if (ret)
707 			goto out;
708 		else
709 			ubuf += sizeof(compat_ulong_t);
710 	}
711 
712 	if (valid_user_regs(&newregs.user_regs))
713 		*task_pt_regs(target) = newregs;
714 	else
715 		ret = -EINVAL;
716 
717 out:
718 	return ret;
719 }
720 
721 static int compat_vfp_get(struct task_struct *target,
722 			  const struct user_regset *regset,
723 			  unsigned int pos, unsigned int count,
724 			  void *kbuf, void __user *ubuf)
725 {
726 	struct user_fpsimd_state *uregs;
727 	compat_ulong_t fpscr;
728 	int ret;
729 
730 	uregs = &target->thread.fpsimd_state.user_fpsimd;
731 
732 	/*
733 	 * The VFP registers are packed into the fpsimd_state, so they all sit
734 	 * nicely together for us. We just need to create the fpscr separately.
735 	 */
736 	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0,
737 				  VFP_STATE_SIZE - sizeof(compat_ulong_t));
738 
739 	if (count && !ret) {
740 		fpscr = (uregs->fpsr & VFP_FPSCR_STAT_MASK) |
741 			(uregs->fpcr & VFP_FPSCR_CTRL_MASK);
742 		ret = put_user(fpscr, (compat_ulong_t *)ubuf);
743 	}
744 
745 	return ret;
746 }
747 
748 static int compat_vfp_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 	struct user_fpsimd_state *uregs;
754 	compat_ulong_t fpscr;
755 	int ret;
756 
757 	if (pos + count > VFP_STATE_SIZE)
758 		return -EIO;
759 
760 	uregs = &target->thread.fpsimd_state.user_fpsimd;
761 
762 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, uregs, 0,
763 				 VFP_STATE_SIZE - sizeof(compat_ulong_t));
764 
765 	if (count && !ret) {
766 		ret = get_user(fpscr, (compat_ulong_t *)ubuf);
767 		uregs->fpsr = fpscr & VFP_FPSCR_STAT_MASK;
768 		uregs->fpcr = fpscr & VFP_FPSCR_CTRL_MASK;
769 	}
770 
771 	return ret;
772 }
773 
774 static const struct user_regset aarch32_regsets[] = {
775 	[REGSET_COMPAT_GPR] = {
776 		.core_note_type = NT_PRSTATUS,
777 		.n = COMPAT_ELF_NGREG,
778 		.size = sizeof(compat_elf_greg_t),
779 		.align = sizeof(compat_elf_greg_t),
780 		.get = compat_gpr_get,
781 		.set = compat_gpr_set
782 	},
783 	[REGSET_COMPAT_VFP] = {
784 		.core_note_type = NT_ARM_VFP,
785 		.n = VFP_STATE_SIZE / sizeof(compat_ulong_t),
786 		.size = sizeof(compat_ulong_t),
787 		.align = sizeof(compat_ulong_t),
788 		.get = compat_vfp_get,
789 		.set = compat_vfp_set
790 	},
791 };
792 
793 static const struct user_regset_view user_aarch32_view = {
794 	.name = "aarch32", .e_machine = EM_ARM,
795 	.regsets = aarch32_regsets, .n = ARRAY_SIZE(aarch32_regsets)
796 };
797 
798 static int compat_ptrace_read_user(struct task_struct *tsk, compat_ulong_t off,
799 				   compat_ulong_t __user *ret)
800 {
801 	compat_ulong_t tmp;
802 
803 	if (off & 3)
804 		return -EIO;
805 
806 	if (off == COMPAT_PT_TEXT_ADDR)
807 		tmp = tsk->mm->start_code;
808 	else if (off == COMPAT_PT_DATA_ADDR)
809 		tmp = tsk->mm->start_data;
810 	else if (off == COMPAT_PT_TEXT_END_ADDR)
811 		tmp = tsk->mm->end_code;
812 	else if (off < sizeof(compat_elf_gregset_t))
813 		return copy_regset_to_user(tsk, &user_aarch32_view,
814 					   REGSET_COMPAT_GPR, off,
815 					   sizeof(compat_ulong_t), ret);
816 	else if (off >= COMPAT_USER_SZ)
817 		return -EIO;
818 	else
819 		tmp = 0;
820 
821 	return put_user(tmp, ret);
822 }
823 
824 static int compat_ptrace_write_user(struct task_struct *tsk, compat_ulong_t off,
825 				    compat_ulong_t val)
826 {
827 	int ret;
828 
829 	if (off & 3 || off >= COMPAT_USER_SZ)
830 		return -EIO;
831 
832 	if (off >= sizeof(compat_elf_gregset_t))
833 		return 0;
834 
835 	ret = copy_regset_from_user(tsk, &user_aarch32_view,
836 				    REGSET_COMPAT_GPR, off,
837 				    sizeof(compat_ulong_t),
838 				    &val);
839 	return ret;
840 }
841 
842 #ifdef CONFIG_HAVE_HW_BREAKPOINT
843 
844 /*
845  * Convert a virtual register number into an index for a thread_info
846  * breakpoint array. Breakpoints are identified using positive numbers
847  * whilst watchpoints are negative. The registers are laid out as pairs
848  * of (address, control), each pair mapping to a unique hw_breakpoint struct.
849  * Register 0 is reserved for describing resource information.
850  */
851 static int compat_ptrace_hbp_num_to_idx(compat_long_t num)
852 {
853 	return (abs(num) - 1) >> 1;
854 }
855 
856 static int compat_ptrace_hbp_get_resource_info(u32 *kdata)
857 {
858 	u8 num_brps, num_wrps, debug_arch, wp_len;
859 	u32 reg = 0;
860 
861 	num_brps	= hw_breakpoint_slots(TYPE_INST);
862 	num_wrps	= hw_breakpoint_slots(TYPE_DATA);
863 
864 	debug_arch	= debug_monitors_arch();
865 	wp_len		= 8;
866 	reg		|= debug_arch;
867 	reg		<<= 8;
868 	reg		|= wp_len;
869 	reg		<<= 8;
870 	reg		|= num_wrps;
871 	reg		<<= 8;
872 	reg		|= num_brps;
873 
874 	*kdata = reg;
875 	return 0;
876 }
877 
878 static int compat_ptrace_hbp_get(unsigned int note_type,
879 				 struct task_struct *tsk,
880 				 compat_long_t num,
881 				 u32 *kdata)
882 {
883 	u64 addr = 0;
884 	u32 ctrl = 0;
885 
886 	int err, idx = compat_ptrace_hbp_num_to_idx(num);;
887 
888 	if (num & 1) {
889 		err = ptrace_hbp_get_addr(note_type, tsk, idx, &addr);
890 		*kdata = (u32)addr;
891 	} else {
892 		err = ptrace_hbp_get_ctrl(note_type, tsk, idx, &ctrl);
893 		*kdata = ctrl;
894 	}
895 
896 	return err;
897 }
898 
899 static int compat_ptrace_hbp_set(unsigned int note_type,
900 				 struct task_struct *tsk,
901 				 compat_long_t num,
902 				 u32 *kdata)
903 {
904 	u64 addr;
905 	u32 ctrl;
906 
907 	int err, idx = compat_ptrace_hbp_num_to_idx(num);
908 
909 	if (num & 1) {
910 		addr = *kdata;
911 		err = ptrace_hbp_set_addr(note_type, tsk, idx, addr);
912 	} else {
913 		ctrl = *kdata;
914 		err = ptrace_hbp_set_ctrl(note_type, tsk, idx, ctrl);
915 	}
916 
917 	return err;
918 }
919 
920 static int compat_ptrace_gethbpregs(struct task_struct *tsk, compat_long_t num,
921 				    compat_ulong_t __user *data)
922 {
923 	int ret;
924 	u32 kdata;
925 	mm_segment_t old_fs = get_fs();
926 
927 	set_fs(KERNEL_DS);
928 	/* Watchpoint */
929 	if (num < 0) {
930 		ret = compat_ptrace_hbp_get(NT_ARM_HW_WATCH, tsk, num, &kdata);
931 	/* Resource info */
932 	} else if (num == 0) {
933 		ret = compat_ptrace_hbp_get_resource_info(&kdata);
934 	/* Breakpoint */
935 	} else {
936 		ret = compat_ptrace_hbp_get(NT_ARM_HW_BREAK, tsk, num, &kdata);
937 	}
938 	set_fs(old_fs);
939 
940 	if (!ret)
941 		ret = put_user(kdata, data);
942 
943 	return ret;
944 }
945 
946 static int compat_ptrace_sethbpregs(struct task_struct *tsk, compat_long_t num,
947 				    compat_ulong_t __user *data)
948 {
949 	int ret;
950 	u32 kdata = 0;
951 	mm_segment_t old_fs = get_fs();
952 
953 	if (num == 0)
954 		return 0;
955 
956 	ret = get_user(kdata, data);
957 	if (ret)
958 		return ret;
959 
960 	set_fs(KERNEL_DS);
961 	if (num < 0)
962 		ret = compat_ptrace_hbp_set(NT_ARM_HW_WATCH, tsk, num, &kdata);
963 	else
964 		ret = compat_ptrace_hbp_set(NT_ARM_HW_BREAK, tsk, num, &kdata);
965 	set_fs(old_fs);
966 
967 	return ret;
968 }
969 #endif	/* CONFIG_HAVE_HW_BREAKPOINT */
970 
971 long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
972 			compat_ulong_t caddr, compat_ulong_t cdata)
973 {
974 	unsigned long addr = caddr;
975 	unsigned long data = cdata;
976 	void __user *datap = compat_ptr(data);
977 	int ret;
978 
979 	switch (request) {
980 		case PTRACE_PEEKUSR:
981 			ret = compat_ptrace_read_user(child, addr, datap);
982 			break;
983 
984 		case PTRACE_POKEUSR:
985 			ret = compat_ptrace_write_user(child, addr, data);
986 			break;
987 
988 		case COMPAT_PTRACE_GETREGS:
989 			ret = copy_regset_to_user(child,
990 						  &user_aarch32_view,
991 						  REGSET_COMPAT_GPR,
992 						  0, sizeof(compat_elf_gregset_t),
993 						  datap);
994 			break;
995 
996 		case COMPAT_PTRACE_SETREGS:
997 			ret = copy_regset_from_user(child,
998 						    &user_aarch32_view,
999 						    REGSET_COMPAT_GPR,
1000 						    0, sizeof(compat_elf_gregset_t),
1001 						    datap);
1002 			break;
1003 
1004 		case COMPAT_PTRACE_GET_THREAD_AREA:
1005 			ret = put_user((compat_ulong_t)child->thread.tp_value,
1006 				       (compat_ulong_t __user *)datap);
1007 			break;
1008 
1009 		case COMPAT_PTRACE_SET_SYSCALL:
1010 			task_pt_regs(child)->syscallno = data;
1011 			ret = 0;
1012 			break;
1013 
1014 		case COMPAT_PTRACE_GETVFPREGS:
1015 			ret = copy_regset_to_user(child,
1016 						  &user_aarch32_view,
1017 						  REGSET_COMPAT_VFP,
1018 						  0, VFP_STATE_SIZE,
1019 						  datap);
1020 			break;
1021 
1022 		case COMPAT_PTRACE_SETVFPREGS:
1023 			ret = copy_regset_from_user(child,
1024 						    &user_aarch32_view,
1025 						    REGSET_COMPAT_VFP,
1026 						    0, VFP_STATE_SIZE,
1027 						    datap);
1028 			break;
1029 
1030 #ifdef CONFIG_HAVE_HW_BREAKPOINT
1031 		case COMPAT_PTRACE_GETHBPREGS:
1032 			ret = compat_ptrace_gethbpregs(child, addr, datap);
1033 			break;
1034 
1035 		case COMPAT_PTRACE_SETHBPREGS:
1036 			ret = compat_ptrace_sethbpregs(child, addr, datap);
1037 			break;
1038 #endif
1039 
1040 		default:
1041 			ret = compat_ptrace_request(child, request, addr,
1042 						    data);
1043 			break;
1044 	}
1045 
1046 	return ret;
1047 }
1048 #endif /* CONFIG_COMPAT */
1049 
1050 const struct user_regset_view *task_user_regset_view(struct task_struct *task)
1051 {
1052 #ifdef CONFIG_COMPAT
1053 	if (is_compat_thread(task_thread_info(task)))
1054 		return &user_aarch32_view;
1055 #endif
1056 	return &user_aarch64_view;
1057 }
1058 
1059 long arch_ptrace(struct task_struct *child, long request,
1060 		 unsigned long addr, unsigned long data)
1061 {
1062 	return ptrace_request(child, request, addr, data);
1063 }
1064 
1065 asmlinkage int syscall_trace(int dir, struct pt_regs *regs)
1066 {
1067 	unsigned long saved_reg;
1068 
1069 	if (!test_thread_flag(TIF_SYSCALL_TRACE))
1070 		return regs->syscallno;
1071 
1072 	if (is_compat_task()) {
1073 		/* AArch32 uses ip (r12) for scratch */
1074 		saved_reg = regs->regs[12];
1075 		regs->regs[12] = dir;
1076 	} else {
1077 		/*
1078 		 * Save X7. X7 is used to denote syscall entry/exit:
1079 		 *   X7 = 0 -> entry, = 1 -> exit
1080 		 */
1081 		saved_reg = regs->regs[7];
1082 		regs->regs[7] = dir;
1083 	}
1084 
1085 	if (dir)
1086 		tracehook_report_syscall_exit(regs, 0);
1087 	else if (tracehook_report_syscall_entry(regs))
1088 		regs->syscallno = ~0UL;
1089 
1090 	if (is_compat_task())
1091 		regs->regs[12] = saved_reg;
1092 	else
1093 		regs->regs[7] = saved_reg;
1094 
1095 	return regs->syscallno;
1096 }
1097