xref: /freebsd/sys/arm64/arm64/trap.c (revision c802b486)
1e5acd89cSAndrew Turner /*-
2e5acd89cSAndrew Turner  * Copyright (c) 2014 Andrew Turner
3e5acd89cSAndrew Turner  * All rights reserved.
4e5acd89cSAndrew Turner  *
5e5acd89cSAndrew Turner  * Redistribution and use in source and binary forms, with or without
6e5acd89cSAndrew Turner  * modification, are permitted provided that the following conditions
7e5acd89cSAndrew Turner  * are met:
8e5acd89cSAndrew Turner  * 1. Redistributions of source code must retain the above copyright
9e5acd89cSAndrew Turner  *    notice, this list of conditions and the following disclaimer.
10e5acd89cSAndrew Turner  * 2. Redistributions in binary form must reproduce the above copyright
11e5acd89cSAndrew Turner  *    notice, this list of conditions and the following disclaimer in the
12e5acd89cSAndrew Turner  *    documentation and/or other materials provided with the distribution.
13e5acd89cSAndrew Turner  *
14e5acd89cSAndrew Turner  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15e5acd89cSAndrew Turner  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16e5acd89cSAndrew Turner  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17e5acd89cSAndrew Turner  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18e5acd89cSAndrew Turner  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19e5acd89cSAndrew Turner  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20e5acd89cSAndrew Turner  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21e5acd89cSAndrew Turner  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22e5acd89cSAndrew Turner  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23e5acd89cSAndrew Turner  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24e5acd89cSAndrew Turner  * SUCH DAMAGE.
25e5acd89cSAndrew Turner  *
26e5acd89cSAndrew Turner  */
27e5acd89cSAndrew Turner 
287ec86b66SAndrew Turner #include "opt_ddb.h"
297ec86b66SAndrew Turner 
30e5acd89cSAndrew Turner #include <sys/param.h>
31e5acd89cSAndrew Turner #include <sys/systm.h>
3289c52f9dSKyle Evans #include <sys/asan.h>
33e5acd89cSAndrew Turner #include <sys/kernel.h>
34daec9284SConrad Meyer #include <sys/ktr.h>
35e5acd89cSAndrew Turner #include <sys/lock.h>
36c05d7bdaSMark Johnston #include <sys/msan.h>
37e5acd89cSAndrew Turner #include <sys/mutex.h>
38e5acd89cSAndrew Turner #include <sys/proc.h>
39e5acd89cSAndrew Turner #include <sys/ptrace.h>
40e5acd89cSAndrew Turner #include <sys/syscall.h>
41e5acd89cSAndrew Turner #include <sys/sysent.h>
42e5acd89cSAndrew Turner #ifdef KDB
43e5acd89cSAndrew Turner #include <sys/kdb.h>
44e5acd89cSAndrew Turner #endif
45e5acd89cSAndrew Turner 
46e5acd89cSAndrew Turner #include <vm/vm.h>
47e5acd89cSAndrew Turner #include <vm/pmap.h>
48e5acd89cSAndrew Turner #include <vm/vm_kern.h>
49e5acd89cSAndrew Turner #include <vm/vm_map.h>
50cb02f6b9SAndrew Turner #include <vm/vm_param.h>
51e5acd89cSAndrew Turner #include <vm/vm_extern.h>
52e5acd89cSAndrew Turner 
53e5acd89cSAndrew Turner #include <machine/frame.h>
5495a85c12SMichal Meloun #include <machine/md_var.h>
55e5acd89cSAndrew Turner #include <machine/pcb.h>
56e5acd89cSAndrew Turner #include <machine/pcpu.h>
57bcf2b954SAndrew Turner #include <machine/undefined.h>
58e5acd89cSAndrew Turner 
59b78ee15eSRuslan Bukin #ifdef KDTRACE_HOOKS
60b78ee15eSRuslan Bukin #include <sys/dtrace_bsd.h>
61b78ee15eSRuslan Bukin #endif
62b78ee15eSRuslan Bukin 
63e5acd89cSAndrew Turner #ifdef VFP
64e5acd89cSAndrew Turner #include <machine/vfp.h>
65e5acd89cSAndrew Turner #endif
66e5acd89cSAndrew Turner 
67e5acd89cSAndrew Turner #ifdef KDB
68e5acd89cSAndrew Turner #include <machine/db_machdep.h>
69e5acd89cSAndrew Turner #endif
70e5acd89cSAndrew Turner 
71e5acd89cSAndrew Turner #ifdef DDB
727ec86b66SAndrew Turner #include <ddb/ddb.h>
737ec86b66SAndrew Turner #include <ddb/db_sym.h>
74e5acd89cSAndrew Turner #endif
75e5acd89cSAndrew Turner 
76e5acd89cSAndrew Turner /* Called from exception.S */
77d7635c7aSAndrew Turner void do_el1h_sync(struct thread *, struct trapframe *);
78f4036a92SZachary Leaf void do_el0_sync(struct thread *, struct trapframe *);
79e5acd89cSAndrew Turner void do_el0_error(struct trapframe *);
80dc9b99a8SAndrew Turner void do_serror(struct trapframe *);
81dc9b99a8SAndrew Turner void unhandled_exception(struct trapframe *);
82dc9b99a8SAndrew Turner 
837ec86b66SAndrew Turner static void print_gp_register(const char *name, uint64_t value);
840510aedcSKonstantin Belousov static void print_registers(struct trapframe *frame);
85e5acd89cSAndrew Turner 
86b78ee15eSRuslan Bukin int (*dtrace_invop_jump_addr)(struct trapframe *);
87b78ee15eSRuslan Bukin 
88acd6f4beSAndrew Turner typedef void (abort_handler)(struct thread *, struct trapframe *, uint64_t,
89acd6f4beSAndrew Turner     uint64_t, int);
90acd6f4beSAndrew Turner 
91c7bb1909SJustin Hibbits static abort_handler align_abort;
92acd6f4beSAndrew Turner static abort_handler data_abort;
9395a85c12SMichal Meloun static abort_handler external_abort;
94acd6f4beSAndrew Turner 
95acd6f4beSAndrew Turner static abort_handler *abort_handlers[] = {
96acd6f4beSAndrew Turner 	[ISS_DATA_DFSC_TF_L0] = data_abort,
97acd6f4beSAndrew Turner 	[ISS_DATA_DFSC_TF_L1] = data_abort,
98acd6f4beSAndrew Turner 	[ISS_DATA_DFSC_TF_L2] = data_abort,
99acd6f4beSAndrew Turner 	[ISS_DATA_DFSC_TF_L3] = data_abort,
100acd6f4beSAndrew Turner 	[ISS_DATA_DFSC_AFF_L1] = data_abort,
101acd6f4beSAndrew Turner 	[ISS_DATA_DFSC_AFF_L2] = data_abort,
102acd6f4beSAndrew Turner 	[ISS_DATA_DFSC_AFF_L3] = data_abort,
103acd6f4beSAndrew Turner 	[ISS_DATA_DFSC_PF_L1] = data_abort,
104acd6f4beSAndrew Turner 	[ISS_DATA_DFSC_PF_L2] = data_abort,
105acd6f4beSAndrew Turner 	[ISS_DATA_DFSC_PF_L3] = data_abort,
106c7bb1909SJustin Hibbits 	[ISS_DATA_DFSC_ALIGN] = align_abort,
10795a85c12SMichal Meloun 	[ISS_DATA_DFSC_EXT] =  external_abort,
108dcfd6058SAndrew Turner 	[ISS_DATA_DFSC_EXT_L0] =  external_abort,
109dcfd6058SAndrew Turner 	[ISS_DATA_DFSC_EXT_L1] =  external_abort,
110dcfd6058SAndrew Turner 	[ISS_DATA_DFSC_EXT_L2] =  external_abort,
111dcfd6058SAndrew Turner 	[ISS_DATA_DFSC_EXT_L3] =  external_abort,
112dcfd6058SAndrew Turner 	[ISS_DATA_DFSC_ECC] =  external_abort,
113dcfd6058SAndrew Turner 	[ISS_DATA_DFSC_ECC_L0] =  external_abort,
114dcfd6058SAndrew Turner 	[ISS_DATA_DFSC_ECC_L1] =  external_abort,
115dcfd6058SAndrew Turner 	[ISS_DATA_DFSC_ECC_L2] =  external_abort,
116dcfd6058SAndrew Turner 	[ISS_DATA_DFSC_ECC_L3] =  external_abort,
117acd6f4beSAndrew Turner };
118acd6f4beSAndrew Turner 
119e5acd89cSAndrew Turner static __inline void
call_trapsignal(struct thread * td,int sig,int code,void * addr,int trapno)120d7d14db9SJohn Baldwin call_trapsignal(struct thread *td, int sig, int code, void *addr, int trapno)
121e5acd89cSAndrew Turner {
122e5acd89cSAndrew Turner 	ksiginfo_t ksi;
123e5acd89cSAndrew Turner 
124e5acd89cSAndrew Turner 	ksiginfo_init_trap(&ksi);
125e5acd89cSAndrew Turner 	ksi.ksi_signo = sig;
126cb02f6b9SAndrew Turner 	ksi.ksi_code = code;
127cb02f6b9SAndrew Turner 	ksi.ksi_addr = addr;
128d7d14db9SJohn Baldwin 	ksi.ksi_trapno = trapno;
129e5acd89cSAndrew Turner 	trapsignal(td, &ksi);
130e5acd89cSAndrew Turner }
131e5acd89cSAndrew Turner 
132e5acd89cSAndrew Turner int
cpu_fetch_syscall_args(struct thread * td)1332d88da2fSKonstantin Belousov cpu_fetch_syscall_args(struct thread *td)
134e5acd89cSAndrew Turner {
135e5acd89cSAndrew Turner 	struct proc *p;
136b1ad6a90SBrooks Davis 	syscallarg_t *ap, *dst_ap;
1372d88da2fSKonstantin Belousov 	struct syscall_args *sa;
138e5acd89cSAndrew Turner 
139e5acd89cSAndrew Turner 	p = td->td_proc;
1402d88da2fSKonstantin Belousov 	sa = &td->td_sa;
14126227084SEdward Tomasz Napierala 	ap = td->td_frame->tf_x;
14226227084SEdward Tomasz Napierala 	dst_ap = &sa->args[0];
143e5acd89cSAndrew Turner 
144e5acd89cSAndrew Turner 	sa->code = td->td_frame->tf_x[8];
145cf98bc28SDavid Chisnall 	sa->original_code = sa->code;
146e5acd89cSAndrew Turner 
14726227084SEdward Tomasz Napierala 	if (__predict_false(sa->code == SYS_syscall || sa->code == SYS___syscall)) {
148e5acd89cSAndrew Turner 		sa->code = *ap++;
14926227084SEdward Tomasz Napierala 	} else {
15026227084SEdward Tomasz Napierala 		*dst_ap++ = *ap++;
151e5acd89cSAndrew Turner 	}
152e5acd89cSAndrew Turner 
15326227084SEdward Tomasz Napierala 	if (__predict_false(sa->code >= p->p_sysent->sv_size))
15439024a89SKonstantin Belousov 		sa->callp = &nosys_sysent;
155e5acd89cSAndrew Turner 	else
156e5acd89cSAndrew Turner 		sa->callp = &p->p_sysent->sv_table[sa->code];
157e5acd89cSAndrew Turner 
15826227084SEdward Tomasz Napierala 	KASSERT(sa->callp->sy_narg <= nitems(sa->args),
15926227084SEdward Tomasz Napierala 	    ("Syscall %d takes too many arguments", sa->code));
16026227084SEdward Tomasz Napierala 
161b1ad6a90SBrooks Davis 	memcpy(dst_ap, ap, (nitems(sa->args) - 1) * sizeof(*dst_ap));
162e5acd89cSAndrew Turner 
163e5acd89cSAndrew Turner 	td->td_retval[0] = 0;
164e5acd89cSAndrew Turner 	td->td_retval[1] = 0;
165e5acd89cSAndrew Turner 
166e5acd89cSAndrew Turner 	return (0);
167e5acd89cSAndrew Turner }
168e5acd89cSAndrew Turner 
169e5acd89cSAndrew Turner #include "../../kern/subr_syscall.c"
170e5acd89cSAndrew Turner 
17195a85c12SMichal Meloun /*
17295a85c12SMichal Meloun  * Test for fault generated by given access instruction in
17395a85c12SMichal Meloun  * bus_peek_<foo> or bus_poke_<foo> bus function.
17495a85c12SMichal Meloun  */
17595a85c12SMichal Meloun extern uint32_t generic_bs_peek_1f, generic_bs_peek_2f;
17695a85c12SMichal Meloun extern uint32_t generic_bs_peek_4f, generic_bs_peek_8f;
17795a85c12SMichal Meloun extern uint32_t generic_bs_poke_1f, generic_bs_poke_2f;
17895a85c12SMichal Meloun extern uint32_t generic_bs_poke_4f, generic_bs_poke_8f;
17995a85c12SMichal Meloun 
18095a85c12SMichal Meloun static bool
test_bs_fault(void * addr)18195a85c12SMichal Meloun test_bs_fault(void *addr)
18295a85c12SMichal Meloun {
18395a85c12SMichal Meloun 	return (addr == &generic_bs_peek_1f ||
18495a85c12SMichal Meloun 	    addr == &generic_bs_peek_2f ||
18595a85c12SMichal Meloun 	    addr == &generic_bs_peek_4f ||
18695a85c12SMichal Meloun 	    addr == &generic_bs_peek_8f ||
18795a85c12SMichal Meloun 	    addr == &generic_bs_poke_1f ||
18895a85c12SMichal Meloun 	    addr == &generic_bs_poke_2f ||
18995a85c12SMichal Meloun 	    addr == &generic_bs_poke_4f ||
19095a85c12SMichal Meloun 	    addr == &generic_bs_poke_8f);
19195a85c12SMichal Meloun }
19295a85c12SMichal Meloun 
193e5acd89cSAndrew Turner static void
svc_handler(struct thread * td,struct trapframe * frame)194d7635c7aSAndrew Turner svc_handler(struct thread *td, struct trapframe *frame)
195e5acd89cSAndrew Turner {
196e5acd89cSAndrew Turner 
19752a680fbSAndrew Turner 	if ((frame->tf_esr & ESR_ELx_ISS_MASK) == 0) {
198c18ca749SJohn Baldwin 		syscallenter(td);
199c18ca749SJohn Baldwin 		syscallret(td);
20052a680fbSAndrew Turner 	} else {
201d7d14db9SJohn Baldwin 		call_trapsignal(td, SIGILL, ILL_ILLOPN, (void *)frame->tf_elr,
202d7d14db9SJohn Baldwin 		    ESR_ELx_EXCEPTION(frame->tf_esr));
20352a680fbSAndrew Turner 		userret(td, frame);
20452a680fbSAndrew Turner 	}
205e5acd89cSAndrew Turner }
206e5acd89cSAndrew Turner 
207e5acd89cSAndrew Turner static void
align_abort(struct thread * td,struct trapframe * frame,uint64_t esr,uint64_t far,int lower)208c7bb1909SJustin Hibbits align_abort(struct thread *td, struct trapframe *frame, uint64_t esr,
209c7bb1909SJustin Hibbits     uint64_t far, int lower)
210c7bb1909SJustin Hibbits {
211a7f1b0caSAndrew Turner 	if (!lower) {
212a7f1b0caSAndrew Turner 		print_registers(frame);
2137ec86b66SAndrew Turner 		print_gp_register("far", far);
214e5c7aa5cSChristos Margiolis 		printf(" esr: 0x%.16lx\n", esr);
215c7bb1909SJustin Hibbits 		panic("Misaligned access from kernel space!");
216a7f1b0caSAndrew Turner 	}
217c7bb1909SJustin Hibbits 
218d7d14db9SJohn Baldwin 	call_trapsignal(td, SIGBUS, BUS_ADRALN, (void *)frame->tf_elr,
219d7d14db9SJohn Baldwin 	    ESR_ELx_EXCEPTION(frame->tf_esr));
220c7bb1909SJustin Hibbits 	userret(td, frame);
221c7bb1909SJustin Hibbits }
222c7bb1909SJustin Hibbits 
22395a85c12SMichal Meloun 
22495a85c12SMichal Meloun static void
external_abort(struct thread * td,struct trapframe * frame,uint64_t esr,uint64_t far,int lower)22595a85c12SMichal Meloun external_abort(struct thread *td, struct trapframe *frame, uint64_t esr,
22695a85c12SMichal Meloun     uint64_t far, int lower)
22795a85c12SMichal Meloun {
228a6945010SAndrew Turner 	if (lower) {
229a6945010SAndrew Turner 		call_trapsignal(td, SIGBUS, BUS_OBJERR, (void *)far,
230a6945010SAndrew Turner 		    ESR_ELx_EXCEPTION(frame->tf_esr));
231a6945010SAndrew Turner 		userret(td, frame);
232a6945010SAndrew Turner 		return;
233a6945010SAndrew Turner 	}
23495a85c12SMichal Meloun 
23595a85c12SMichal Meloun 	/*
23695a85c12SMichal Meloun 	 * Try to handle synchronous external aborts caused by
23795a85c12SMichal Meloun 	 * bus_space_peek() and/or bus_space_poke() functions.
23895a85c12SMichal Meloun 	 */
239a6945010SAndrew Turner 	if (test_bs_fault((void *)frame->tf_elr)) {
24095a85c12SMichal Meloun 		frame->tf_elr = (uint64_t)generic_bs_fault;
24195a85c12SMichal Meloun 		return;
24295a85c12SMichal Meloun 	}
24395a85c12SMichal Meloun 
24495a85c12SMichal Meloun 	print_registers(frame);
2457ec86b66SAndrew Turner 	print_gp_register("far", far);
246a6945010SAndrew Turner 	panic("Unhandled external data abort");
24795a85c12SMichal Meloun }
24895a85c12SMichal Meloun 
24903bf40c5SMark Johnston /*
25003bf40c5SMark Johnston  * It is unsafe to access the stack canary value stored in "td" until
25103bf40c5SMark Johnston  * kernel map translation faults are handled, see the pmap_klookup() call below.
25203bf40c5SMark Johnston  * Thus, stack-smashing detection with per-thread canaries must be disabled in
25303bf40c5SMark Johnston  * this function.
25403bf40c5SMark Johnston  */
25503bf40c5SMark Johnston static void NO_PERTHREAD_SSP
data_abort(struct thread * td,struct trapframe * frame,uint64_t esr,uint64_t far,int lower)256d7635c7aSAndrew Turner data_abort(struct thread *td, struct trapframe *frame, uint64_t esr,
257acd6f4beSAndrew Turner     uint64_t far, int lower)
258e5acd89cSAndrew Turner {
259e5acd89cSAndrew Turner 	struct vm_map *map;
260e5acd89cSAndrew Turner 	struct pcb *pcb;
261e5acd89cSAndrew Turner 	vm_prot_t ftype;
262cb02f6b9SAndrew Turner 	int error, sig, ucode;
263c9c4d38aSAndriy Gapon #ifdef KDB
264c9c4d38aSAndriy Gapon 	bool handled;
265c9c4d38aSAndriy Gapon #endif
266e5acd89cSAndrew Turner 
2676ced3789SKonstantin Belousov 	/*
2686ced3789SKonstantin Belousov 	 * According to the ARMv8-A rev. A.g, B2.10.5 "Load-Exclusive
2696ced3789SKonstantin Belousov 	 * and Store-Exclusive instruction usage restrictions", state
2706ced3789SKonstantin Belousov 	 * of the exclusive monitors after data abort exception is unknown.
2716ced3789SKonstantin Belousov 	 */
2726ced3789SKonstantin Belousov 	clrex();
2736ced3789SKonstantin Belousov 
2748f746773SAndrew Turner #ifdef KDB
2758f746773SAndrew Turner 	if (kdb_active) {
2768f746773SAndrew Turner 		kdb_reenter();
2778f746773SAndrew Turner 		return;
2788f746773SAndrew Turner 	}
2798f746773SAndrew Turner #endif
2808f746773SAndrew Turner 
2812c10be9eSMark Johnston 	if (lower) {
2822c10be9eSMark Johnston 		map = &td->td_proc->p_vmspace->vm_map;
2832c10be9eSMark Johnston 	} else if (!ADDR_IS_CANONICAL(far)) {
284b7a78d57SAndrew Turner 		/* We received a TBI/PAC/etc. fault from the kernel */
285b7a78d57SAndrew Turner 		error = KERN_INVALID_ADDRESS;
28603d10488SKyle Evans 		pcb = td->td_pcb;
287b7a78d57SAndrew Turner 		goto bad_far;
2882c10be9eSMark Johnston 	} else if (ADDR_IS_KERNEL(far)) {
2892c10be9eSMark Johnston 		/*
2902c10be9eSMark Johnston 		 * Handle a special case: the data abort was caused by accessing
2912c10be9eSMark Johnston 		 * a thread structure while its mapping was being promoted or
2922c10be9eSMark Johnston 		 * demoted, as a consequence of the break-before-make rule.  It
2932c10be9eSMark Johnston 		 * is not safe to enable interrupts or dereference "td" before
2942c10be9eSMark Johnston 		 * this case is handled.
2952c10be9eSMark Johnston 		 *
2962c10be9eSMark Johnston 		 * In principle, if pmap_klookup() fails, there is no need to
2972c10be9eSMark Johnston 		 * call pmap_fault() below, but avoiding that call is not worth
2982c10be9eSMark Johnston 		 * the effort.
2992c10be9eSMark Johnston 		 */
3002c10be9eSMark Johnston 		if (ESR_ELx_EXCEPTION(esr) == EXCP_DATA_ABORT) {
3012c10be9eSMark Johnston 			switch (esr & ISS_DATA_DFSC_MASK) {
3022c10be9eSMark Johnston 			case ISS_DATA_DFSC_TF_L0:
3032c10be9eSMark Johnston 			case ISS_DATA_DFSC_TF_L1:
3042c10be9eSMark Johnston 			case ISS_DATA_DFSC_TF_L2:
3052c10be9eSMark Johnston 			case ISS_DATA_DFSC_TF_L3:
3062c10be9eSMark Johnston 				if (pmap_klookup(far, NULL))
3072c10be9eSMark Johnston 					return;
3082c10be9eSMark Johnston 				break;
309b7a78d57SAndrew Turner 			}
3102c10be9eSMark Johnston 		}
3112c10be9eSMark Johnston 		intr_enable();
312e5acd89cSAndrew Turner 		map = kernel_map;
3131d479540SAndrew Turner 	} else {
3142c10be9eSMark Johnston 		intr_enable();
3152c10be9eSMark Johnston 		map = &td->td_proc->p_vmspace->vm_map;
3161d479540SAndrew Turner 		if (map == NULL)
3171d479540SAndrew Turner 			map = kernel_map;
3181d479540SAndrew Turner 	}
3192c10be9eSMark Johnston 	pcb = td->td_pcb;
320e5acd89cSAndrew Turner 
32178921ae8SAndrew Turner 	/*
322ca2cae0bSMark Johnston 	 * Try to handle translation, access flag, and permission faults.
323ca2cae0bSMark Johnston 	 * Translation faults may occur as a result of the required
324ca2cae0bSMark Johnston 	 * break-before-make sequence used when promoting or demoting
325ca2cae0bSMark Johnston 	 * superpages.  Such faults must not occur while holding the pmap lock,
326ca2cae0bSMark Johnston 	 * or pmap_fault() will recurse on that lock.
32778921ae8SAndrew Turner 	 */
328ca2cae0bSMark Johnston 	if ((lower || map == kernel_map || pcb->pcb_onfault != 0) &&
329ca2cae0bSMark Johnston 	    pmap_fault(map->pmap, esr, far) == KERN_SUCCESS)
330e2b8bf0aSAndrew Turner 		return;
331e2b8bf0aSAndrew Turner 
3320731b0a9SAndrew Turner #ifdef INVARIANTS
3330731b0a9SAndrew Turner 	if (td->td_md.md_spinlock_count != 0) {
3340731b0a9SAndrew Turner 		print_registers(frame);
3350731b0a9SAndrew Turner 		print_gp_register("far", far);
336e5c7aa5cSChristos Margiolis 		printf(" esr: 0x%.16lx\n", esr);
337fa512fcdSAndrew Turner 		panic("data abort with spinlock held (spinlock count %d != 0)",
338fa512fcdSAndrew Turner 		    td->td_md.md_spinlock_count);
3390731b0a9SAndrew Turner 	}
3400731b0a9SAndrew Turner #endif
341510a3f1bSAndrew Turner 	if (td->td_critnest != 0 || WITNESS_CHECK(WARN_SLEEPOK |
342510a3f1bSAndrew Turner 	    WARN_GIANTOK, NULL, "Kernel page fault") != 0) {
343510a3f1bSAndrew Turner 		print_registers(frame);
3447ec86b66SAndrew Turner 		print_gp_register("far", far);
345e5c7aa5cSChristos Margiolis 		printf(" esr: 0x%.16lx\n", esr);
346510a3f1bSAndrew Turner 		panic("data abort in critical section or under mutex");
347510a3f1bSAndrew Turner 	}
348510a3f1bSAndrew Turner 
349acd6f4beSAndrew Turner 	switch (ESR_ELx_EXCEPTION(esr)) {
350acd6f4beSAndrew Turner 	case EXCP_INSN_ABORT:
351acd6f4beSAndrew Turner 	case EXCP_INSN_ABORT_L:
352ca2cae0bSMark Johnston 		ftype = VM_PROT_EXECUTE;
353acd6f4beSAndrew Turner 		break;
354acd6f4beSAndrew Turner 	default:
355029c1c48SAndrew Turner 		/*
356029c1c48SAndrew Turner 		 * If the exception was because of a read or cache operation
357029c1c48SAndrew Turner 		 * pass a read fault type into the vm code. Cache operations
358029c1c48SAndrew Turner 		 * need read permission but will set the WnR flag when the
359029c1c48SAndrew Turner 		 * memory is unmapped.
360029c1c48SAndrew Turner 		 */
361029c1c48SAndrew Turner 		if ((esr & ISS_DATA_WnR) == 0 || (esr & ISS_DATA_CM) != 0)
362029c1c48SAndrew Turner 			ftype = VM_PROT_READ;
363029c1c48SAndrew Turner 		else
364029c1c48SAndrew Turner 			ftype = VM_PROT_WRITE;
365acd6f4beSAndrew Turner 		break;
366acd6f4beSAndrew Turner 	}
367e5acd89cSAndrew Turner 
3681fa67124SKonstantin Belousov 	/* Fault in the page. */
369df08823dSKonstantin Belousov 	error = vm_fault_trap(map, far, ftype, VM_FAULT_NORMAL, &sig, &ucode);
370cb02f6b9SAndrew Turner 	if (error != KERN_SUCCESS) {
371e5acd89cSAndrew Turner 		if (lower) {
372d7d14db9SJohn Baldwin 			call_trapsignal(td, sig, ucode, (void *)far,
373d7d14db9SJohn Baldwin 			    ESR_ELx_EXCEPTION(esr));
374e5acd89cSAndrew Turner 		} else {
3752c10be9eSMark Johnston bad_far:
376e5acd89cSAndrew Turner 			if (td->td_intr_nesting_level == 0 &&
377e5acd89cSAndrew Turner 			    pcb->pcb_onfault != 0) {
378e5acd89cSAndrew Turner 				frame->tf_x[0] = error;
379e5acd89cSAndrew Turner 				frame->tf_elr = pcb->pcb_onfault;
380e5acd89cSAndrew Turner 				return;
381e5acd89cSAndrew Turner 			}
3821e888d78SAndrew Turner 
3831e888d78SAndrew Turner 			printf("Fatal data abort:\n");
3841e888d78SAndrew Turner 			print_registers(frame);
3857ec86b66SAndrew Turner 			print_gp_register("far", far);
386e5c7aa5cSChristos Margiolis 			printf(" esr: 0x%.16lx\n", esr);
3871e888d78SAndrew Turner 
3888f746773SAndrew Turner #ifdef KDB
389b317cfd4SJohn Baldwin 			if (debugger_on_trap) {
390c9c4d38aSAndriy Gapon 				kdb_why = KDB_WHY_TRAP;
391c9c4d38aSAndriy Gapon 				handled = kdb_trap(ESR_ELx_EXCEPTION(esr), 0,
392c9c4d38aSAndriy Gapon 				    frame);
393c9c4d38aSAndriy Gapon 				kdb_why = KDB_WHY_UNSET;
394c9c4d38aSAndriy Gapon 				if (handled)
3958f746773SAndrew Turner 					return;
396c9c4d38aSAndriy Gapon 			}
3978f746773SAndrew Turner #endif
398e5c7aa5cSChristos Margiolis 			panic("vm_fault failed: 0x%lx error %d",
399fbf75b11SBjoern A. Zeeb 			    frame->tf_elr, error);
400e5acd89cSAndrew Turner 		}
401e5acd89cSAndrew Turner 	}
402e5acd89cSAndrew Turner 
403e5acd89cSAndrew Turner 	if (lower)
404e5acd89cSAndrew Turner 		userret(td, frame);
405e5acd89cSAndrew Turner }
406e5acd89cSAndrew Turner 
407ccd285e7SEd Maste static void
print_gp_register(const char * name,uint64_t value)4087ec86b66SAndrew Turner print_gp_register(const char *name, uint64_t value)
4097ec86b66SAndrew Turner {
4107ec86b66SAndrew Turner #if defined(DDB)
4117ec86b66SAndrew Turner 	c_db_sym_t sym;
4127ec86b66SAndrew Turner 	const char *sym_name;
4137ec86b66SAndrew Turner 	db_expr_t sym_value;
4147ec86b66SAndrew Turner 	db_expr_t offset;
4157ec86b66SAndrew Turner #endif
4167ec86b66SAndrew Turner 
417e5c7aa5cSChristos Margiolis 	printf(" %s: 0x%.16lx", name, value);
4187ec86b66SAndrew Turner #if defined(DDB)
4197ec86b66SAndrew Turner 	/* If this looks like a kernel address try to find the symbol */
4207ec86b66SAndrew Turner 	if (value >= VM_MIN_KERNEL_ADDRESS) {
4217ec86b66SAndrew Turner 		sym = db_search_symbol(value, DB_STGY_ANY, &offset);
4227ec86b66SAndrew Turner 		if (sym != C_DB_SYM_NULL) {
4237ec86b66SAndrew Turner 			db_symbol_values(sym, &sym_name, &sym_value);
424e5c7aa5cSChristos Margiolis 			printf(" (%s + 0x%lx)", sym_name, offset);
4257ec86b66SAndrew Turner 		}
4267ec86b66SAndrew Turner 	}
4277ec86b66SAndrew Turner #endif
4287ec86b66SAndrew Turner 	printf("\n");
4297ec86b66SAndrew Turner }
4307ec86b66SAndrew Turner 
4317ec86b66SAndrew Turner static void
print_registers(struct trapframe * frame)432ccd285e7SEd Maste print_registers(struct trapframe *frame)
433ccd285e7SEd Maste {
4347ec86b66SAndrew Turner 	char name[4];
435ccd285e7SEd Maste 	u_int reg;
436ccd285e7SEd Maste 
4372e620e70SAndrew Turner 	for (reg = 0; reg < nitems(frame->tf_x); reg++) {
4387ec86b66SAndrew Turner 		snprintf(name, sizeof(name), "%sx%d", (reg < 10) ? " " : "",
4397ec86b66SAndrew Turner 		    reg);
4407ec86b66SAndrew Turner 		print_gp_register(name, frame->tf_x[reg]);
441ccd285e7SEd Maste 	}
442e5c7aa5cSChristos Margiolis 	printf("  sp: 0x%.16lx\n", frame->tf_sp);
4437ec86b66SAndrew Turner 	print_gp_register(" lr", frame->tf_lr);
44462cbc00dSAndrew Turner 	print_gp_register("elr", frame->tf_elr);
445e5c7aa5cSChristos Margiolis 	printf("spsr: 0x%.16lx\n", frame->tf_spsr);
446ccd285e7SEd Maste }
447ccd285e7SEd Maste 
4486e2caba7SDmitry Chagin #ifdef VFP
4496e2caba7SDmitry Chagin static void
fpe_trap(struct thread * td,void * addr,uint32_t exception)4506e2caba7SDmitry Chagin fpe_trap(struct thread *td, void *addr, uint32_t exception)
4516e2caba7SDmitry Chagin {
4526e2caba7SDmitry Chagin 	int code;
4536e2caba7SDmitry Chagin 
4546e2caba7SDmitry Chagin 	code = FPE_FLTIDO;
4556e2caba7SDmitry Chagin 	if ((exception & ISS_FP_TFV) != 0) {
4566e2caba7SDmitry Chagin 		if ((exception & ISS_FP_IOF) != 0)
4576e2caba7SDmitry Chagin 			code = FPE_FLTINV;
4586e2caba7SDmitry Chagin 		else if ((exception & ISS_FP_DZF) != 0)
4596e2caba7SDmitry Chagin 			code = FPE_FLTDIV;
4606e2caba7SDmitry Chagin 		else if ((exception & ISS_FP_OFF) != 0)
4616e2caba7SDmitry Chagin 			code = FPE_FLTOVF;
4626e2caba7SDmitry Chagin 		else if ((exception & ISS_FP_UFF) != 0)
4636e2caba7SDmitry Chagin 			code = FPE_FLTUND;
4646e2caba7SDmitry Chagin 		else if ((exception & ISS_FP_IXF) != 0)
4656e2caba7SDmitry Chagin 			code = FPE_FLTRES;
4666e2caba7SDmitry Chagin 	}
4676e2caba7SDmitry Chagin 	call_trapsignal(td, SIGFPE, code, addr, exception);
4686e2caba7SDmitry Chagin }
4696e2caba7SDmitry Chagin #endif
4706e2caba7SDmitry Chagin 
47103bf40c5SMark Johnston /*
47203bf40c5SMark Johnston  * See the comment above data_abort().
47303bf40c5SMark Johnston  */
47403bf40c5SMark Johnston void NO_PERTHREAD_SSP
do_el1h_sync(struct thread * td,struct trapframe * frame)475d7635c7aSAndrew Turner do_el1h_sync(struct thread *td, struct trapframe *frame)
476e5acd89cSAndrew Turner {
477e5acd89cSAndrew Turner 	uint32_t exception;
4780510aedcSKonstantin Belousov 	uint64_t esr, far;
479acd6f4beSAndrew Turner 	int dfsc;
480e5acd89cSAndrew Turner 
48189c52f9dSKyle Evans 	kasan_mark(frame, sizeof(*frame), sizeof(*frame), 0);
482c05d7bdaSMark Johnston 	kmsan_mark(frame, sizeof(*frame), KMSAN_STATE_INITED);
483c05d7bdaSMark Johnston 
484f4036a92SZachary Leaf 	far = frame->tf_far;
485e5acd89cSAndrew Turner 	/* Read the esr register to get the exception details */
486f17e4f07SAndrew Turner 	esr = frame->tf_esr;
487e5acd89cSAndrew Turner 	exception = ESR_ELx_EXCEPTION(esr);
488e5acd89cSAndrew Turner 
489b78ee15eSRuslan Bukin #ifdef KDTRACE_HOOKS
490b78ee15eSRuslan Bukin 	if (dtrace_trap_func != NULL && (*dtrace_trap_func)(frame, exception))
491b78ee15eSRuslan Bukin 		return;
492b78ee15eSRuslan Bukin #endif
493b78ee15eSRuslan Bukin 
49459833b08SChristos Margiolis 	CTR4(KTR_TRAP, "%s: exception=%lu, elr=0x%lx, esr=0x%lx",
49559833b08SChristos Margiolis 	    __func__, exception, frame->tf_elr, esr);
4963ad7e84eSAndrew Turner 
497874635e3SMitchell Horne 	/*
498874635e3SMitchell Horne 	 * Enable debug exceptions if we aren't already handling one. They will
499874635e3SMitchell Horne 	 * be masked again in the exception handler's epilogue.
500874635e3SMitchell Horne 	 */
501d93b3a65SAndrew Turner 	switch (exception) {
502d93b3a65SAndrew Turner 	case EXCP_BRK:
503*c802b486SAndrew Turner 	case EXCP_BRKPT_EL1:
504d93b3a65SAndrew Turner 	case EXCP_WATCHPT_EL1:
505d93b3a65SAndrew Turner 	case EXCP_SOFTSTP_EL1:
506d93b3a65SAndrew Turner 		break;
507d93b3a65SAndrew Turner 	default:
508874635e3SMitchell Horne 		dbg_enable();
509d93b3a65SAndrew Turner 		break;
510d93b3a65SAndrew Turner 	}
511874635e3SMitchell Horne 
512e5acd89cSAndrew Turner 	switch (exception) {
513e5acd89cSAndrew Turner 	case EXCP_FP_SIMD:
514e5acd89cSAndrew Turner 	case EXCP_TRAP_FP:
5156ed982a2SAndrew Turner #ifdef VFP
516d7635c7aSAndrew Turner 		if ((td->td_pcb->pcb_fpflags & PCB_FP_KERN) != 0) {
5176ed982a2SAndrew Turner 			vfp_restore_state();
5186ed982a2SAndrew Turner 		} else
5196ed982a2SAndrew Turner #endif
5206ed982a2SAndrew Turner 		{
521ccd285e7SEd Maste 			print_registers(frame);
522e5c7aa5cSChristos Margiolis 			printf(" esr: 0x%.16lx\n", esr);
523e5acd89cSAndrew Turner 			panic("VFP exception in the kernel");
5246ed982a2SAndrew Turner 		}
5256ed982a2SAndrew Turner 		break;
526d953ec32SAndrew Turner 	case EXCP_INSN_ABORT:
527e5acd89cSAndrew Turner 	case EXCP_DATA_ABORT:
528acd6f4beSAndrew Turner 		dfsc = esr & ISS_DATA_DFSC_MASK;
529acd6f4beSAndrew Turner 		if (dfsc < nitems(abort_handlers) &&
5309bf9b8b9SAndrew Turner 		    abort_handlers[dfsc] != NULL) {
531acd6f4beSAndrew Turner 			abort_handlers[dfsc](td, frame, esr, far, 0);
5329bf9b8b9SAndrew Turner 		} else {
5339bf9b8b9SAndrew Turner 			print_registers(frame);
5347ec86b66SAndrew Turner 			print_gp_register("far", far);
535e5c7aa5cSChristos Margiolis 			printf(" esr: 0x%.16lx\n", esr);
536e5c7aa5cSChristos Margiolis 			panic("Unhandled EL1 %s abort: 0x%x",
537acd6f4beSAndrew Turner 			    exception == EXCP_INSN_ABORT ? "instruction" :
538acd6f4beSAndrew Turner 			    "data", dfsc);
5399bf9b8b9SAndrew Turner 		}
540e5acd89cSAndrew Turner 		break;
541e5acd89cSAndrew Turner 	case EXCP_BRK:
542b78ee15eSRuslan Bukin #ifdef KDTRACE_HOOKS
543b78ee15eSRuslan Bukin 		if ((esr & ESR_ELx_ISS_MASK) == 0x40d && \
544b78ee15eSRuslan Bukin 		    dtrace_invop_jump_addr != 0) {
545b78ee15eSRuslan Bukin 			dtrace_invop_jump_addr(frame);
546b78ee15eSRuslan Bukin 			break;
547b78ee15eSRuslan Bukin 		}
548b78ee15eSRuslan Bukin #endif
549de14bffeSOleksandr Tymoshenko #ifdef KDB
550e9bb4ce3Smhorne 		kdb_trap(exception, 0, frame);
551de14bffeSOleksandr Tymoshenko #else
55226658510SAndrew Turner 		panic("No debugger in kernel.");
553de14bffeSOleksandr Tymoshenko #endif
554be84f91cSAndrew Turner 		break;
555*c802b486SAndrew Turner 	case EXCP_BRKPT_EL1:
556e5acd89cSAndrew Turner 	case EXCP_WATCHPT_EL1:
557e5acd89cSAndrew Turner 	case EXCP_SOFTSTP_EL1:
558e5acd89cSAndrew Turner #ifdef KDB
559e9bb4ce3Smhorne 		kdb_trap(exception, 0, frame);
560e5acd89cSAndrew Turner #else
56126658510SAndrew Turner 		panic("No debugger in kernel.");
562e5acd89cSAndrew Turner #endif
563e5acd89cSAndrew Turner 		break;
56485b7c566SAndrew Turner 	case EXCP_FPAC:
56585b7c566SAndrew Turner 		/* We can see this if the authentication on PAC fails */
56685b7c566SAndrew Turner 		print_registers(frame);
567f4036a92SZachary Leaf 		print_gp_register("far", far);
56885b7c566SAndrew Turner 		panic("FPAC kernel exception");
56985b7c566SAndrew Turner 		break;
570bcf2b954SAndrew Turner 	case EXCP_UNKNOWN:
571bcf2b954SAndrew Turner 		if (undef_insn(1, frame))
572bcf2b954SAndrew Turner 			break;
5733a0cc6feSAndrew Turner 		print_registers(frame);
5743a0cc6feSAndrew Turner 		print_gp_register("far", far);
5753a0cc6feSAndrew Turner 		panic("Undefined instruction: %08x",
576e793a55aSAndrew Turner 		    *(uint32_t *)frame->tf_elr);
5773a0cc6feSAndrew Turner 		break;
578450f731bSAndrew Turner 	case EXCP_BTI:
579450f731bSAndrew Turner 		print_registers(frame);
580450f731bSAndrew Turner 		print_gp_register("far", far);
581450f731bSAndrew Turner 		panic("Branch Target exception");
582450f731bSAndrew Turner 		break;
583e5acd89cSAndrew Turner 	default:
584ccd285e7SEd Maste 		print_registers(frame);
585f4036a92SZachary Leaf 		print_gp_register("far", far);
586e5c7aa5cSChristos Margiolis 		panic("Unknown kernel exception 0x%x esr_el1 0x%lx", exception,
587e5acd89cSAndrew Turner 		    esr);
588e5acd89cSAndrew Turner 	}
589e5acd89cSAndrew Turner }
590e5acd89cSAndrew Turner 
591e5acd89cSAndrew Turner void
do_el0_sync(struct thread * td,struct trapframe * frame)592f4036a92SZachary Leaf do_el0_sync(struct thread *td, struct trapframe *frame)
593e5acd89cSAndrew Turner {
5947023544aSAndrew Turner 	pcpu_bp_harden bp_harden;
595e5acd89cSAndrew Turner 	uint32_t exception;
596f4036a92SZachary Leaf 	uint64_t esr, far;
597acd6f4beSAndrew Turner 	int dfsc;
598e5acd89cSAndrew Turner 
599e5acd89cSAndrew Turner 	/* Check we have a sane environment when entering from userland */
600e5acd89cSAndrew Turner 	KASSERT((uintptr_t)get_pcpu() >= VM_MIN_KERNEL_ADDRESS,
601e5c7aa5cSChristos Margiolis 	    ("Invalid pcpu address from userland: %p (tpidr 0x%lx)",
602e5acd89cSAndrew Turner 	     get_pcpu(), READ_SPECIALREG(tpidr_el1)));
603e5acd89cSAndrew Turner 
60489c52f9dSKyle Evans 	kasan_mark(frame, sizeof(*frame), sizeof(*frame), 0);
605c05d7bdaSMark Johnston 	kmsan_mark(frame, sizeof(*frame), KMSAN_STATE_INITED);
606c05d7bdaSMark Johnston 
607f4036a92SZachary Leaf 	far = frame->tf_far;
608f17e4f07SAndrew Turner 	esr = frame->tf_esr;
609e5acd89cSAndrew Turner 	exception = ESR_ELx_EXCEPTION(esr);
610f2994222SAndrew Turner 	if (exception == EXCP_INSN_ABORT_L && far > VM_MAXUSER_ADDRESS) {
6117023544aSAndrew Turner 		/*
6127023544aSAndrew Turner 		 * Userspace may be trying to train the branch predictor to
6137023544aSAndrew Turner 		 * attack the kernel. If we are on a CPU affected by this
6147023544aSAndrew Turner 		 * call the handler to clear the branch predictor state.
6157023544aSAndrew Turner 		 */
6167023544aSAndrew Turner 		bp_harden = PCPU_GET(bp_harden);
6177023544aSAndrew Turner 		if (bp_harden != NULL)
6187023544aSAndrew Turner 			bp_harden();
6197023544aSAndrew Turner 	}
6200510aedcSKonstantin Belousov 	intr_enable();
621e5acd89cSAndrew Turner 
62259833b08SChristos Margiolis 	CTR4(KTR_TRAP, "%s: exception=%lu, elr=0x%lx, esr=0x%lx",
62359833b08SChristos Margiolis 	    __func__, exception, frame->tf_elr, esr);
6243ad7e84eSAndrew Turner 
625e5acd89cSAndrew Turner 	switch (exception) {
626e5acd89cSAndrew Turner 	case EXCP_FP_SIMD:
627e5acd89cSAndrew Turner #ifdef VFP
628e5acd89cSAndrew Turner 		vfp_restore_state();
629e5acd89cSAndrew Turner #else
630e5acd89cSAndrew Turner 		panic("VFP exception in userland");
631e5acd89cSAndrew Turner #endif
632e5acd89cSAndrew Turner 		break;
6336e2caba7SDmitry Chagin 	case EXCP_TRAP_FP:
6346e2caba7SDmitry Chagin #ifdef VFP
6356e2caba7SDmitry Chagin 		fpe_trap(td, (void *)frame->tf_elr, esr);
6366e2caba7SDmitry Chagin 		userret(td, frame);
6376e2caba7SDmitry Chagin #else
6386e2caba7SDmitry Chagin 		panic("VFP exception in userland");
6396e2caba7SDmitry Chagin #endif
6406e2caba7SDmitry Chagin 		break;
641ffa5bf8bSAndrew Turner 	case EXCP_SVE:
642ffa5bf8bSAndrew Turner 		call_trapsignal(td, SIGILL, ILL_ILLTRP, (void *)frame->tf_elr,
643ffa5bf8bSAndrew Turner 		    exception);
644ffa5bf8bSAndrew Turner 		userret(td, frame);
645ffa5bf8bSAndrew Turner 		break;
6467af24ff7SEd Schouten 	case EXCP_SVC32:
6477af24ff7SEd Schouten 	case EXCP_SVC64:
648d7635c7aSAndrew Turner 		svc_handler(td, frame);
649e5acd89cSAndrew Turner 		break;
650e5acd89cSAndrew Turner 	case EXCP_INSN_ABORT_L:
651e5acd89cSAndrew Turner 	case EXCP_DATA_ABORT_L:
6524cbca608SZbigniew Bodek 	case EXCP_DATA_ABORT:
653acd6f4beSAndrew Turner 		dfsc = esr & ISS_DATA_DFSC_MASK;
654acd6f4beSAndrew Turner 		if (dfsc < nitems(abort_handlers) &&
655acd6f4beSAndrew Turner 		    abort_handlers[dfsc] != NULL)
656acd6f4beSAndrew Turner 			abort_handlers[dfsc](td, frame, esr, far, 1);
657a7f1b0caSAndrew Turner 		else {
658a7f1b0caSAndrew Turner 			print_registers(frame);
6597ec86b66SAndrew Turner 			print_gp_register("far", far);
660e5c7aa5cSChristos Margiolis 			printf(" esr: 0x%.16lx\n", esr);
661e5c7aa5cSChristos Margiolis 			panic("Unhandled EL0 %s abort: 0x%x",
662acd6f4beSAndrew Turner 			    exception == EXCP_INSN_ABORT_L ? "instruction" :
663acd6f4beSAndrew Turner 			    "data", dfsc);
664a7f1b0caSAndrew Turner 		}
665e5acd89cSAndrew Turner 		break;
666ccd285e7SEd Maste 	case EXCP_UNKNOWN:
667bcf2b954SAndrew Turner 		if (!undef_insn(0, frame))
668d7d14db9SJohn Baldwin 			call_trapsignal(td, SIGILL, ILL_ILLTRP, (void *)far,
669d7d14db9SJohn Baldwin 			    exception);
670bcf2b954SAndrew Turner 		userret(td, frame);
671ccd285e7SEd Maste 		break;
67285b7c566SAndrew Turner 	case EXCP_FPAC:
67385b7c566SAndrew Turner 		call_trapsignal(td, SIGILL, ILL_ILLOPN, (void *)frame->tf_elr,
67485b7c566SAndrew Turner 		    exception);
67585b7c566SAndrew Turner 		userret(td, frame);
67685b7c566SAndrew Turner 		break;
677729ac0eeSAndrew Turner 	case EXCP_SP_ALIGN:
678d7d14db9SJohn Baldwin 		call_trapsignal(td, SIGBUS, BUS_ADRALN, (void *)frame->tf_sp,
679d7d14db9SJohn Baldwin 		    exception);
680729ac0eeSAndrew Turner 		userret(td, frame);
681729ac0eeSAndrew Turner 		break;
6828bdcc096SAndrew Turner 	case EXCP_PC_ALIGN:
683d7d14db9SJohn Baldwin 		call_trapsignal(td, SIGBUS, BUS_ADRALN, (void *)frame->tf_elr,
684d7d14db9SJohn Baldwin 		    exception);
6858bdcc096SAndrew Turner 		userret(td, frame);
6868bdcc096SAndrew Turner 		break;
68705f39d1aSAndrew Turner 	case EXCP_BRKPT_EL0:
6880987c184SAndrew Turner 	case EXCP_BRK:
68927340501SOlivier Houchard #ifdef COMPAT_FREEBSD32
69027340501SOlivier Houchard 	case EXCP_BRKPT_32:
69127340501SOlivier Houchard #endif /* COMPAT_FREEBSD32 */
692d7d14db9SJohn Baldwin 		call_trapsignal(td, SIGTRAP, TRAP_BRKPT, (void *)frame->tf_elr,
693d7d14db9SJohn Baldwin 		    exception);
6940987c184SAndrew Turner 		userret(td, frame);
6950987c184SAndrew Turner 		break;
696bd012c71SMitchell Horne 	case EXCP_WATCHPT_EL0:
697bd012c71SMitchell Horne 		call_trapsignal(td, SIGTRAP, TRAP_TRACE, (void *)far,
698bd012c71SMitchell Horne 		    exception);
699bd012c71SMitchell Horne 		userret(td, frame);
700bd012c71SMitchell Horne 		break;
70113db6962SAndrew Turner 	case EXCP_MSR:
7028e67b938SAndrew Turner 		/*
7038e67b938SAndrew Turner 		 * The CPU can raise EXCP_MSR when userspace executes an mrs
7048e67b938SAndrew Turner 		 * instruction to access a special register userspace doesn't
7058e67b938SAndrew Turner 		 * have access to.
7068e67b938SAndrew Turner 		 */
7078e67b938SAndrew Turner 		if (!undef_insn(0, frame))
7088e67b938SAndrew Turner 			call_trapsignal(td, SIGILL, ILL_PRVOPC,
7098e67b938SAndrew Turner 			    (void *)frame->tf_elr, exception);
71013db6962SAndrew Turner 		userret(td, frame);
71113db6962SAndrew Turner 		break;
71287e19994SAndrew Turner 	case EXCP_SOFTSTP_EL0:
71331cf95ceSAndrew Turner 		PROC_LOCK(td->td_proc);
71431cf95ceSAndrew Turner 		if ((td->td_dbgflags & TDB_STEP) != 0) {
71587e19994SAndrew Turner 			td->td_frame->tf_spsr &= ~PSR_SS;
71687e19994SAndrew Turner 			td->td_pcb->pcb_flags &= ~PCB_SINGLE_STEP;
717fc232b89SAndrew Turner 			WRITE_SPECIALREG(mdscr_el1,
718664640baSAndrew Turner 			    READ_SPECIALREG(mdscr_el1) & ~MDSCR_SS);
71931cf95ceSAndrew Turner 		}
72031cf95ceSAndrew Turner 		PROC_UNLOCK(td->td_proc);
72187e19994SAndrew Turner 		call_trapsignal(td, SIGTRAP, TRAP_TRACE,
722d7d14db9SJohn Baldwin 		    (void *)frame->tf_elr, exception);
72387e19994SAndrew Turner 		userret(td, frame);
72487e19994SAndrew Turner 		break;
725450f731bSAndrew Turner 	case EXCP_BTI:
726450f731bSAndrew Turner 		call_trapsignal(td, SIGILL, ILL_ILLOPC, (void *)frame->tf_elr,
727450f731bSAndrew Turner 		    exception);
728450f731bSAndrew Turner 		userret(td, frame);
729450f731bSAndrew Turner 		break;
730e5acd89cSAndrew Turner 	default:
731d7d14db9SJohn Baldwin 		call_trapsignal(td, SIGBUS, BUS_OBJERR, (void *)frame->tf_elr,
732d7d14db9SJohn Baldwin 		    exception);
733e0c6c1d1SAndrew Turner 		userret(td, frame);
734e0c6c1d1SAndrew Turner 		break;
735e5acd89cSAndrew Turner 	}
7364c247b97SAndrew Turner 
737d7635c7aSAndrew Turner 	KASSERT((td->td_pcb->pcb_fpflags & ~PCB_FP_USERMASK) == 0,
7384c247b97SAndrew Turner 	    ("Kernel VFP flags set while entering userspace"));
7396ed982a2SAndrew Turner 	KASSERT(
740d7635c7aSAndrew Turner 	    td->td_pcb->pcb_fpusaved == &td->td_pcb->pcb_fpustate,
7416ed982a2SAndrew Turner 	    ("Kernel VFP state in use when entering userspace"));
742e5acd89cSAndrew Turner }
743e5acd89cSAndrew Turner 
744dc9b99a8SAndrew Turner /*
745dc9b99a8SAndrew Turner  * TODO: We will need to handle these later when we support ARMv8.2 RAS.
746dc9b99a8SAndrew Turner  */
747e5acd89cSAndrew Turner void
do_serror(struct trapframe * frame)748dc9b99a8SAndrew Turner do_serror(struct trapframe *frame)
749e5acd89cSAndrew Turner {
750dc9b99a8SAndrew Turner 	uint64_t esr, far;
751e5acd89cSAndrew Turner 
75289c52f9dSKyle Evans 	kasan_mark(frame, sizeof(*frame), sizeof(*frame), 0);
753c05d7bdaSMark Johnston 	kmsan_mark(frame, sizeof(*frame), KMSAN_STATE_INITED);
754c05d7bdaSMark Johnston 
755f4036a92SZachary Leaf 	far = frame->tf_far;
756dc9b99a8SAndrew Turner 	esr = frame->tf_esr;
757dc9b99a8SAndrew Turner 
758dc9b99a8SAndrew Turner 	print_registers(frame);
7597ec86b66SAndrew Turner 	print_gp_register("far", far);
760e5c7aa5cSChristos Margiolis 	printf(" esr: 0x%.16lx\n", esr);
761dc9b99a8SAndrew Turner 	panic("Unhandled System Error");
762e5acd89cSAndrew Turner }
763e5acd89cSAndrew Turner 
764dc9b99a8SAndrew Turner void
unhandled_exception(struct trapframe * frame)765dc9b99a8SAndrew Turner unhandled_exception(struct trapframe *frame)
766dc9b99a8SAndrew Turner {
767dc9b99a8SAndrew Turner 	uint64_t esr, far;
768dc9b99a8SAndrew Turner 
76989c52f9dSKyle Evans 	kasan_mark(frame, sizeof(*frame), sizeof(*frame), 0);
770c05d7bdaSMark Johnston 	kmsan_mark(frame, sizeof(*frame), KMSAN_STATE_INITED);
771c05d7bdaSMark Johnston 
772f4036a92SZachary Leaf 	far = frame->tf_far;
773dc9b99a8SAndrew Turner 	esr = frame->tf_esr;
774dc9b99a8SAndrew Turner 
775dc9b99a8SAndrew Turner 	print_registers(frame);
7767ec86b66SAndrew Turner 	print_gp_register("far", far);
777e5c7aa5cSChristos Margiolis 	printf(" esr: 0x%.16lx\n", esr);
778dc9b99a8SAndrew Turner 	panic("Unhandled exception");
779dc9b99a8SAndrew Turner }
780