xref: /freebsd/sys/arm64/arm64/trap.c (revision 2d88da2f)
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 
28e5acd89cSAndrew Turner #include <sys/cdefs.h>
29e5acd89cSAndrew Turner __FBSDID("$FreeBSD$");
30e5acd89cSAndrew Turner 
31e5acd89cSAndrew Turner #include <sys/param.h>
32e5acd89cSAndrew Turner #include <sys/systm.h>
33e5acd89cSAndrew Turner #include <sys/kernel.h>
34e5acd89cSAndrew Turner #include <sys/lock.h>
35e5acd89cSAndrew Turner #include <sys/mutex.h>
36e5acd89cSAndrew Turner #include <sys/pioctl.h>
37e5acd89cSAndrew Turner #include <sys/proc.h>
38e5acd89cSAndrew Turner #include <sys/ptrace.h>
39e5acd89cSAndrew Turner #include <sys/syscall.h>
40e5acd89cSAndrew Turner #include <sys/sysent.h>
41e5acd89cSAndrew Turner #ifdef KDB
42e5acd89cSAndrew Turner #include <sys/kdb.h>
43e5acd89cSAndrew Turner #endif
44e5acd89cSAndrew Turner 
45e5acd89cSAndrew Turner #include <vm/vm.h>
46e5acd89cSAndrew Turner #include <vm/pmap.h>
47e5acd89cSAndrew Turner #include <vm/vm_kern.h>
48e5acd89cSAndrew Turner #include <vm/vm_map.h>
49cb02f6b9SAndrew Turner #include <vm/vm_param.h>
50e5acd89cSAndrew Turner #include <vm/vm_extern.h>
51e5acd89cSAndrew Turner 
52e5acd89cSAndrew Turner #include <machine/frame.h>
53e5acd89cSAndrew Turner #include <machine/pcb.h>
54e5acd89cSAndrew Turner #include <machine/pcpu.h>
55e5acd89cSAndrew Turner 
56b78ee15eSRuslan Bukin #ifdef KDTRACE_HOOKS
57b78ee15eSRuslan Bukin #include <sys/dtrace_bsd.h>
58b78ee15eSRuslan Bukin #endif
59b78ee15eSRuslan Bukin 
60e5acd89cSAndrew Turner #ifdef VFP
61e5acd89cSAndrew Turner #include <machine/vfp.h>
62e5acd89cSAndrew Turner #endif
63e5acd89cSAndrew Turner 
64e5acd89cSAndrew Turner #ifdef KDB
65e5acd89cSAndrew Turner #include <machine/db_machdep.h>
66e5acd89cSAndrew Turner #endif
67e5acd89cSAndrew Turner 
68e5acd89cSAndrew Turner #ifdef DDB
69e5acd89cSAndrew Turner #include <ddb/db_output.h>
70e5acd89cSAndrew Turner #endif
71e5acd89cSAndrew Turner 
729d77aa2aSAndrew Turner extern register_t fsu_intr_fault;
73e5acd89cSAndrew Turner 
74e5acd89cSAndrew Turner /* Called from exception.S */
75d7635c7aSAndrew Turner void do_el1h_sync(struct thread *, struct trapframe *);
76d7635c7aSAndrew Turner void do_el0_sync(struct thread *, struct trapframe *);
77e5acd89cSAndrew Turner void do_el0_error(struct trapframe *);
780510aedcSKonstantin Belousov static void print_registers(struct trapframe *frame);
79e5acd89cSAndrew Turner 
80b78ee15eSRuslan Bukin int (*dtrace_invop_jump_addr)(struct trapframe *);
81b78ee15eSRuslan Bukin 
82e5acd89cSAndrew Turner static __inline void
83cb02f6b9SAndrew Turner call_trapsignal(struct thread *td, int sig, int code, void *addr)
84e5acd89cSAndrew Turner {
85e5acd89cSAndrew Turner 	ksiginfo_t ksi;
86e5acd89cSAndrew Turner 
87e5acd89cSAndrew Turner 	ksiginfo_init_trap(&ksi);
88e5acd89cSAndrew Turner 	ksi.ksi_signo = sig;
89cb02f6b9SAndrew Turner 	ksi.ksi_code = code;
90cb02f6b9SAndrew Turner 	ksi.ksi_addr = addr;
91e5acd89cSAndrew Turner 	trapsignal(td, &ksi);
92e5acd89cSAndrew Turner }
93e5acd89cSAndrew Turner 
94e5acd89cSAndrew Turner int
952d88da2fSKonstantin Belousov cpu_fetch_syscall_args(struct thread *td)
96e5acd89cSAndrew Turner {
97e5acd89cSAndrew Turner 	struct proc *p;
98e5acd89cSAndrew Turner 	register_t *ap;
992d88da2fSKonstantin Belousov 	struct syscall_args *sa;
100e5acd89cSAndrew Turner 	int nap;
101e5acd89cSAndrew Turner 
102e5acd89cSAndrew Turner 	nap = 8;
103e5acd89cSAndrew Turner 	p = td->td_proc;
104e5acd89cSAndrew Turner 	ap = td->td_frame->tf_x;
1052d88da2fSKonstantin Belousov 	sa = &td->td_sa;
106e5acd89cSAndrew Turner 
107e5acd89cSAndrew Turner 	sa->code = td->td_frame->tf_x[8];
108e5acd89cSAndrew Turner 
109e5acd89cSAndrew Turner 	if (sa->code == SYS_syscall || sa->code == SYS___syscall) {
110e5acd89cSAndrew Turner 		sa->code = *ap++;
111e5acd89cSAndrew Turner 		nap--;
112e5acd89cSAndrew Turner 	}
113e5acd89cSAndrew Turner 
114e5acd89cSAndrew Turner 	if (p->p_sysent->sv_mask)
115e5acd89cSAndrew Turner 		sa->code &= p->p_sysent->sv_mask;
116e5acd89cSAndrew Turner 	if (sa->code >= p->p_sysent->sv_size)
117e5acd89cSAndrew Turner 		sa->callp = &p->p_sysent->sv_table[0];
118e5acd89cSAndrew Turner 	else
119e5acd89cSAndrew Turner 		sa->callp = &p->p_sysent->sv_table[sa->code];
120e5acd89cSAndrew Turner 
121e5acd89cSAndrew Turner 	sa->narg = sa->callp->sy_narg;
122e5acd89cSAndrew Turner 	memcpy(sa->args, ap, nap * sizeof(register_t));
123e5acd89cSAndrew Turner 	if (sa->narg > nap)
1246bc3fe5fSPedro F. Giffuni 		panic("ARM64TODO: Could we have more than 8 args?");
125e5acd89cSAndrew Turner 
126e5acd89cSAndrew Turner 	td->td_retval[0] = 0;
127e5acd89cSAndrew Turner 	td->td_retval[1] = 0;
128e5acd89cSAndrew Turner 
129e5acd89cSAndrew Turner 	return (0);
130e5acd89cSAndrew Turner }
131e5acd89cSAndrew Turner 
132e5acd89cSAndrew Turner #include "../../kern/subr_syscall.c"
133e5acd89cSAndrew Turner 
134e5acd89cSAndrew Turner static void
135d7635c7aSAndrew Turner svc_handler(struct thread *td, struct trapframe *frame)
136e5acd89cSAndrew Turner {
137e5acd89cSAndrew Turner 	int error;
138e5acd89cSAndrew Turner 
13952a680fbSAndrew Turner 	if ((frame->tf_esr & ESR_ELx_ISS_MASK) == 0) {
1402d88da2fSKonstantin Belousov 		error = syscallenter(td);
1412d88da2fSKonstantin Belousov 		syscallret(td, error);
14252a680fbSAndrew Turner 	} else {
14352a680fbSAndrew Turner 		call_trapsignal(td, SIGILL, ILL_ILLOPN, (void *)frame->tf_elr);
14452a680fbSAndrew Turner 		userret(td, frame);
14552a680fbSAndrew Turner 	}
146e5acd89cSAndrew Turner }
147e5acd89cSAndrew Turner 
148e5acd89cSAndrew Turner static void
149d7635c7aSAndrew Turner data_abort(struct thread *td, struct trapframe *frame, uint64_t esr,
150d7635c7aSAndrew Turner     uint64_t far, int lower)
151e5acd89cSAndrew Turner {
152e5acd89cSAndrew Turner 	struct vm_map *map;
153e5acd89cSAndrew Turner 	struct proc *p;
154e5acd89cSAndrew Turner 	struct pcb *pcb;
155e5acd89cSAndrew Turner 	vm_prot_t ftype;
156e5acd89cSAndrew Turner 	vm_offset_t va;
157cb02f6b9SAndrew Turner 	int error, sig, ucode;
158e5acd89cSAndrew Turner 
1596ced3789SKonstantin Belousov 	/*
1606ced3789SKonstantin Belousov 	 * According to the ARMv8-A rev. A.g, B2.10.5 "Load-Exclusive
1616ced3789SKonstantin Belousov 	 * and Store-Exclusive instruction usage restrictions", state
1626ced3789SKonstantin Belousov 	 * of the exclusive monitors after data abort exception is unknown.
1636ced3789SKonstantin Belousov 	 */
1646ced3789SKonstantin Belousov 	clrex();
1656ced3789SKonstantin Belousov 
1668f746773SAndrew Turner #ifdef KDB
1678f746773SAndrew Turner 	if (kdb_active) {
1688f746773SAndrew Turner 		kdb_reenter();
1698f746773SAndrew Turner 		return;
1708f746773SAndrew Turner 	}
1718f746773SAndrew Turner #endif
1728f746773SAndrew Turner 
173e5acd89cSAndrew Turner 	pcb = td->td_pcb;
174e5acd89cSAndrew Turner 
175e5acd89cSAndrew Turner 	/*
176e5acd89cSAndrew Turner 	 * Special case for fuswintr and suswintr. These can't sleep so
177e5acd89cSAndrew Turner 	 * handle them early on in the trap handler.
178e5acd89cSAndrew Turner 	 */
1799d77aa2aSAndrew Turner 	if (__predict_false(pcb->pcb_onfault == (vm_offset_t)&fsu_intr_fault)) {
180e5acd89cSAndrew Turner 		frame->tf_elr = pcb->pcb_onfault;
181e5acd89cSAndrew Turner 		return;
182e5acd89cSAndrew Turner 	}
183e5acd89cSAndrew Turner 
1840510aedcSKonstantin Belousov 	p = td->td_proc;
185e5acd89cSAndrew Turner 	if (lower)
1860510aedcSKonstantin Belousov 		map = &p->p_vmspace->vm_map;
187e5acd89cSAndrew Turner 	else {
188e5acd89cSAndrew Turner 		/* The top bit tells us which range to use */
18971cb533eSAndrew Turner 		if (far >= VM_MAXUSER_ADDRESS) {
190e5acd89cSAndrew Turner 			map = kernel_map;
1911d479540SAndrew Turner 		} else {
1920510aedcSKonstantin Belousov 			map = &p->p_vmspace->vm_map;
1931d479540SAndrew Turner 			if (map == NULL)
1941d479540SAndrew Turner 				map = kernel_map;
1951d479540SAndrew Turner 		}
196e5acd89cSAndrew Turner 	}
197e5acd89cSAndrew Turner 
198510a3f1bSAndrew Turner 	if (pmap_fault(map->pmap, esr, far) == KERN_SUCCESS)
199510a3f1bSAndrew Turner 		return;
200510a3f1bSAndrew Turner 
201510a3f1bSAndrew Turner 	KASSERT(td->td_md.md_spinlock_count == 0,
202510a3f1bSAndrew Turner 	    ("data abort with spinlock held"));
203510a3f1bSAndrew Turner 	if (td->td_critnest != 0 || WITNESS_CHECK(WARN_SLEEPOK |
204510a3f1bSAndrew Turner 	    WARN_GIANTOK, NULL, "Kernel page fault") != 0) {
205510a3f1bSAndrew Turner 		print_registers(frame);
206510a3f1bSAndrew Turner 		printf(" far: %16lx\n", far);
207510a3f1bSAndrew Turner 		printf(" esr:         %.8lx\n", esr);
208510a3f1bSAndrew Turner 		panic("data abort in critical section or under mutex");
209510a3f1bSAndrew Turner 	}
210510a3f1bSAndrew Turner 
211e5acd89cSAndrew Turner 	va = trunc_page(far);
212e5acd89cSAndrew Turner 	ftype = ((esr >> 6) & 1) ? VM_PROT_READ | VM_PROT_WRITE : VM_PROT_READ;
213e5acd89cSAndrew Turner 
2141fa67124SKonstantin Belousov 	/* Fault in the page. */
215e5acd89cSAndrew Turner 	error = vm_fault(map, va, ftype, VM_FAULT_NORMAL);
216cb02f6b9SAndrew Turner 	if (error != KERN_SUCCESS) {
217e5acd89cSAndrew Turner 		if (lower) {
218e5acd89cSAndrew Turner 			sig = SIGSEGV;
219cb02f6b9SAndrew Turner 			if (error == KERN_PROTECTION_FAILURE)
220cb02f6b9SAndrew Turner 				ucode = SEGV_ACCERR;
221cb02f6b9SAndrew Turner 			else
222cb02f6b9SAndrew Turner 				ucode = SEGV_MAPERR;
223cb02f6b9SAndrew Turner 			call_trapsignal(td, sig, ucode, (void *)far);
224e5acd89cSAndrew Turner 		} else {
225e5acd89cSAndrew Turner 			if (td->td_intr_nesting_level == 0 &&
226e5acd89cSAndrew Turner 			    pcb->pcb_onfault != 0) {
227e5acd89cSAndrew Turner 				frame->tf_x[0] = error;
228e5acd89cSAndrew Turner 				frame->tf_elr = pcb->pcb_onfault;
229e5acd89cSAndrew Turner 				return;
230e5acd89cSAndrew Turner 			}
2311e888d78SAndrew Turner 
2321e888d78SAndrew Turner 			printf("Fatal data abort:\n");
2331e888d78SAndrew Turner 			print_registers(frame);
2341e888d78SAndrew Turner 			printf(" far: %16lx\n", far);
2351e888d78SAndrew Turner 			printf(" esr:         %.8lx\n", esr);
2361e888d78SAndrew Turner 
2378f746773SAndrew Turner #ifdef KDB
2388f746773SAndrew Turner 			if (debugger_on_panic || kdb_active)
2398f746773SAndrew Turner 				if (kdb_trap(ESR_ELx_EXCEPTION(esr), 0, frame))
2408f746773SAndrew Turner 					return;
2418f746773SAndrew Turner #endif
242e5acd89cSAndrew Turner 			panic("vm_fault failed: %lx", frame->tf_elr);
243e5acd89cSAndrew Turner 		}
244e5acd89cSAndrew Turner 	}
245e5acd89cSAndrew Turner 
246e5acd89cSAndrew Turner 	if (lower)
247e5acd89cSAndrew Turner 		userret(td, frame);
248e5acd89cSAndrew Turner }
249e5acd89cSAndrew Turner 
250ccd285e7SEd Maste static void
251ccd285e7SEd Maste print_registers(struct trapframe *frame)
252ccd285e7SEd Maste {
253ccd285e7SEd Maste 	u_int reg;
254ccd285e7SEd Maste 
2552e620e70SAndrew Turner 	for (reg = 0; reg < nitems(frame->tf_x); reg++) {
256ccd285e7SEd Maste 		printf(" %sx%d: %16lx\n", (reg < 10) ? " " : "", reg,
257ccd285e7SEd Maste 		    frame->tf_x[reg]);
258ccd285e7SEd Maste 	}
259ccd285e7SEd Maste 	printf("  sp: %16lx\n", frame->tf_sp);
260ccd285e7SEd Maste 	printf("  lr: %16lx\n", frame->tf_lr);
261ccd285e7SEd Maste 	printf(" elr: %16lx\n", frame->tf_elr);
262f17e4f07SAndrew Turner 	printf("spsr:         %8x\n", frame->tf_spsr);
263ccd285e7SEd Maste }
264ccd285e7SEd Maste 
265e5acd89cSAndrew Turner void
266d7635c7aSAndrew Turner do_el1h_sync(struct thread *td, struct trapframe *frame)
267e5acd89cSAndrew Turner {
268e5acd89cSAndrew Turner 	uint32_t exception;
2690510aedcSKonstantin Belousov 	uint64_t esr, far;
270e5acd89cSAndrew Turner 
271e5acd89cSAndrew Turner 	/* Read the esr register to get the exception details */
272f17e4f07SAndrew Turner 	esr = frame->tf_esr;
273e5acd89cSAndrew Turner 	exception = ESR_ELx_EXCEPTION(esr);
274e5acd89cSAndrew Turner 
275b78ee15eSRuslan Bukin #ifdef KDTRACE_HOOKS
276b78ee15eSRuslan Bukin 	if (dtrace_trap_func != NULL && (*dtrace_trap_func)(frame, exception))
277b78ee15eSRuslan Bukin 		return;
278b78ee15eSRuslan Bukin #endif
279b78ee15eSRuslan Bukin 
2803ad7e84eSAndrew Turner 	CTR4(KTR_TRAP,
281d7635c7aSAndrew Turner 	    "do_el1_sync: curthread: %p, esr %lx, elr: %lx, frame: %p", td,
282d7635c7aSAndrew Turner 	    esr, frame->tf_elr, frame);
2833ad7e84eSAndrew Turner 
284e5acd89cSAndrew Turner 	switch(exception) {
285e5acd89cSAndrew Turner 	case EXCP_FP_SIMD:
286e5acd89cSAndrew Turner 	case EXCP_TRAP_FP:
2876ed982a2SAndrew Turner #ifdef VFP
288d7635c7aSAndrew Turner 		if ((td->td_pcb->pcb_fpflags & PCB_FP_KERN) != 0) {
2896ed982a2SAndrew Turner 			vfp_restore_state();
2906ed982a2SAndrew Turner 		} else
2916ed982a2SAndrew Turner #endif
2926ed982a2SAndrew Turner 		{
293ccd285e7SEd Maste 			print_registers(frame);
2941e888d78SAndrew Turner 			printf(" esr:         %.8lx\n", esr);
295e5acd89cSAndrew Turner 			panic("VFP exception in the kernel");
2966ed982a2SAndrew Turner 		}
2976ed982a2SAndrew Turner 		break;
298d953ec32SAndrew Turner 	case EXCP_INSN_ABORT:
299e5acd89cSAndrew Turner 	case EXCP_DATA_ABORT:
3000510aedcSKonstantin Belousov 		far = READ_SPECIALREG(far_el1);
3010510aedcSKonstantin Belousov 		intr_enable();
302d7635c7aSAndrew Turner 		data_abort(td, frame, esr, far, 0);
303e5acd89cSAndrew Turner 		break;
304e5acd89cSAndrew Turner 	case EXCP_BRK:
305b78ee15eSRuslan Bukin #ifdef KDTRACE_HOOKS
306b78ee15eSRuslan Bukin 		if ((esr & ESR_ELx_ISS_MASK) == 0x40d && \
307b78ee15eSRuslan Bukin 		    dtrace_invop_jump_addr != 0) {
308b78ee15eSRuslan Bukin 			dtrace_invop_jump_addr(frame);
309b78ee15eSRuslan Bukin 			break;
310b78ee15eSRuslan Bukin 		}
311b78ee15eSRuslan Bukin #endif
3128f746773SAndrew Turner 		/* FALLTHROUGH */
313e5acd89cSAndrew Turner 	case EXCP_WATCHPT_EL1:
314e5acd89cSAndrew Turner 	case EXCP_SOFTSTP_EL1:
315e5acd89cSAndrew Turner #ifdef KDB
316e5acd89cSAndrew Turner 		kdb_trap(exception, 0, frame);
317e5acd89cSAndrew Turner #else
318e5acd89cSAndrew Turner 		panic("No debugger in kernel.\n");
319e5acd89cSAndrew Turner #endif
320e5acd89cSAndrew Turner 		break;
321e5acd89cSAndrew Turner 	default:
322ccd285e7SEd Maste 		print_registers(frame);
323e5acd89cSAndrew Turner 		panic("Unknown kernel exception %x esr_el1 %lx\n", exception,
324e5acd89cSAndrew Turner 		    esr);
325e5acd89cSAndrew Turner 	}
326e5acd89cSAndrew Turner }
327e5acd89cSAndrew Turner 
328ccd285e7SEd Maste /*
3295a060174SEd Maste  * The attempted execution of an instruction bit pattern that has no allocated
3308d5bb774SEd Maste  * instruction results in an exception with an unknown reason.
331ccd285e7SEd Maste  */
332ccd285e7SEd Maste static void
333add8a9c2SAndrew Turner el0_excp_unknown(struct trapframe *frame, uint64_t far)
334ccd285e7SEd Maste {
335ccd285e7SEd Maste 	struct thread *td;
336ccd285e7SEd Maste 
337ccd285e7SEd Maste 	td = curthread;
338ccd285e7SEd Maste 	call_trapsignal(td, SIGILL, ILL_ILLTRP, (void *)far);
339ccd285e7SEd Maste 	userret(td, frame);
340ccd285e7SEd Maste }
341ccd285e7SEd Maste 
342e5acd89cSAndrew Turner void
343d7635c7aSAndrew Turner do_el0_sync(struct thread *td, struct trapframe *frame)
344e5acd89cSAndrew Turner {
345e5acd89cSAndrew Turner 	uint32_t exception;
3460510aedcSKonstantin Belousov 	uint64_t esr, far;
347e5acd89cSAndrew Turner 
348e5acd89cSAndrew Turner 	/* Check we have a sane environment when entering from userland */
349e5acd89cSAndrew Turner 	KASSERT((uintptr_t)get_pcpu() >= VM_MIN_KERNEL_ADDRESS,
350e5acd89cSAndrew Turner 	    ("Invalid pcpu address from userland: %p (tpidr %lx)",
351e5acd89cSAndrew Turner 	     get_pcpu(), READ_SPECIALREG(tpidr_el1)));
352e5acd89cSAndrew Turner 
353f17e4f07SAndrew Turner 	esr = frame->tf_esr;
354e5acd89cSAndrew Turner 	exception = ESR_ELx_EXCEPTION(esr);
3550510aedcSKonstantin Belousov 	switch (exception) {
356add8a9c2SAndrew Turner 	case EXCP_UNKNOWN:
3570510aedcSKonstantin Belousov 	case EXCP_INSN_ABORT_L:
3580510aedcSKonstantin Belousov 	case EXCP_DATA_ABORT_L:
3590510aedcSKonstantin Belousov 	case EXCP_DATA_ABORT:
3600510aedcSKonstantin Belousov 		far = READ_SPECIALREG(far_el1);
3610510aedcSKonstantin Belousov 	}
3620510aedcSKonstantin Belousov 	intr_enable();
363e5acd89cSAndrew Turner 
3643ad7e84eSAndrew Turner 	CTR4(KTR_TRAP,
365d7635c7aSAndrew Turner 	    "do_el0_sync: curthread: %p, esr %lx, elr: %lx, frame: %p", td, esr,
366d7635c7aSAndrew Turner 	    frame->tf_elr, frame);
3673ad7e84eSAndrew Turner 
368e5acd89cSAndrew Turner 	switch(exception) {
369e5acd89cSAndrew Turner 	case EXCP_FP_SIMD:
370e5acd89cSAndrew Turner 	case EXCP_TRAP_FP:
371e5acd89cSAndrew Turner #ifdef VFP
372e5acd89cSAndrew Turner 		vfp_restore_state();
373e5acd89cSAndrew Turner #else
374e5acd89cSAndrew Turner 		panic("VFP exception in userland");
375e5acd89cSAndrew Turner #endif
376e5acd89cSAndrew Turner 		break;
377e5acd89cSAndrew Turner 	case EXCP_SVC:
378d7635c7aSAndrew Turner 		svc_handler(td, frame);
379e5acd89cSAndrew Turner 		break;
380e5acd89cSAndrew Turner 	case EXCP_INSN_ABORT_L:
381e5acd89cSAndrew Turner 	case EXCP_DATA_ABORT_L:
3824cbca608SZbigniew Bodek 	case EXCP_DATA_ABORT:
383d7635c7aSAndrew Turner 		data_abort(td, frame, esr, far, 1);
384e5acd89cSAndrew Turner 		break;
385ccd285e7SEd Maste 	case EXCP_UNKNOWN:
386add8a9c2SAndrew Turner 		el0_excp_unknown(frame, far);
387ccd285e7SEd Maste 		break;
388729ac0eeSAndrew Turner 	case EXCP_SP_ALIGN:
389729ac0eeSAndrew Turner 		call_trapsignal(td, SIGBUS, BUS_ADRALN, (void *)frame->tf_sp);
390729ac0eeSAndrew Turner 		userret(td, frame);
391729ac0eeSAndrew Turner 		break;
3928bdcc096SAndrew Turner 	case EXCP_PC_ALIGN:
3938bdcc096SAndrew Turner 		call_trapsignal(td, SIGBUS, BUS_ADRALN, (void *)frame->tf_elr);
3948bdcc096SAndrew Turner 		userret(td, frame);
3958bdcc096SAndrew Turner 		break;
3960987c184SAndrew Turner 	case EXCP_BRK:
3970987c184SAndrew Turner 		call_trapsignal(td, SIGTRAP, TRAP_BRKPT, (void *)frame->tf_elr);
3980987c184SAndrew Turner 		userret(td, frame);
3990987c184SAndrew Turner 		break;
40013db6962SAndrew Turner 	case EXCP_MSR:
40113db6962SAndrew Turner 		call_trapsignal(td, SIGILL, ILL_PRVOPC, (void *)frame->tf_elr);
40213db6962SAndrew Turner 		userret(td, frame);
40313db6962SAndrew Turner 		break;
40487e19994SAndrew Turner 	case EXCP_SOFTSTP_EL0:
40587e19994SAndrew Turner 		td->td_frame->tf_spsr &= ~PSR_SS;
40687e19994SAndrew Turner 		td->td_pcb->pcb_flags &= ~PCB_SINGLE_STEP;
40787e19994SAndrew Turner 		WRITE_SPECIALREG(MDSCR_EL1,
40887e19994SAndrew Turner 		    READ_SPECIALREG(MDSCR_EL1) & ~DBG_MDSCR_SS);
40987e19994SAndrew Turner 		call_trapsignal(td, SIGTRAP, TRAP_TRACE,
41087e19994SAndrew Turner 		    (void *)frame->tf_elr);
41187e19994SAndrew Turner 		userret(td, frame);
41287e19994SAndrew Turner 		break;
413e5acd89cSAndrew Turner 	default:
414e0c6c1d1SAndrew Turner 		call_trapsignal(td, SIGBUS, BUS_OBJERR, (void *)frame->tf_elr);
415e0c6c1d1SAndrew Turner 		userret(td, frame);
416e0c6c1d1SAndrew Turner 		break;
417e5acd89cSAndrew Turner 	}
4184c247b97SAndrew Turner 
419d7635c7aSAndrew Turner 	KASSERT((td->td_pcb->pcb_fpflags & ~PCB_FP_USERMASK) == 0,
4204c247b97SAndrew Turner 	    ("Kernel VFP flags set while entering userspace"));
4216ed982a2SAndrew Turner 	KASSERT(
422d7635c7aSAndrew Turner 	    td->td_pcb->pcb_fpusaved == &td->td_pcb->pcb_fpustate,
4236ed982a2SAndrew Turner 	    ("Kernel VFP state in use when entering userspace"));
424e5acd89cSAndrew Turner }
425e5acd89cSAndrew Turner 
426e5acd89cSAndrew Turner void
427e5acd89cSAndrew Turner do_el0_error(struct trapframe *frame)
428e5acd89cSAndrew Turner {
429e5acd89cSAndrew Turner 
430c547d650SEd Maste 	panic("ARM64TODO: do_el0_error");
431e5acd89cSAndrew Turner }
432e5acd89cSAndrew Turner 
433