xref: /freebsd/sys/arm64/arm64/trap.c (revision add8a9c2)
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 */
75e5acd89cSAndrew Turner void do_el1h_sync(struct trapframe *);
76e5acd89cSAndrew Turner void do_el0_sync(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
95e5acd89cSAndrew Turner cpu_fetch_syscall_args(struct thread *td, struct syscall_args *sa)
96e5acd89cSAndrew Turner {
97e5acd89cSAndrew Turner 	struct proc *p;
98e5acd89cSAndrew Turner 	register_t *ap;
99e5acd89cSAndrew Turner 	int nap;
100e5acd89cSAndrew Turner 
101e5acd89cSAndrew Turner 	nap = 8;
102e5acd89cSAndrew Turner 	p = td->td_proc;
103e5acd89cSAndrew Turner 	ap = td->td_frame->tf_x;
104e5acd89cSAndrew Turner 
105e5acd89cSAndrew Turner 	sa->code = td->td_frame->tf_x[8];
106e5acd89cSAndrew Turner 
107e5acd89cSAndrew Turner 	if (sa->code == SYS_syscall || sa->code == SYS___syscall) {
108e5acd89cSAndrew Turner 		sa->code = *ap++;
109e5acd89cSAndrew Turner 		nap--;
110e5acd89cSAndrew Turner 	}
111e5acd89cSAndrew Turner 
112e5acd89cSAndrew Turner 	if (p->p_sysent->sv_mask)
113e5acd89cSAndrew Turner 		sa->code &= p->p_sysent->sv_mask;
114e5acd89cSAndrew Turner 	if (sa->code >= p->p_sysent->sv_size)
115e5acd89cSAndrew Turner 		sa->callp = &p->p_sysent->sv_table[0];
116e5acd89cSAndrew Turner 	else
117e5acd89cSAndrew Turner 		sa->callp = &p->p_sysent->sv_table[sa->code];
118e5acd89cSAndrew Turner 
119e5acd89cSAndrew Turner 	sa->narg = sa->callp->sy_narg;
120e5acd89cSAndrew Turner 	memcpy(sa->args, ap, nap * sizeof(register_t));
121e5acd89cSAndrew Turner 	if (sa->narg > nap)
1226bc3fe5fSPedro F. Giffuni 		panic("ARM64TODO: Could we have more than 8 args?");
123e5acd89cSAndrew Turner 
124e5acd89cSAndrew Turner 	td->td_retval[0] = 0;
125e5acd89cSAndrew Turner 	td->td_retval[1] = 0;
126e5acd89cSAndrew Turner 
127e5acd89cSAndrew Turner 	return (0);
128e5acd89cSAndrew Turner }
129e5acd89cSAndrew Turner 
130e5acd89cSAndrew Turner #include "../../kern/subr_syscall.c"
131e5acd89cSAndrew Turner 
132e5acd89cSAndrew Turner static void
133e5acd89cSAndrew Turner svc_handler(struct trapframe *frame)
134e5acd89cSAndrew Turner {
135e5acd89cSAndrew Turner 	struct syscall_args sa;
136e5acd89cSAndrew Turner 	struct thread *td;
137e5acd89cSAndrew Turner 	int error;
138e5acd89cSAndrew Turner 
139e5acd89cSAndrew Turner 	td = curthread;
140e5acd89cSAndrew Turner 
141e5acd89cSAndrew Turner 	error = syscallenter(td, &sa);
142e5acd89cSAndrew Turner 	syscallret(td, error, &sa);
143e5acd89cSAndrew Turner }
144e5acd89cSAndrew Turner 
145e5acd89cSAndrew Turner static void
1460510aedcSKonstantin Belousov data_abort(struct trapframe *frame, uint64_t esr, uint64_t far, int lower)
147e5acd89cSAndrew Turner {
148e5acd89cSAndrew Turner 	struct vm_map *map;
149e5acd89cSAndrew Turner 	struct thread *td;
150e5acd89cSAndrew Turner 	struct proc *p;
151e5acd89cSAndrew Turner 	struct pcb *pcb;
152e5acd89cSAndrew Turner 	vm_prot_t ftype;
153e5acd89cSAndrew Turner 	vm_offset_t va;
154cb02f6b9SAndrew Turner 	int error, sig, ucode;
155e5acd89cSAndrew Turner 
1566ced3789SKonstantin Belousov 	/*
1576ced3789SKonstantin Belousov 	 * According to the ARMv8-A rev. A.g, B2.10.5 "Load-Exclusive
1586ced3789SKonstantin Belousov 	 * and Store-Exclusive instruction usage restrictions", state
1596ced3789SKonstantin Belousov 	 * of the exclusive monitors after data abort exception is unknown.
1606ced3789SKonstantin Belousov 	 */
1616ced3789SKonstantin Belousov 	clrex();
1626ced3789SKonstantin Belousov 
1638f746773SAndrew Turner #ifdef KDB
1648f746773SAndrew Turner 	if (kdb_active) {
1658f746773SAndrew Turner 		kdb_reenter();
1668f746773SAndrew Turner 		return;
1678f746773SAndrew Turner 	}
1688f746773SAndrew Turner #endif
1698f746773SAndrew Turner 
170e5acd89cSAndrew Turner 	td = curthread;
171e5acd89cSAndrew Turner 	pcb = td->td_pcb;
172e5acd89cSAndrew Turner 
173e5acd89cSAndrew Turner 	/*
174e5acd89cSAndrew Turner 	 * Special case for fuswintr and suswintr. These can't sleep so
175e5acd89cSAndrew Turner 	 * handle them early on in the trap handler.
176e5acd89cSAndrew Turner 	 */
1779d77aa2aSAndrew Turner 	if (__predict_false(pcb->pcb_onfault == (vm_offset_t)&fsu_intr_fault)) {
178e5acd89cSAndrew Turner 		frame->tf_elr = pcb->pcb_onfault;
179e5acd89cSAndrew Turner 		return;
180e5acd89cSAndrew Turner 	}
181e5acd89cSAndrew Turner 
1820510aedcSKonstantin Belousov 	KASSERT(td->td_md.md_spinlock_count == 0,
1830510aedcSKonstantin Belousov 	    ("data abort with spinlock held"));
1840510aedcSKonstantin Belousov 	if (td->td_critnest != 0 || WITNESS_CHECK(WARN_SLEEPOK |
1850510aedcSKonstantin Belousov 	    WARN_GIANTOK, NULL, "Kernel page fault") != 0) {
1860510aedcSKonstantin Belousov 		print_registers(frame);
1871e888d78SAndrew Turner 		printf(" far: %16lx\n", far);
1881e888d78SAndrew Turner 		printf(" esr:         %.8lx\n", esr);
1890510aedcSKonstantin Belousov 		panic("data abort in critical section or under mutex");
1900510aedcSKonstantin Belousov 	}
191e5acd89cSAndrew Turner 
1920510aedcSKonstantin Belousov 	p = td->td_proc;
193e5acd89cSAndrew Turner 	if (lower)
1940510aedcSKonstantin Belousov 		map = &p->p_vmspace->vm_map;
195e5acd89cSAndrew Turner 	else {
196e5acd89cSAndrew Turner 		/* The top bit tells us which range to use */
197e5acd89cSAndrew Turner 		if ((far >> 63) == 1)
198e5acd89cSAndrew Turner 			map = kernel_map;
199e5acd89cSAndrew Turner 		else
2000510aedcSKonstantin Belousov 			map = &p->p_vmspace->vm_map;
201e5acd89cSAndrew Turner 	}
202e5acd89cSAndrew Turner 
203e5acd89cSAndrew Turner 	va = trunc_page(far);
204e5acd89cSAndrew Turner 	ftype = ((esr >> 6) & 1) ? VM_PROT_READ | VM_PROT_WRITE : VM_PROT_READ;
205e5acd89cSAndrew Turner 
2061fa67124SKonstantin Belousov 	/* Fault in the page. */
207e5acd89cSAndrew Turner 	error = vm_fault(map, va, ftype, VM_FAULT_NORMAL);
208cb02f6b9SAndrew Turner 	if (error != KERN_SUCCESS) {
209e5acd89cSAndrew Turner 		if (lower) {
210e5acd89cSAndrew Turner 			sig = SIGSEGV;
211cb02f6b9SAndrew Turner 			if (error == KERN_PROTECTION_FAILURE)
212cb02f6b9SAndrew Turner 				ucode = SEGV_ACCERR;
213cb02f6b9SAndrew Turner 			else
214cb02f6b9SAndrew Turner 				ucode = SEGV_MAPERR;
215cb02f6b9SAndrew Turner 			call_trapsignal(td, sig, ucode, (void *)far);
216e5acd89cSAndrew Turner 		} else {
217e5acd89cSAndrew Turner 			if (td->td_intr_nesting_level == 0 &&
218e5acd89cSAndrew Turner 			    pcb->pcb_onfault != 0) {
219e5acd89cSAndrew Turner 				frame->tf_x[0] = error;
220e5acd89cSAndrew Turner 				frame->tf_elr = pcb->pcb_onfault;
221e5acd89cSAndrew Turner 				return;
222e5acd89cSAndrew Turner 			}
2231e888d78SAndrew Turner 
2241e888d78SAndrew Turner 			printf("Fatal data abort:\n");
2251e888d78SAndrew Turner 			print_registers(frame);
2261e888d78SAndrew Turner 			printf(" far: %16lx\n", far);
2271e888d78SAndrew Turner 			printf(" esr:         %.8lx\n", esr);
2281e888d78SAndrew Turner 
2298f746773SAndrew Turner #ifdef KDB
2308f746773SAndrew Turner 			if (debugger_on_panic || kdb_active)
2318f746773SAndrew Turner 				if (kdb_trap(ESR_ELx_EXCEPTION(esr), 0, frame))
2328f746773SAndrew Turner 					return;
2338f746773SAndrew Turner #endif
234e5acd89cSAndrew Turner 			panic("vm_fault failed: %lx", frame->tf_elr);
235e5acd89cSAndrew Turner 		}
236e5acd89cSAndrew Turner 	}
237e5acd89cSAndrew Turner 
238e5acd89cSAndrew Turner 	if (lower)
239e5acd89cSAndrew Turner 		userret(td, frame);
240e5acd89cSAndrew Turner }
241e5acd89cSAndrew Turner 
242ccd285e7SEd Maste static void
243ccd285e7SEd Maste print_registers(struct trapframe *frame)
244ccd285e7SEd Maste {
245ccd285e7SEd Maste 	u_int reg;
246ccd285e7SEd Maste 
247ccd285e7SEd Maste 	for (reg = 0; reg < 31; reg++) {
248ccd285e7SEd Maste 		printf(" %sx%d: %16lx\n", (reg < 10) ? " " : "", reg,
249ccd285e7SEd Maste 		    frame->tf_x[reg]);
250ccd285e7SEd Maste 	}
251ccd285e7SEd Maste 	printf("  sp: %16lx\n", frame->tf_sp);
252ccd285e7SEd Maste 	printf("  lr: %16lx\n", frame->tf_lr);
253ccd285e7SEd Maste 	printf(" elr: %16lx\n", frame->tf_elr);
254ccd285e7SEd Maste 	printf("spsr: %16lx\n", frame->tf_spsr);
255ccd285e7SEd Maste }
256ccd285e7SEd Maste 
257e5acd89cSAndrew Turner void
258e5acd89cSAndrew Turner do_el1h_sync(struct trapframe *frame)
259e5acd89cSAndrew Turner {
260e5acd89cSAndrew Turner 	uint32_t exception;
2610510aedcSKonstantin Belousov 	uint64_t esr, far;
262e5acd89cSAndrew Turner 
263e5acd89cSAndrew Turner 	/* Read the esr register to get the exception details */
264e5acd89cSAndrew Turner 	esr = READ_SPECIALREG(esr_el1);
265e5acd89cSAndrew Turner 	exception = ESR_ELx_EXCEPTION(esr);
266e5acd89cSAndrew Turner 
267b78ee15eSRuslan Bukin #ifdef KDTRACE_HOOKS
268b78ee15eSRuslan Bukin 	if (dtrace_trap_func != NULL && (*dtrace_trap_func)(frame, exception))
269b78ee15eSRuslan Bukin 		return;
270b78ee15eSRuslan Bukin #endif
271b78ee15eSRuslan Bukin 
2723ad7e84eSAndrew Turner 	CTR4(KTR_TRAP,
2733ad7e84eSAndrew Turner 	    "do_el1_sync: curthread: %p, esr %lx, elr: %lx, frame: %p",
2743ad7e84eSAndrew Turner 	    curthread, esr, frame->tf_elr, frame);
2753ad7e84eSAndrew Turner 
276e5acd89cSAndrew Turner 	switch(exception) {
277e5acd89cSAndrew Turner 	case EXCP_FP_SIMD:
278e5acd89cSAndrew Turner 	case EXCP_TRAP_FP:
279ccd285e7SEd Maste 		print_registers(frame);
2801e888d78SAndrew Turner 		printf(" esr:         %.8lx\n", esr);
281e5acd89cSAndrew Turner 		panic("VFP exception in the kernel");
282e5acd89cSAndrew Turner 	case EXCP_DATA_ABORT:
2830510aedcSKonstantin Belousov 		far = READ_SPECIALREG(far_el1);
2840510aedcSKonstantin Belousov 		intr_enable();
2850510aedcSKonstantin Belousov 		data_abort(frame, esr, far, 0);
286e5acd89cSAndrew Turner 		break;
287e5acd89cSAndrew Turner 	case EXCP_BRK:
288b78ee15eSRuslan Bukin #ifdef KDTRACE_HOOKS
289b78ee15eSRuslan Bukin 		if ((esr & ESR_ELx_ISS_MASK) == 0x40d && \
290b78ee15eSRuslan Bukin 		    dtrace_invop_jump_addr != 0) {
291b78ee15eSRuslan Bukin 			dtrace_invop_jump_addr(frame);
292b78ee15eSRuslan Bukin 			break;
293b78ee15eSRuslan Bukin 		}
294b78ee15eSRuslan Bukin #endif
2958f746773SAndrew Turner 		/* FALLTHROUGH */
296e5acd89cSAndrew Turner 	case EXCP_WATCHPT_EL1:
297e5acd89cSAndrew Turner 	case EXCP_SOFTSTP_EL1:
298e5acd89cSAndrew Turner #ifdef KDB
299e5acd89cSAndrew Turner 		kdb_trap(exception, 0, frame);
300e5acd89cSAndrew Turner #else
301e5acd89cSAndrew Turner 		panic("No debugger in kernel.\n");
302e5acd89cSAndrew Turner #endif
303e5acd89cSAndrew Turner 		break;
304e5acd89cSAndrew Turner 	default:
305ccd285e7SEd Maste 		print_registers(frame);
306e5acd89cSAndrew Turner 		panic("Unknown kernel exception %x esr_el1 %lx\n", exception,
307e5acd89cSAndrew Turner 		    esr);
308e5acd89cSAndrew Turner 	}
309e5acd89cSAndrew Turner }
310e5acd89cSAndrew Turner 
311ccd285e7SEd Maste /*
3125a060174SEd Maste  * The attempted execution of an instruction bit pattern that has no allocated
3138d5bb774SEd Maste  * instruction results in an exception with an unknown reason.
314ccd285e7SEd Maste  */
315ccd285e7SEd Maste static void
316add8a9c2SAndrew Turner el0_excp_unknown(struct trapframe *frame, uint64_t far)
317ccd285e7SEd Maste {
318ccd285e7SEd Maste 	struct thread *td;
319ccd285e7SEd Maste 
320ccd285e7SEd Maste 	td = curthread;
321ccd285e7SEd Maste 	call_trapsignal(td, SIGILL, ILL_ILLTRP, (void *)far);
322ccd285e7SEd Maste 	userret(td, frame);
323ccd285e7SEd Maste }
324ccd285e7SEd Maste 
325e5acd89cSAndrew Turner void
326e5acd89cSAndrew Turner do_el0_sync(struct trapframe *frame)
327e5acd89cSAndrew Turner {
3280987c184SAndrew Turner 	struct thread *td;
329e5acd89cSAndrew Turner 	uint32_t exception;
3300510aedcSKonstantin Belousov 	uint64_t esr, far;
331e5acd89cSAndrew Turner 
332e5acd89cSAndrew Turner 	/* Check we have a sane environment when entering from userland */
333e5acd89cSAndrew Turner 	KASSERT((uintptr_t)get_pcpu() >= VM_MIN_KERNEL_ADDRESS,
334e5acd89cSAndrew Turner 	    ("Invalid pcpu address from userland: %p (tpidr %lx)",
335e5acd89cSAndrew Turner 	     get_pcpu(), READ_SPECIALREG(tpidr_el1)));
336e5acd89cSAndrew Turner 
33787e19994SAndrew Turner 	td = curthread;
33887e19994SAndrew Turner 	td->td_frame = frame;
33987e19994SAndrew Turner 
340e5acd89cSAndrew Turner 	esr = READ_SPECIALREG(esr_el1);
341e5acd89cSAndrew Turner 	exception = ESR_ELx_EXCEPTION(esr);
3420510aedcSKonstantin Belousov 	switch (exception) {
343add8a9c2SAndrew Turner 	case EXCP_UNKNOWN:
3440510aedcSKonstantin Belousov 	case EXCP_INSN_ABORT_L:
3450510aedcSKonstantin Belousov 	case EXCP_DATA_ABORT_L:
3460510aedcSKonstantin Belousov 	case EXCP_DATA_ABORT:
3470510aedcSKonstantin Belousov 		far = READ_SPECIALREG(far_el1);
3480510aedcSKonstantin Belousov 	}
3490510aedcSKonstantin Belousov 	intr_enable();
350e5acd89cSAndrew Turner 
3513ad7e84eSAndrew Turner 	CTR4(KTR_TRAP,
3523ad7e84eSAndrew Turner 	    "do_el0_sync: curthread: %p, esr %lx, elr: %lx, frame: %p",
3533ad7e84eSAndrew Turner 	    curthread, esr, frame->tf_elr, frame);
3543ad7e84eSAndrew Turner 
355e5acd89cSAndrew Turner 	switch(exception) {
356e5acd89cSAndrew Turner 	case EXCP_FP_SIMD:
357e5acd89cSAndrew Turner 	case EXCP_TRAP_FP:
358e5acd89cSAndrew Turner #ifdef VFP
359e5acd89cSAndrew Turner 		vfp_restore_state();
360e5acd89cSAndrew Turner #else
361e5acd89cSAndrew Turner 		panic("VFP exception in userland");
362e5acd89cSAndrew Turner #endif
363e5acd89cSAndrew Turner 		break;
364e5acd89cSAndrew Turner 	case EXCP_SVC:
365e5acd89cSAndrew Turner 		svc_handler(frame);
366e5acd89cSAndrew Turner 		break;
367e5acd89cSAndrew Turner 	case EXCP_INSN_ABORT_L:
368e5acd89cSAndrew Turner 	case EXCP_DATA_ABORT_L:
3694cbca608SZbigniew Bodek 	case EXCP_DATA_ABORT:
3700510aedcSKonstantin Belousov 		data_abort(frame, esr, far, 1);
371e5acd89cSAndrew Turner 		break;
372ccd285e7SEd Maste 	case EXCP_UNKNOWN:
373add8a9c2SAndrew Turner 		el0_excp_unknown(frame, far);
374ccd285e7SEd Maste 		break;
375729ac0eeSAndrew Turner 	case EXCP_SP_ALIGN:
376729ac0eeSAndrew Turner 		call_trapsignal(td, SIGBUS, BUS_ADRALN, (void *)frame->tf_sp);
377729ac0eeSAndrew Turner 		userret(td, frame);
378729ac0eeSAndrew Turner 		break;
3798bdcc096SAndrew Turner 	case EXCP_PC_ALIGN:
3808bdcc096SAndrew Turner 		call_trapsignal(td, SIGBUS, BUS_ADRALN, (void *)frame->tf_elr);
3818bdcc096SAndrew Turner 		userret(td, frame);
3828bdcc096SAndrew Turner 		break;
3830987c184SAndrew Turner 	case EXCP_BRK:
3840987c184SAndrew Turner 		call_trapsignal(td, SIGTRAP, TRAP_BRKPT, (void *)frame->tf_elr);
3850987c184SAndrew Turner 		userret(td, frame);
3860987c184SAndrew Turner 		break;
38787e19994SAndrew Turner 	case EXCP_SOFTSTP_EL0:
38887e19994SAndrew Turner 		td->td_frame->tf_spsr &= ~PSR_SS;
38987e19994SAndrew Turner 		td->td_pcb->pcb_flags &= ~PCB_SINGLE_STEP;
39087e19994SAndrew Turner 		WRITE_SPECIALREG(MDSCR_EL1,
39187e19994SAndrew Turner 		    READ_SPECIALREG(MDSCR_EL1) & ~DBG_MDSCR_SS);
39287e19994SAndrew Turner 		call_trapsignal(td, SIGTRAP, TRAP_TRACE,
39387e19994SAndrew Turner 		    (void *)frame->tf_elr);
39487e19994SAndrew Turner 		userret(td, frame);
39587e19994SAndrew Turner 		break;
396e5acd89cSAndrew Turner 	default:
397ccd285e7SEd Maste 		print_registers(frame);
398e5acd89cSAndrew Turner 		panic("Unknown userland exception %x esr_el1 %lx\n", exception,
399e5acd89cSAndrew Turner 		    esr);
400e5acd89cSAndrew Turner 	}
401e5acd89cSAndrew Turner }
402e5acd89cSAndrew Turner 
403e5acd89cSAndrew Turner void
404e5acd89cSAndrew Turner do_el0_error(struct trapframe *frame)
405e5acd89cSAndrew Turner {
406e5acd89cSAndrew Turner 
407c547d650SEd Maste 	panic("ARM64TODO: do_el0_error");
408e5acd89cSAndrew Turner }
409e5acd89cSAndrew Turner 
410