trap.c revision 288671
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: head/sys/arm64/arm64/trap.c 288671 2015-10-04 21:16:45Z andrew $");
30
31#include <sys/param.h>
32#include <sys/systm.h>
33#include <sys/kernel.h>
34#include <sys/lock.h>
35#include <sys/mutex.h>
36#include <sys/pioctl.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/pcb.h>
54#include <machine/pcpu.h>
55#include <machine/vmparam.h>
56
57#ifdef KDTRACE_HOOKS
58#include <sys/dtrace_bsd.h>
59#endif
60
61#ifdef VFP
62#include <machine/vfp.h>
63#endif
64
65#ifdef KDB
66#include <machine/db_machdep.h>
67#endif
68
69#ifdef DDB
70#include <ddb/db_output.h>
71#endif
72
73extern register_t fsu_intr_fault;
74
75/* Called from exception.S */
76void do_el1h_sync(struct trapframe *);
77void do_el0_sync(struct trapframe *);
78void do_el0_error(struct trapframe *);
79static void print_registers(struct trapframe *frame);
80
81int (*dtrace_invop_jump_addr)(struct trapframe *);
82
83static __inline void
84call_trapsignal(struct thread *td, int sig, int code, void *addr)
85{
86	ksiginfo_t ksi;
87
88	ksiginfo_init_trap(&ksi);
89	ksi.ksi_signo = sig;
90	ksi.ksi_code = code;
91	ksi.ksi_addr = addr;
92	trapsignal(td, &ksi);
93}
94
95int
96cpu_fetch_syscall_args(struct thread *td, struct syscall_args *sa)
97{
98	struct proc *p;
99	register_t *ap;
100	int nap;
101
102	nap = 8;
103	p = td->td_proc;
104	ap = td->td_frame->tf_x;
105
106	sa->code = td->td_frame->tf_x[8];
107
108	if (sa->code == SYS_syscall || sa->code == SYS___syscall) {
109		sa->code = *ap++;
110		nap--;
111	}
112
113	if (p->p_sysent->sv_mask)
114		sa->code &= p->p_sysent->sv_mask;
115	if (sa->code >= p->p_sysent->sv_size)
116		sa->callp = &p->p_sysent->sv_table[0];
117	else
118		sa->callp = &p->p_sysent->sv_table[sa->code];
119
120	sa->narg = sa->callp->sy_narg;
121	memcpy(sa->args, ap, nap * sizeof(register_t));
122	if (sa->narg > nap)
123		panic("ARM64TODO: Could we have more than 8 args?");
124
125	td->td_retval[0] = 0;
126	td->td_retval[1] = 0;
127
128	return (0);
129}
130
131#include "../../kern/subr_syscall.c"
132
133static void
134svc_handler(struct trapframe *frame)
135{
136	struct syscall_args sa;
137	struct thread *td;
138	int error;
139
140	td = curthread;
141	td->td_frame = frame;
142
143	error = syscallenter(td, &sa);
144	syscallret(td, error, &sa);
145}
146
147static void
148data_abort(struct trapframe *frame, uint64_t esr, uint64_t far, int lower)
149{
150	struct vm_map *map;
151	struct thread *td;
152	struct proc *p;
153	struct pcb *pcb;
154	vm_prot_t ftype;
155	vm_offset_t va;
156	int error, sig, ucode;
157
158	/*
159	 * According to the ARMv8-A rev. A.g, B2.10.5 "Load-Exclusive
160	 * and Store-Exclusive instruction usage restrictions", state
161	 * of the exclusive monitors after data abort exception is unknown.
162	 */
163	clrex();
164
165#ifdef KDB
166	if (kdb_active) {
167		kdb_reenter();
168		return;
169	}
170#endif
171
172	td = curthread;
173	pcb = td->td_pcb;
174
175	/*
176	 * Special case for fuswintr and suswintr. These can't sleep so
177	 * handle them early on in the trap handler.
178	 */
179	if (__predict_false(pcb->pcb_onfault == (vm_offset_t)&fsu_intr_fault)) {
180		frame->tf_elr = pcb->pcb_onfault;
181		return;
182	}
183
184	KASSERT(td->td_md.md_spinlock_count == 0,
185	    ("data abort with spinlock held"));
186	if (td->td_critnest != 0 || WITNESS_CHECK(WARN_SLEEPOK |
187	    WARN_GIANTOK, NULL, "Kernel page fault") != 0) {
188		print_registers(frame);
189		panic("data abort in critical section or under mutex");
190	}
191
192	p = td->td_proc;
193	if (lower)
194		map = &p->p_vmspace->vm_map;
195	else {
196		/* The top bit tells us which range to use */
197		if ((far >> 63) == 1)
198			map = kernel_map;
199		else
200			map = &p->p_vmspace->vm_map;
201	}
202
203	va = trunc_page(far);
204	ftype = ((esr >> 6) & 1) ? VM_PROT_READ | VM_PROT_WRITE : VM_PROT_READ;
205
206	/* Fault in the page. */
207	error = vm_fault(map, va, ftype, VM_FAULT_NORMAL);
208	if (error != KERN_SUCCESS) {
209		if (lower) {
210			sig = SIGSEGV;
211			if (error == KERN_PROTECTION_FAILURE)
212				ucode = SEGV_ACCERR;
213			else
214				ucode = SEGV_MAPERR;
215			call_trapsignal(td, sig, ucode, (void *)far);
216		} else {
217			if (td->td_intr_nesting_level == 0 &&
218			    pcb->pcb_onfault != 0) {
219				frame->tf_x[0] = error;
220				frame->tf_elr = pcb->pcb_onfault;
221				return;
222			}
223#ifdef KDB
224			if (debugger_on_panic || kdb_active)
225				if (kdb_trap(ESR_ELx_EXCEPTION(esr), 0, frame))
226					return;
227#endif
228			panic("vm_fault failed: %lx", frame->tf_elr);
229		}
230	}
231
232	if (lower)
233		userret(td, frame);
234}
235
236static void
237print_registers(struct trapframe *frame)
238{
239	u_int reg;
240
241	for (reg = 0; reg < 31; reg++) {
242		printf(" %sx%d: %16lx\n", (reg < 10) ? " " : "", reg,
243		    frame->tf_x[reg]);
244	}
245	printf("  sp: %16lx\n", frame->tf_sp);
246	printf("  lr: %16lx\n", frame->tf_lr);
247	printf(" elr: %16lx\n", frame->tf_elr);
248	printf("spsr: %16lx\n", frame->tf_spsr);
249}
250
251void
252do_el1h_sync(struct trapframe *frame)
253{
254	uint32_t exception;
255	uint64_t esr, far;
256
257	/* Read the esr register to get the exception details */
258	esr = READ_SPECIALREG(esr_el1);
259	exception = ESR_ELx_EXCEPTION(esr);
260
261#ifdef KDTRACE_HOOKS
262	if (dtrace_trap_func != NULL && (*dtrace_trap_func)(frame, exception))
263		return;
264#endif
265
266	/*
267	 * Sanity check we are in an exception er can handle. The IL bit
268	 * is used to indicate the instruction length, except in a few
269	 * exceptions described in the ARMv8 ARM.
270	 *
271	 * It is unclear in some cases if the bit is implementation defined.
272	 * The Foundation Model and QEMU disagree on if the IL bit should
273	 * be set when we are in a data fault from the same EL and the ISV
274	 * bit (bit 24) is also set.
275	 */
276	KASSERT((esr & ESR_ELx_IL) == ESR_ELx_IL ||
277	    (exception == EXCP_DATA_ABORT && ((esr & ISS_DATA_ISV) == 0)),
278	    ("Invalid instruction length in exception, esr %lx", esr));
279
280	CTR4(KTR_TRAP,
281	    "do_el1_sync: curthread: %p, esr %lx, elr: %lx, frame: %p",
282	    curthread, esr, frame->tf_elr, frame);
283
284	switch(exception) {
285	case EXCP_FP_SIMD:
286	case EXCP_TRAP_FP:
287		print_registers(frame);
288		panic("VFP exception in the kernel");
289	case EXCP_DATA_ABORT:
290		far = READ_SPECIALREG(far_el1);
291		intr_enable();
292		data_abort(frame, esr, far, 0);
293		break;
294	case EXCP_BRK:
295#ifdef KDTRACE_HOOKS
296		if ((esr & ESR_ELx_ISS_MASK) == 0x40d && \
297		    dtrace_invop_jump_addr != 0) {
298			dtrace_invop_jump_addr(frame);
299			break;
300		}
301#endif
302		/* FALLTHROUGH */
303	case EXCP_WATCHPT_EL1:
304	case EXCP_SOFTSTP_EL1:
305#ifdef KDB
306		kdb_trap(exception, 0, frame);
307#else
308		panic("No debugger in kernel.\n");
309#endif
310		break;
311	default:
312		print_registers(frame);
313		panic("Unknown kernel exception %x esr_el1 %lx\n", exception,
314		    esr);
315	}
316}
317
318/*
319 * The attempted execution of an instruction bit pattern that has no allocated
320 * instruction results in an exception with an unknown reason.
321 */
322static void
323el0_excp_unknown(struct trapframe *frame)
324{
325	struct thread *td;
326	uint64_t far;
327
328	td = curthread;
329	far = READ_SPECIALREG(far_el1);
330	call_trapsignal(td, SIGILL, ILL_ILLTRP, (void *)far);
331	userret(td, frame);
332}
333
334void
335do_el0_sync(struct trapframe *frame)
336{
337	struct thread *td;
338	uint32_t exception;
339	uint64_t esr, far;
340
341	/* Check we have a sane environment when entering from userland */
342	KASSERT((uintptr_t)get_pcpu() >= VM_MIN_KERNEL_ADDRESS,
343	    ("Invalid pcpu address from userland: %p (tpidr %lx)",
344	     get_pcpu(), READ_SPECIALREG(tpidr_el1)));
345
346	esr = READ_SPECIALREG(esr_el1);
347	exception = ESR_ELx_EXCEPTION(esr);
348	switch (exception) {
349	case EXCP_INSN_ABORT_L:
350	case EXCP_DATA_ABORT_L:
351	case EXCP_DATA_ABORT:
352		far = READ_SPECIALREG(far_el1);
353	}
354	intr_enable();
355
356	CTR4(KTR_TRAP,
357	    "do_el0_sync: curthread: %p, esr %lx, elr: %lx, frame: %p",
358	    curthread, esr, frame->tf_elr, frame);
359
360	switch(exception) {
361	case EXCP_FP_SIMD:
362	case EXCP_TRAP_FP:
363#ifdef VFP
364		vfp_restore_state();
365#else
366		panic("VFP exception in userland");
367#endif
368		break;
369	case EXCP_SVC:
370		svc_handler(frame);
371		break;
372	case EXCP_INSN_ABORT_L:
373	case EXCP_DATA_ABORT_L:
374	case EXCP_DATA_ABORT:
375		data_abort(frame, esr, far, 1);
376		break;
377	case EXCP_UNKNOWN:
378		el0_excp_unknown(frame);
379		break;
380	case EXCP_PC_ALIGN:
381		td = curthread;
382		call_trapsignal(td, SIGBUS, BUS_ADRALN, (void *)frame->tf_elr);
383		userret(td, frame);
384		break;
385	case EXCP_BRK:
386		td = curthread;
387		call_trapsignal(td, SIGTRAP, TRAP_BRKPT, (void *)frame->tf_elr);
388		userret(td, frame);
389		break;
390	default:
391		print_registers(frame);
392		panic("Unknown userland exception %x esr_el1 %lx\n", exception,
393		    esr);
394	}
395}
396
397void
398do_el0_error(struct trapframe *frame)
399{
400
401	panic("ARM64TODO: do_el0_error");
402}
403
404