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 344905 2019-03-08 00:20:37Z jhb $");
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#ifdef KDB
159	bool handled;
160#endif
161
162	/*
163	 * According to the ARMv8-A rev. A.g, B2.10.5 "Load-Exclusive
164	 * and Store-Exclusive instruction usage restrictions", state
165	 * of the exclusive monitors after data abort exception is unknown.
166	 */
167	clrex();
168
169#ifdef KDB
170	if (kdb_active) {
171		kdb_reenter();
172		return;
173	}
174#endif
175
176	pcb = td->td_pcb;
177
178	/*
179	 * Special case for fuswintr and suswintr. These can't sleep so
180	 * handle them early on in the trap handler.
181	 */
182	if (__predict_false(pcb->pcb_onfault == (vm_offset_t)&fsu_intr_fault)) {
183		frame->tf_elr = pcb->pcb_onfault;
184		return;
185	}
186
187	p = td->td_proc;
188	if (lower)
189		map = &p->p_vmspace->vm_map;
190	else {
191		/* The top bit tells us which range to use */
192		if ((far >> 63) == 1)
193			map = kernel_map;
194		else
195			map = &p->p_vmspace->vm_map;
196	}
197
198	if (pmap_fault(map->pmap, esr, far) == KERN_SUCCESS)
199		return;
200
201	KASSERT(td->td_md.md_spinlock_count == 0,
202	    ("data abort with spinlock held"));
203	if (td->td_critnest != 0 || WITNESS_CHECK(WARN_SLEEPOK |
204	    WARN_GIANTOK, NULL, "Kernel page fault") != 0) {
205		print_registers(frame);
206		printf(" far: %16lx\n", far);
207		printf(" esr:         %.8lx\n", esr);
208		panic("data abort in critical section or under mutex");
209	}
210
211	va = trunc_page(far);
212	ftype = ((esr >> 6) & 1) ? VM_PROT_READ | VM_PROT_WRITE : VM_PROT_READ;
213
214	/* Fault in the page. */
215	error = vm_fault(map, va, ftype, VM_FAULT_NORMAL);
216	if (error != KERN_SUCCESS) {
217		if (lower) {
218			sig = SIGSEGV;
219			if (error == KERN_PROTECTION_FAILURE)
220				ucode = SEGV_ACCERR;
221			else
222				ucode = SEGV_MAPERR;
223			call_trapsignal(td, sig, ucode, (void *)far);
224		} else {
225			if (td->td_intr_nesting_level == 0 &&
226			    pcb->pcb_onfault != 0) {
227				frame->tf_x[0] = error;
228				frame->tf_elr = pcb->pcb_onfault;
229				return;
230			}
231
232			printf("Fatal data abort:\n");
233			print_registers(frame);
234			printf(" far: %16lx\n", far);
235			printf(" esr:         %.8lx\n", esr);
236
237#ifdef KDB
238			if (debugger_on_trap) {
239				kdb_why = KDB_WHY_TRAP;
240				handled = kdb_trap(ESR_ELx_EXCEPTION(esr), 0,
241				    frame);
242				kdb_why = KDB_WHY_UNSET;
243				if (handled)
244					return;
245			}
246#endif
247			panic("vm_fault failed: %lx", frame->tf_elr);
248		}
249	}
250
251	if (lower)
252		userret(td, frame);
253}
254
255static void
256print_registers(struct trapframe *frame)
257{
258	u_int reg;
259
260	for (reg = 0; reg < 31; reg++) {
261		printf(" %sx%d: %16lx\n", (reg < 10) ? " " : "", reg,
262		    frame->tf_x[reg]);
263	}
264	printf("  sp: %16lx\n", frame->tf_sp);
265	printf("  lr: %16lx\n", frame->tf_lr);
266	printf(" elr: %16lx\n", frame->tf_elr);
267	printf("spsr:         %8x\n", frame->tf_spsr);
268}
269
270void
271do_el1h_sync(struct thread *td, struct trapframe *frame)
272{
273	uint32_t exception;
274	uint64_t esr, far;
275
276	/* Read the esr register to get the exception details */
277	esr = frame->tf_esr;
278	exception = ESR_ELx_EXCEPTION(esr);
279
280#ifdef KDTRACE_HOOKS
281	if (dtrace_trap_func != NULL && (*dtrace_trap_func)(frame, exception))
282		return;
283#endif
284
285	CTR4(KTR_TRAP,
286	    "do_el1_sync: curthread: %p, esr %lx, elr: %lx, frame: %p", td,
287	    esr, frame->tf_elr, frame);
288
289	switch(exception) {
290	case EXCP_FP_SIMD:
291	case EXCP_TRAP_FP:
292		print_registers(frame);
293		printf(" esr:         %.8lx\n", esr);
294		panic("VFP exception in the kernel");
295	case EXCP_INSN_ABORT:
296	case EXCP_DATA_ABORT:
297		far = READ_SPECIALREG(far_el1);
298		intr_enable();
299		data_abort(td, frame, esr, far, 0);
300		break;
301	case EXCP_BRK:
302#ifdef KDTRACE_HOOKS
303		if ((esr & ESR_ELx_ISS_MASK) == 0x40d && \
304		    dtrace_invop_jump_addr != 0) {
305			dtrace_invop_jump_addr(frame);
306			break;
307		}
308#endif
309		/* FALLTHROUGH */
310	case EXCP_WATCHPT_EL1:
311	case EXCP_SOFTSTP_EL1:
312#ifdef KDB
313		kdb_trap(exception, 0, frame);
314#else
315		panic("No debugger in kernel.\n");
316#endif
317		break;
318	default:
319		print_registers(frame);
320		panic("Unknown kernel exception %x esr_el1 %lx\n", exception,
321		    esr);
322	}
323}
324
325/*
326 * The attempted execution of an instruction bit pattern that has no allocated
327 * instruction results in an exception with an unknown reason.
328 */
329static void
330el0_excp_unknown(struct trapframe *frame, uint64_t far)
331{
332	struct thread *td;
333
334	td = curthread;
335	call_trapsignal(td, SIGILL, ILL_ILLTRP, (void *)far);
336	userret(td, frame);
337}
338
339void
340do_el0_sync(struct thread *td, struct trapframe *frame)
341{
342	uint32_t exception;
343	uint64_t esr, far;
344
345	/* Check we have a sane environment when entering from userland */
346	KASSERT((uintptr_t)get_pcpu() >= VM_MIN_KERNEL_ADDRESS,
347	    ("Invalid pcpu address from userland: %p (tpidr %lx)",
348	     get_pcpu(), READ_SPECIALREG(tpidr_el1)));
349
350	esr = frame->tf_esr;
351	exception = ESR_ELx_EXCEPTION(esr);
352	switch (exception) {
353	case EXCP_UNKNOWN:
354	case EXCP_INSN_ABORT_L:
355	case EXCP_DATA_ABORT_L:
356	case EXCP_DATA_ABORT:
357		far = READ_SPECIALREG(far_el1);
358	}
359	intr_enable();
360
361	CTR4(KTR_TRAP,
362	    "do_el0_sync: curthread: %p, esr %lx, elr: %lx, frame: %p", td, esr,
363	    frame->tf_elr, frame);
364
365	switch(exception) {
366	case EXCP_FP_SIMD:
367	case EXCP_TRAP_FP:
368#ifdef VFP
369		vfp_restore_state();
370#else
371		panic("VFP exception in userland");
372#endif
373		break;
374	case EXCP_SVC:
375		svc_handler(td, frame);
376		break;
377	case EXCP_INSN_ABORT_L:
378	case EXCP_DATA_ABORT_L:
379	case EXCP_DATA_ABORT:
380		data_abort(td, frame, esr, far, 1);
381		break;
382	case EXCP_UNKNOWN:
383		el0_excp_unknown(frame, far);
384		break;
385	case EXCP_SP_ALIGN:
386		call_trapsignal(td, SIGBUS, BUS_ADRALN, (void *)frame->tf_sp);
387		userret(td, frame);
388		break;
389	case EXCP_PC_ALIGN:
390		call_trapsignal(td, SIGBUS, BUS_ADRALN, (void *)frame->tf_elr);
391		userret(td, frame);
392		break;
393	case EXCP_BRK:
394		call_trapsignal(td, SIGTRAP, TRAP_BRKPT, (void *)frame->tf_elr);
395		userret(td, frame);
396		break;
397	case EXCP_MSR:
398		call_trapsignal(td, SIGILL, ILL_PRVOPC, (void *)frame->tf_elr);
399		userret(td, frame);
400		break;
401	case EXCP_SOFTSTP_EL0:
402		td->td_frame->tf_spsr &= ~PSR_SS;
403		td->td_pcb->pcb_flags &= ~PCB_SINGLE_STEP;
404		WRITE_SPECIALREG(MDSCR_EL1,
405		    READ_SPECIALREG(MDSCR_EL1) & ~DBG_MDSCR_SS);
406		call_trapsignal(td, SIGTRAP, TRAP_TRACE,
407		    (void *)frame->tf_elr);
408		userret(td, frame);
409		break;
410	default:
411		call_trapsignal(td, SIGBUS, BUS_OBJERR, (void *)frame->tf_elr);
412		userret(td, frame);
413		break;
414	}
415}
416
417void
418do_el0_error(struct trapframe *frame)
419{
420
421	panic("ARM64TODO: do_el0_error");
422}
423
424