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