1/*-
2 * Copyright (c) 2015 Ruslan Bukin <br@bsdpad.com>
3 * All rights reserved.
4 *
5 * Portions of this software were developed by SRI International and the
6 * University of Cambridge Computer Laboratory under DARPA/AFRL contract
7 * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme.
8 *
9 * Portions of this software were developed by the University of Cambridge
10 * Computer Laboratory as part of the CTSRD Project, with support from the
11 * UK Higher Education Innovation Fund (HEIF).
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 *    notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 *    notice, this list of conditions and the following disclaimer in the
20 *    documentation and/or other materials provided with the distribution.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35#include <sys/cdefs.h>
36__FBSDID("$FreeBSD: stable/11/sys/riscv/riscv/trap.c 321343 2017-07-21 18:06:57Z kib $");
37
38#include <sys/param.h>
39#include <sys/systm.h>
40#include <sys/kernel.h>
41#include <sys/lock.h>
42#include <sys/mutex.h>
43#include <sys/pioctl.h>
44#include <sys/bus.h>
45#include <sys/proc.h>
46#include <sys/ptrace.h>
47#include <sys/syscall.h>
48#include <sys/sysent.h>
49#ifdef KDB
50#include <sys/kdb.h>
51#endif
52
53#include <vm/vm.h>
54#include <vm/pmap.h>
55#include <vm/vm_kern.h>
56#include <vm/vm_map.h>
57#include <vm/vm_param.h>
58#include <vm/vm_extern.h>
59
60#include <machine/frame.h>
61#include <machine/pcb.h>
62#include <machine/pcpu.h>
63
64#include <machine/resource.h>
65#include <machine/intr.h>
66
67#ifdef KDTRACE_HOOKS
68#include <sys/dtrace_bsd.h>
69#endif
70
71int (*dtrace_invop_jump_addr)(struct trapframe *);
72
73extern register_t fsu_intr_fault;
74
75/* Called from exception.S */
76void do_trap_supervisor(struct trapframe *);
77void do_trap_user(struct trapframe *);
78
79static __inline void
80call_trapsignal(struct thread *td, int sig, int code, void *addr)
81{
82	ksiginfo_t ksi;
83
84	ksiginfo_init_trap(&ksi);
85	ksi.ksi_signo = sig;
86	ksi.ksi_code = code;
87	ksi.ksi_addr = addr;
88	trapsignal(td, &ksi);
89}
90
91int
92cpu_fetch_syscall_args(struct thread *td)
93{
94	struct proc *p;
95	register_t *ap;
96	struct syscall_args *sa;
97	int nap;
98
99	nap = 8;
100	p = td->td_proc;
101	sa = &td->td_sa;
102	ap = &td->td_frame->tf_a[0];
103
104	sa->code = td->td_frame->tf_t[0];
105
106	if (sa->code == SYS_syscall || sa->code == SYS___syscall) {
107		sa->code = *ap++;
108		nap--;
109	}
110
111	if (p->p_sysent->sv_mask)
112		sa->code &= p->p_sysent->sv_mask;
113	if (sa->code >= p->p_sysent->sv_size)
114		sa->callp = &p->p_sysent->sv_table[0];
115	else
116		sa->callp = &p->p_sysent->sv_table[sa->code];
117
118	sa->narg = sa->callp->sy_narg;
119	memcpy(sa->args, ap, nap * sizeof(register_t));
120	if (sa->narg > nap)
121		panic("TODO: Could we have more then 8 args?");
122
123	td->td_retval[0] = 0;
124	td->td_retval[1] = 0;
125
126	return (0);
127}
128
129#include "../../kern/subr_syscall.c"
130
131static void
132dump_regs(struct trapframe *frame)
133{
134	int n;
135	int i;
136
137	n = (sizeof(frame->tf_t) / sizeof(frame->tf_t[0]));
138	for (i = 0; i < n; i++)
139		printf("t[%d] == 0x%016lx\n", i, frame->tf_t[i]);
140
141	n = (sizeof(frame->tf_s) / sizeof(frame->tf_s[0]));
142	for (i = 0; i < n; i++)
143		printf("s[%d] == 0x%016lx\n", i, frame->tf_s[i]);
144
145	n = (sizeof(frame->tf_a) / sizeof(frame->tf_a[0]));
146	for (i = 0; i < n; i++)
147		printf("a[%d] == 0x%016lx\n", i, frame->tf_a[i]);
148
149	printf("sepc == 0x%016lx\n", frame->tf_sepc);
150	printf("sstatus == 0x%016lx\n", frame->tf_sstatus);
151}
152
153static void
154svc_handler(struct trapframe *frame)
155{
156	struct thread *td;
157	int error;
158
159	td = curthread;
160	td->td_frame = frame;
161
162	error = syscallenter(td);
163	syscallret(td, error);
164}
165
166static void
167data_abort(struct trapframe *frame, int lower)
168{
169	struct vm_map *map;
170	uint64_t sbadaddr;
171	struct thread *td;
172	struct pcb *pcb;
173	vm_prot_t ftype;
174	vm_offset_t va;
175	struct proc *p;
176	int ucode;
177	int error;
178	int sig;
179
180#ifdef KDB
181	if (kdb_active) {
182		kdb_reenter();
183		return;
184	}
185#endif
186
187	td = curthread;
188	pcb = td->td_pcb;
189
190	/*
191	 * Special case for fuswintr and suswintr. These can't sleep so
192	 * handle them early on in the trap handler.
193	 */
194	if (__predict_false(pcb->pcb_onfault == (vm_offset_t)&fsu_intr_fault)) {
195		frame->tf_sepc = pcb->pcb_onfault;
196		return;
197	}
198
199	sbadaddr = frame->tf_sbadaddr;
200
201	p = td->td_proc;
202
203	if (lower)
204		map = &td->td_proc->p_vmspace->vm_map;
205	else {
206		/* The top bit tells us which range to use */
207		if ((sbadaddr >> 63) == 1)
208			map = kernel_map;
209		else
210			map = &td->td_proc->p_vmspace->vm_map;
211	}
212
213	va = trunc_page(sbadaddr);
214
215	if (frame->tf_scause == EXCP_STORE_ACCESS_FAULT) {
216		ftype = (VM_PROT_READ | VM_PROT_WRITE);
217	} else {
218		ftype = (VM_PROT_READ);
219	}
220
221	if (map != kernel_map) {
222		/*
223		 * Keep swapout from messing with us during this
224		 *	critical time.
225		 */
226		PROC_LOCK(p);
227		++p->p_lock;
228		PROC_UNLOCK(p);
229
230		/* Fault in the user page: */
231		error = vm_fault(map, va, ftype, VM_FAULT_NORMAL);
232
233		PROC_LOCK(p);
234		--p->p_lock;
235		PROC_UNLOCK(p);
236	} else {
237		/*
238		 * Don't have to worry about process locking or stacks in the
239		 * kernel.
240		 */
241		error = vm_fault(map, va, ftype, VM_FAULT_NORMAL);
242	}
243
244	if (error != KERN_SUCCESS) {
245		if (lower) {
246			sig = SIGSEGV;
247			if (error == KERN_PROTECTION_FAILURE)
248				ucode = SEGV_ACCERR;
249			else
250				ucode = SEGV_MAPERR;
251			call_trapsignal(td, sig, ucode, (void *)sbadaddr);
252		} else {
253			if (td->td_intr_nesting_level == 0 &&
254			    pcb->pcb_onfault != 0) {
255				frame->tf_a[0] = error;
256				frame->tf_sepc = pcb->pcb_onfault;
257				return;
258			}
259			dump_regs(frame);
260			panic("vm_fault failed: %lx, va 0x%016lx",
261				frame->tf_sepc, sbadaddr);
262		}
263	}
264
265	if (lower)
266		userret(td, frame);
267}
268
269void
270do_trap_supervisor(struct trapframe *frame)
271{
272	uint64_t exception;
273
274	exception = (frame->tf_scause & EXCP_MASK);
275	if (frame->tf_scause & EXCP_INTR) {
276		/* Interrupt */
277		riscv_cpu_intr(frame);
278		return;
279	}
280
281#ifdef KDTRACE_HOOKS
282	if (dtrace_trap_func != NULL && (*dtrace_trap_func)(frame, exception))
283		return;
284#endif
285
286	CTR3(KTR_TRAP, "do_trap_supervisor: curthread: %p, sepc: %lx, frame: %p",
287	    curthread, frame->tf_sepc, frame);
288
289	switch(exception) {
290	case EXCP_LOAD_ACCESS_FAULT:
291	case EXCP_STORE_ACCESS_FAULT:
292	case EXCP_INSTR_ACCESS_FAULT:
293		data_abort(frame, 0);
294		break;
295	case EXCP_INSTR_BREAKPOINT:
296#ifdef KDTRACE_HOOKS
297		if (dtrace_invop_jump_addr != 0) {
298			dtrace_invop_jump_addr(frame);
299			break;
300		}
301#endif
302#ifdef KDB
303		kdb_trap(exception, 0, frame);
304#else
305		dump_regs(frame);
306		panic("No debugger in kernel.\n");
307#endif
308		break;
309	case EXCP_INSTR_ILLEGAL:
310		dump_regs(frame);
311		panic("Illegal instruction at 0x%016lx\n", frame->tf_sepc);
312		break;
313	default:
314		dump_regs(frame);
315		panic("Unknown kernel exception %x badaddr %lx\n",
316			exception, frame->tf_sbadaddr);
317	}
318}
319
320void
321do_trap_user(struct trapframe *frame)
322{
323	uint64_t exception;
324	struct thread *td;
325
326	td = curthread;
327	td->td_frame = frame;
328
329	exception = (frame->tf_scause & EXCP_MASK);
330	if (frame->tf_scause & EXCP_INTR) {
331		/* Interrupt */
332		riscv_cpu_intr(frame);
333		return;
334	}
335
336	CTR3(KTR_TRAP, "do_trap_user: curthread: %p, sepc: %lx, frame: %p",
337	    curthread, frame->tf_sepc, frame);
338
339	switch(exception) {
340	case EXCP_LOAD_ACCESS_FAULT:
341	case EXCP_STORE_ACCESS_FAULT:
342	case EXCP_INSTR_ACCESS_FAULT:
343		data_abort(frame, 1);
344		break;
345	case EXCP_UMODE_ENV_CALL:
346		frame->tf_sepc += 4;	/* Next instruction */
347		svc_handler(frame);
348		break;
349	case EXCP_INSTR_ILLEGAL:
350		call_trapsignal(td, SIGILL, ILL_ILLTRP, (void *)frame->tf_sepc);
351		userret(td, frame);
352		break;
353	case EXCP_INSTR_BREAKPOINT:
354		call_trapsignal(td, SIGTRAP, TRAP_BRKPT, (void *)frame->tf_sepc);
355		userret(td, frame);
356		break;
357	default:
358		dump_regs(frame);
359		panic("Unknown userland exception %x badaddr %lx\n",
360			exception, frame->tf_sbadaddr);
361	}
362}
363