xref: /freebsd/sys/arm64/arm64/trap.c (revision 19261079)
1 /*-
2  * Copyright (c) 2014 Andrew Turner
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  */
27 
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30 
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/kernel.h>
34 #include <sys/ktr.h>
35 #include <sys/lock.h>
36 #include <sys/mutex.h>
37 #include <sys/proc.h>
38 #include <sys/ptrace.h>
39 #include <sys/syscall.h>
40 #include <sys/sysent.h>
41 #ifdef KDB
42 #include <sys/kdb.h>
43 #endif
44 
45 #include <vm/vm.h>
46 #include <vm/pmap.h>
47 #include <vm/vm_kern.h>
48 #include <vm/vm_map.h>
49 #include <vm/vm_param.h>
50 #include <vm/vm_extern.h>
51 
52 #include <machine/frame.h>
53 #include <machine/md_var.h>
54 #include <machine/pcb.h>
55 #include <machine/pcpu.h>
56 #include <machine/undefined.h>
57 
58 #ifdef KDTRACE_HOOKS
59 #include <sys/dtrace_bsd.h>
60 #endif
61 
62 #ifdef VFP
63 #include <machine/vfp.h>
64 #endif
65 
66 #ifdef KDB
67 #include <machine/db_machdep.h>
68 #endif
69 
70 #ifdef DDB
71 #include <ddb/db_output.h>
72 #endif
73 
74 /* Called from exception.S */
75 void do_el1h_sync(struct thread *, struct trapframe *);
76 void do_el0_sync(struct thread *, struct trapframe *);
77 void do_el0_error(struct trapframe *);
78 void do_serror(struct trapframe *);
79 void unhandled_exception(struct trapframe *);
80 
81 static void print_registers(struct trapframe *frame);
82 
83 int (*dtrace_invop_jump_addr)(struct trapframe *);
84 
85 typedef void (abort_handler)(struct thread *, struct trapframe *, uint64_t,
86     uint64_t, int);
87 
88 static abort_handler align_abort;
89 static abort_handler data_abort;
90 static abort_handler external_abort;
91 
92 static abort_handler *abort_handlers[] = {
93 	[ISS_DATA_DFSC_TF_L0] = data_abort,
94 	[ISS_DATA_DFSC_TF_L1] = data_abort,
95 	[ISS_DATA_DFSC_TF_L2] = data_abort,
96 	[ISS_DATA_DFSC_TF_L3] = data_abort,
97 	[ISS_DATA_DFSC_AFF_L1] = data_abort,
98 	[ISS_DATA_DFSC_AFF_L2] = data_abort,
99 	[ISS_DATA_DFSC_AFF_L3] = data_abort,
100 	[ISS_DATA_DFSC_PF_L1] = data_abort,
101 	[ISS_DATA_DFSC_PF_L2] = data_abort,
102 	[ISS_DATA_DFSC_PF_L3] = data_abort,
103 	[ISS_DATA_DFSC_ALIGN] = align_abort,
104 	[ISS_DATA_DFSC_EXT] =  external_abort,
105 	[ISS_DATA_DFSC_EXT_L0] =  external_abort,
106 	[ISS_DATA_DFSC_EXT_L1] =  external_abort,
107 	[ISS_DATA_DFSC_EXT_L2] =  external_abort,
108 	[ISS_DATA_DFSC_EXT_L3] =  external_abort,
109 	[ISS_DATA_DFSC_ECC] =  external_abort,
110 	[ISS_DATA_DFSC_ECC_L0] =  external_abort,
111 	[ISS_DATA_DFSC_ECC_L1] =  external_abort,
112 	[ISS_DATA_DFSC_ECC_L2] =  external_abort,
113 	[ISS_DATA_DFSC_ECC_L3] =  external_abort,
114 };
115 
116 static __inline void
117 call_trapsignal(struct thread *td, int sig, int code, void *addr, int trapno)
118 {
119 	ksiginfo_t ksi;
120 
121 	ksiginfo_init_trap(&ksi);
122 	ksi.ksi_signo = sig;
123 	ksi.ksi_code = code;
124 	ksi.ksi_addr = addr;
125 	ksi.ksi_trapno = trapno;
126 	trapsignal(td, &ksi);
127 }
128 
129 int
130 cpu_fetch_syscall_args(struct thread *td)
131 {
132 	struct proc *p;
133 	register_t *ap, *dst_ap;
134 	struct syscall_args *sa;
135 
136 	p = td->td_proc;
137 	sa = &td->td_sa;
138 	ap = td->td_frame->tf_x;
139 	dst_ap = &sa->args[0];
140 
141 	sa->code = td->td_frame->tf_x[8];
142 	sa->original_code = sa->code;
143 
144 	if (__predict_false(sa->code == SYS_syscall || sa->code == SYS___syscall)) {
145 		sa->code = *ap++;
146 	} else {
147 		*dst_ap++ = *ap++;
148 	}
149 
150 	if (__predict_false(sa->code >= p->p_sysent->sv_size))
151 		sa->callp = &p->p_sysent->sv_table[0];
152 	else
153 		sa->callp = &p->p_sysent->sv_table[sa->code];
154 
155 	KASSERT(sa->callp->sy_narg <= nitems(sa->args),
156 	    ("Syscall %d takes too many arguments", sa->code));
157 
158 	memcpy(dst_ap, ap, (MAXARGS - 1) * sizeof(register_t));
159 
160 	td->td_retval[0] = 0;
161 	td->td_retval[1] = 0;
162 
163 	return (0);
164 }
165 
166 #include "../../kern/subr_syscall.c"
167 
168 /*
169  * Test for fault generated by given access instruction in
170  * bus_peek_<foo> or bus_poke_<foo> bus function.
171  */
172 extern uint32_t generic_bs_peek_1f, generic_bs_peek_2f;
173 extern uint32_t generic_bs_peek_4f, generic_bs_peek_8f;
174 extern uint32_t generic_bs_poke_1f, generic_bs_poke_2f;
175 extern uint32_t generic_bs_poke_4f, generic_bs_poke_8f;
176 
177 static bool
178 test_bs_fault(void *addr)
179 {
180 	return (addr == &generic_bs_peek_1f ||
181 	    addr == &generic_bs_peek_2f ||
182 	    addr == &generic_bs_peek_4f ||
183 	    addr == &generic_bs_peek_8f ||
184 	    addr == &generic_bs_poke_1f ||
185 	    addr == &generic_bs_poke_2f ||
186 	    addr == &generic_bs_poke_4f ||
187 	    addr == &generic_bs_poke_8f);
188 }
189 
190 static void
191 svc_handler(struct thread *td, struct trapframe *frame)
192 {
193 
194 	if ((frame->tf_esr & ESR_ELx_ISS_MASK) == 0) {
195 		syscallenter(td);
196 		syscallret(td);
197 	} else {
198 		call_trapsignal(td, SIGILL, ILL_ILLOPN, (void *)frame->tf_elr,
199 		    ESR_ELx_EXCEPTION(frame->tf_esr));
200 		userret(td, frame);
201 	}
202 }
203 
204 static void
205 align_abort(struct thread *td, struct trapframe *frame, uint64_t esr,
206     uint64_t far, int lower)
207 {
208 	if (!lower) {
209 		print_registers(frame);
210 		printf(" far: %16lx\n", far);
211 		printf(" esr:         %.8lx\n", esr);
212 		panic("Misaligned access from kernel space!");
213 	}
214 
215 	call_trapsignal(td, SIGBUS, BUS_ADRALN, (void *)frame->tf_elr,
216 	    ESR_ELx_EXCEPTION(frame->tf_esr));
217 	userret(td, frame);
218 }
219 
220 
221 static void
222 external_abort(struct thread *td, struct trapframe *frame, uint64_t esr,
223     uint64_t far, int lower)
224 {
225 
226 	/*
227 	 * Try to handle synchronous external aborts caused by
228 	 * bus_space_peek() and/or bus_space_poke() functions.
229 	 */
230 	if (!lower && test_bs_fault((void *)frame->tf_elr)) {
231 		frame->tf_elr = (uint64_t)generic_bs_fault;
232 		return;
233 	}
234 
235 	print_registers(frame);
236 	printf(" far: %16lx\n", far);
237 	panic("Unhandled EL%d external data abort", lower ? 0: 1);
238 }
239 
240 static void
241 data_abort(struct thread *td, struct trapframe *frame, uint64_t esr,
242     uint64_t far, int lower)
243 {
244 	struct vm_map *map;
245 	struct proc *p;
246 	struct pcb *pcb;
247 	vm_prot_t ftype;
248 	int error, sig, ucode;
249 #ifdef KDB
250 	bool handled;
251 #endif
252 
253 	/*
254 	 * According to the ARMv8-A rev. A.g, B2.10.5 "Load-Exclusive
255 	 * and Store-Exclusive instruction usage restrictions", state
256 	 * of the exclusive monitors after data abort exception is unknown.
257 	 */
258 	clrex();
259 
260 #ifdef KDB
261 	if (kdb_active) {
262 		kdb_reenter();
263 		return;
264 	}
265 #endif
266 
267 	pcb = td->td_pcb;
268 	p = td->td_proc;
269 	if (lower)
270 		map = &p->p_vmspace->vm_map;
271 	else {
272 		intr_enable();
273 
274 		/* We received a TBI/PAC/etc. fault from the kernel */
275 		if (!ADDR_IS_CANONICAL(far)) {
276 			error = KERN_INVALID_ADDRESS;
277 			goto bad_far;
278 		}
279 
280 		/* The top bit tells us which range to use */
281 		if (ADDR_IS_KERNEL(far)) {
282 			map = kernel_map;
283 		} else {
284 			map = &p->p_vmspace->vm_map;
285 			if (map == NULL)
286 				map = kernel_map;
287 		}
288 	}
289 
290 	/*
291 	 * Try to handle translation, access flag, and permission faults.
292 	 * Translation faults may occur as a result of the required
293 	 * break-before-make sequence used when promoting or demoting
294 	 * superpages.  Such faults must not occur while holding the pmap lock,
295 	 * or pmap_fault() will recurse on that lock.
296 	 */
297 	if ((lower || map == kernel_map || pcb->pcb_onfault != 0) &&
298 	    pmap_fault(map->pmap, esr, far) == KERN_SUCCESS)
299 		return;
300 
301 	KASSERT(td->td_md.md_spinlock_count == 0,
302 	    ("data abort with spinlock held"));
303 	if (td->td_critnest != 0 || WITNESS_CHECK(WARN_SLEEPOK |
304 	    WARN_GIANTOK, NULL, "Kernel page fault") != 0) {
305 		print_registers(frame);
306 		printf(" far: %16lx\n", far);
307 		printf(" esr:         %.8lx\n", esr);
308 		panic("data abort in critical section or under mutex");
309 	}
310 
311 	switch (ESR_ELx_EXCEPTION(esr)) {
312 	case EXCP_INSN_ABORT:
313 	case EXCP_INSN_ABORT_L:
314 		ftype = VM_PROT_EXECUTE;
315 		break;
316 	default:
317 		ftype = (esr & ISS_DATA_WnR) == 0 ? VM_PROT_READ :
318 		    VM_PROT_WRITE;
319 		break;
320 	}
321 
322 	/* Fault in the page. */
323 	error = vm_fault_trap(map, far, ftype, VM_FAULT_NORMAL, &sig, &ucode);
324 	if (error != KERN_SUCCESS) {
325 bad_far:
326 		if (lower) {
327 			call_trapsignal(td, sig, ucode, (void *)far,
328 			    ESR_ELx_EXCEPTION(esr));
329 		} else {
330 			if (td->td_intr_nesting_level == 0 &&
331 			    pcb->pcb_onfault != 0) {
332 				frame->tf_x[0] = error;
333 				frame->tf_elr = pcb->pcb_onfault;
334 				return;
335 			}
336 
337 			printf("Fatal data abort:\n");
338 			print_registers(frame);
339 			printf(" far: %16lx\n", far);
340 			printf(" esr:         %.8lx\n", esr);
341 
342 #ifdef KDB
343 			if (debugger_on_trap) {
344 				kdb_why = KDB_WHY_TRAP;
345 				handled = kdb_trap(ESR_ELx_EXCEPTION(esr), 0,
346 				    frame);
347 				kdb_why = KDB_WHY_UNSET;
348 				if (handled)
349 					return;
350 			}
351 #endif
352 			panic("vm_fault failed: %lx error %d",
353 			    frame->tf_elr, error);
354 		}
355 	}
356 
357 	if (lower)
358 		userret(td, frame);
359 }
360 
361 static void
362 print_registers(struct trapframe *frame)
363 {
364 	u_int reg;
365 
366 	for (reg = 0; reg < nitems(frame->tf_x); reg++) {
367 		printf(" %sx%d: %16lx\n", (reg < 10) ? " " : "", reg,
368 		    frame->tf_x[reg]);
369 	}
370 	printf("  sp: %16lx\n", frame->tf_sp);
371 	printf("  lr: %16lx\n", frame->tf_lr);
372 	printf(" elr: %16lx\n", frame->tf_elr);
373 	printf("spsr:         %8x\n", frame->tf_spsr);
374 }
375 
376 void
377 do_el1h_sync(struct thread *td, struct trapframe *frame)
378 {
379 	uint32_t exception;
380 	uint64_t esr, far;
381 	int dfsc;
382 
383 	/* Read the esr register to get the exception details */
384 	esr = frame->tf_esr;
385 	exception = ESR_ELx_EXCEPTION(esr);
386 
387 #ifdef KDTRACE_HOOKS
388 	if (dtrace_trap_func != NULL && (*dtrace_trap_func)(frame, exception))
389 		return;
390 #endif
391 
392 	CTR4(KTR_TRAP,
393 	    "do_el1_sync: curthread: %p, esr %lx, elr: %lx, frame: %p", td,
394 	    esr, frame->tf_elr, frame);
395 
396 	/*
397 	 * Enable debug exceptions if we aren't already handling one. They will
398 	 * be masked again in the exception handler's epilogue.
399 	 */
400 	if (exception != EXCP_BRK && exception != EXCP_WATCHPT_EL1 &&
401 	    exception != EXCP_SOFTSTP_EL1)
402 		dbg_enable();
403 
404 	switch (exception) {
405 	case EXCP_FP_SIMD:
406 	case EXCP_TRAP_FP:
407 #ifdef VFP
408 		if ((td->td_pcb->pcb_fpflags & PCB_FP_KERN) != 0) {
409 			vfp_restore_state();
410 		} else
411 #endif
412 		{
413 			print_registers(frame);
414 			printf(" esr:         %.8lx\n", esr);
415 			panic("VFP exception in the kernel");
416 		}
417 		break;
418 	case EXCP_INSN_ABORT:
419 	case EXCP_DATA_ABORT:
420 		far = READ_SPECIALREG(far_el1);
421 		dfsc = esr & ISS_DATA_DFSC_MASK;
422 		if (dfsc < nitems(abort_handlers) &&
423 		    abort_handlers[dfsc] != NULL) {
424 			abort_handlers[dfsc](td, frame, esr, far, 0);
425 		} else {
426 			print_registers(frame);
427 			printf(" far: %16lx\n", far);
428 			printf(" esr:         %.8lx\n", esr);
429 			panic("Unhandled EL1 %s abort: %x",
430 			    exception == EXCP_INSN_ABORT ? "instruction" :
431 			    "data", dfsc);
432 		}
433 		break;
434 	case EXCP_BRK:
435 #ifdef KDTRACE_HOOKS
436 		if ((esr & ESR_ELx_ISS_MASK) == 0x40d && \
437 		    dtrace_invop_jump_addr != 0) {
438 			dtrace_invop_jump_addr(frame);
439 			break;
440 		}
441 #endif
442 #ifdef KDB
443 		kdb_trap(exception, 0, frame);
444 #else
445 		panic("No debugger in kernel.");
446 #endif
447 		break;
448 	case EXCP_WATCHPT_EL1:
449 	case EXCP_SOFTSTP_EL1:
450 #ifdef KDB
451 		kdb_trap(exception, 0, frame);
452 #else
453 		panic("No debugger in kernel.");
454 #endif
455 		break;
456 	case EXCP_UNKNOWN:
457 		if (undef_insn(1, frame))
458 			break;
459 		/* FALLTHROUGH */
460 	default:
461 		print_registers(frame);
462 		printf(" far: %16lx\n", READ_SPECIALREG(far_el1));
463 		panic("Unknown kernel exception %x esr_el1 %lx", exception,
464 		    esr);
465 	}
466 }
467 
468 void
469 do_el0_sync(struct thread *td, struct trapframe *frame)
470 {
471 	pcpu_bp_harden bp_harden;
472 	uint32_t exception;
473 	uint64_t esr, far;
474 	int dfsc;
475 
476 	/* Check we have a sane environment when entering from userland */
477 	KASSERT((uintptr_t)get_pcpu() >= VM_MIN_KERNEL_ADDRESS,
478 	    ("Invalid pcpu address from userland: %p (tpidr %lx)",
479 	     get_pcpu(), READ_SPECIALREG(tpidr_el1)));
480 
481 	esr = frame->tf_esr;
482 	exception = ESR_ELx_EXCEPTION(esr);
483 	switch (exception) {
484 	case EXCP_INSN_ABORT_L:
485 		far = READ_SPECIALREG(far_el1);
486 
487 		/*
488 		 * Userspace may be trying to train the branch predictor to
489 		 * attack the kernel. If we are on a CPU affected by this
490 		 * call the handler to clear the branch predictor state.
491 		 */
492 		if (far > VM_MAXUSER_ADDRESS) {
493 			bp_harden = PCPU_GET(bp_harden);
494 			if (bp_harden != NULL)
495 				bp_harden();
496 		}
497 		break;
498 	case EXCP_UNKNOWN:
499 	case EXCP_DATA_ABORT_L:
500 	case EXCP_DATA_ABORT:
501 	case EXCP_WATCHPT_EL0:
502 		far = READ_SPECIALREG(far_el1);
503 		break;
504 	}
505 	intr_enable();
506 
507 	CTR4(KTR_TRAP,
508 	    "do_el0_sync: curthread: %p, esr %lx, elr: %lx, frame: %p", td, esr,
509 	    frame->tf_elr, frame);
510 
511 	switch (exception) {
512 	case EXCP_FP_SIMD:
513 	case EXCP_TRAP_FP:
514 #ifdef VFP
515 		vfp_restore_state();
516 #else
517 		panic("VFP exception in userland");
518 #endif
519 		break;
520 	case EXCP_SVC32:
521 	case EXCP_SVC64:
522 		svc_handler(td, frame);
523 		break;
524 	case EXCP_INSN_ABORT_L:
525 	case EXCP_DATA_ABORT_L:
526 	case EXCP_DATA_ABORT:
527 		dfsc = esr & ISS_DATA_DFSC_MASK;
528 		if (dfsc < nitems(abort_handlers) &&
529 		    abort_handlers[dfsc] != NULL)
530 			abort_handlers[dfsc](td, frame, esr, far, 1);
531 		else {
532 			print_registers(frame);
533 			printf(" far: %16lx\n", far);
534 			printf(" esr:         %.8lx\n", esr);
535 			panic("Unhandled EL0 %s abort: %x",
536 			    exception == EXCP_INSN_ABORT_L ? "instruction" :
537 			    "data", dfsc);
538 		}
539 		break;
540 	case EXCP_UNKNOWN:
541 		if (!undef_insn(0, frame))
542 			call_trapsignal(td, SIGILL, ILL_ILLTRP, (void *)far,
543 			    exception);
544 		userret(td, frame);
545 		break;
546 	case EXCP_SP_ALIGN:
547 		call_trapsignal(td, SIGBUS, BUS_ADRALN, (void *)frame->tf_sp,
548 		    exception);
549 		userret(td, frame);
550 		break;
551 	case EXCP_PC_ALIGN:
552 		call_trapsignal(td, SIGBUS, BUS_ADRALN, (void *)frame->tf_elr,
553 		    exception);
554 		userret(td, frame);
555 		break;
556 	case EXCP_BRKPT_EL0:
557 	case EXCP_BRK:
558 		call_trapsignal(td, SIGTRAP, TRAP_BRKPT, (void *)frame->tf_elr,
559 		    exception);
560 		userret(td, frame);
561 		break;
562 	case EXCP_WATCHPT_EL0:
563 		call_trapsignal(td, SIGTRAP, TRAP_TRACE, (void *)far,
564 		    exception);
565 		userret(td, frame);
566 		break;
567 	case EXCP_MSR:
568 		/*
569 		 * The CPU can raise EXCP_MSR when userspace executes an mrs
570 		 * instruction to access a special register userspace doesn't
571 		 * have access to.
572 		 */
573 		if (!undef_insn(0, frame))
574 			call_trapsignal(td, SIGILL, ILL_PRVOPC,
575 			    (void *)frame->tf_elr, exception);
576 		userret(td, frame);
577 		break;
578 	case EXCP_SOFTSTP_EL0:
579 		td->td_frame->tf_spsr &= ~PSR_SS;
580 		td->td_pcb->pcb_flags &= ~PCB_SINGLE_STEP;
581 		WRITE_SPECIALREG(mdscr_el1,
582 		    READ_SPECIALREG(mdscr_el1) & ~DBG_MDSCR_SS);
583 		call_trapsignal(td, SIGTRAP, TRAP_TRACE,
584 		    (void *)frame->tf_elr, exception);
585 		userret(td, frame);
586 		break;
587 	default:
588 		call_trapsignal(td, SIGBUS, BUS_OBJERR, (void *)frame->tf_elr,
589 		    exception);
590 		userret(td, frame);
591 		break;
592 	}
593 
594 	KASSERT((td->td_pcb->pcb_fpflags & ~PCB_FP_USERMASK) == 0,
595 	    ("Kernel VFP flags set while entering userspace"));
596 	KASSERT(
597 	    td->td_pcb->pcb_fpusaved == &td->td_pcb->pcb_fpustate,
598 	    ("Kernel VFP state in use when entering userspace"));
599 }
600 
601 /*
602  * TODO: We will need to handle these later when we support ARMv8.2 RAS.
603  */
604 void
605 do_serror(struct trapframe *frame)
606 {
607 	uint64_t esr, far;
608 
609 	far = READ_SPECIALREG(far_el1);
610 	esr = frame->tf_esr;
611 
612 	print_registers(frame);
613 	printf(" far: %16lx\n", far);
614 	printf(" esr:         %.8lx\n", esr);
615 	panic("Unhandled System Error");
616 }
617 
618 void
619 unhandled_exception(struct trapframe *frame)
620 {
621 	uint64_t esr, far;
622 
623 	far = READ_SPECIALREG(far_el1);
624 	esr = frame->tf_esr;
625 
626 	print_registers(frame);
627 	printf(" far: %16lx\n", far);
628 	printf(" esr:         %.8lx\n", esr);
629 	panic("Unhandled exception");
630 }
631