trap.c revision 300618
1295041Sbr/*-
2295041Sbr * Copyright (c) 2015 Ruslan Bukin <br@bsdpad.com>
3295041Sbr * All rights reserved.
4295041Sbr *
5295041Sbr * Portions of this software were developed by SRI International and the
6295041Sbr * University of Cambridge Computer Laboratory under DARPA/AFRL contract
7295041Sbr * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme.
8295041Sbr *
9295041Sbr * Portions of this software were developed by the University of Cambridge
10295041Sbr * Computer Laboratory as part of the CTSRD Project, with support from the
11295041Sbr * UK Higher Education Innovation Fund (HEIF).
12295041Sbr *
13295041Sbr * Redistribution and use in source and binary forms, with or without
14295041Sbr * modification, are permitted provided that the following conditions
15295041Sbr * are met:
16295041Sbr * 1. Redistributions of source code must retain the above copyright
17295041Sbr *    notice, this list of conditions and the following disclaimer.
18295041Sbr * 2. Redistributions in binary form must reproduce the above copyright
19295041Sbr *    notice, this list of conditions and the following disclaimer in the
20295041Sbr *    documentation and/or other materials provided with the distribution.
21295041Sbr *
22295041Sbr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23295041Sbr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24295041Sbr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25295041Sbr * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26295041Sbr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27295041Sbr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28295041Sbr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29295041Sbr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30295041Sbr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31295041Sbr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32295041Sbr * SUCH DAMAGE.
33295041Sbr */
34295041Sbr
35295041Sbr#include <sys/cdefs.h>
36295041Sbr__FBSDID("$FreeBSD: head/sys/riscv/riscv/trap.c 300618 2016-05-24 16:41:37Z br $");
37295041Sbr
38295041Sbr#include <sys/param.h>
39295041Sbr#include <sys/systm.h>
40295041Sbr#include <sys/kernel.h>
41295041Sbr#include <sys/lock.h>
42295041Sbr#include <sys/mutex.h>
43295041Sbr#include <sys/pioctl.h>
44295041Sbr#include <sys/bus.h>
45295041Sbr#include <sys/proc.h>
46295041Sbr#include <sys/ptrace.h>
47295041Sbr#include <sys/syscall.h>
48295041Sbr#include <sys/sysent.h>
49296614Sbr#ifdef KDB
50296614Sbr#include <sys/kdb.h>
51296614Sbr#endif
52295041Sbr
53295041Sbr#include <vm/vm.h>
54295041Sbr#include <vm/pmap.h>
55295041Sbr#include <vm/vm_kern.h>
56295041Sbr#include <vm/vm_map.h>
57295041Sbr#include <vm/vm_param.h>
58295041Sbr#include <vm/vm_extern.h>
59295041Sbr
60295041Sbr#include <machine/frame.h>
61295041Sbr#include <machine/pcb.h>
62295041Sbr#include <machine/pcpu.h>
63295041Sbr
64295041Sbr#include <machine/resource.h>
65295041Sbr#include <machine/intr.h>
66295041Sbr
67300618Sbr#ifdef KDTRACE_HOOKS
68300618Sbr#include <sys/dtrace_bsd.h>
69300618Sbr#endif
70300618Sbr
71300618Sbrint (*dtrace_invop_jump_addr)(struct trapframe *);
72300618Sbr
73295041Sbrextern register_t fsu_intr_fault;
74295041Sbr
75295041Sbr/* Called from exception.S */
76295041Sbrvoid do_trap_supervisor(struct trapframe *);
77295041Sbrvoid do_trap_user(struct trapframe *);
78295041Sbr
79295041Sbrstatic __inline void
80295041Sbrcall_trapsignal(struct thread *td, int sig, int code, void *addr)
81295041Sbr{
82295041Sbr	ksiginfo_t ksi;
83295041Sbr
84295041Sbr	ksiginfo_init_trap(&ksi);
85295041Sbr	ksi.ksi_signo = sig;
86295041Sbr	ksi.ksi_code = code;
87295041Sbr	ksi.ksi_addr = addr;
88295041Sbr	trapsignal(td, &ksi);
89295041Sbr}
90295041Sbr
91295041Sbrint
92295041Sbrcpu_fetch_syscall_args(struct thread *td, struct syscall_args *sa)
93295041Sbr{
94295041Sbr	struct proc *p;
95295041Sbr	register_t *ap;
96295041Sbr	int nap;
97295041Sbr
98295041Sbr	nap = 8;
99295041Sbr	p = td->td_proc;
100295041Sbr	ap = &td->td_frame->tf_a[0];
101295041Sbr
102295041Sbr	sa->code = td->td_frame->tf_t[0];
103295041Sbr
104295041Sbr	if (sa->code == SYS_syscall || sa->code == SYS___syscall) {
105295041Sbr		sa->code = *ap++;
106295041Sbr		nap--;
107295041Sbr	}
108295041Sbr
109295041Sbr	if (p->p_sysent->sv_mask)
110295041Sbr		sa->code &= p->p_sysent->sv_mask;
111295041Sbr	if (sa->code >= p->p_sysent->sv_size)
112295041Sbr		sa->callp = &p->p_sysent->sv_table[0];
113295041Sbr	else
114295041Sbr		sa->callp = &p->p_sysent->sv_table[sa->code];
115295041Sbr
116295041Sbr	sa->narg = sa->callp->sy_narg;
117295041Sbr	memcpy(sa->args, ap, nap * sizeof(register_t));
118295041Sbr	if (sa->narg > nap)
119295041Sbr		panic("TODO: Could we have more then 8 args?");
120295041Sbr
121295041Sbr	td->td_retval[0] = 0;
122295041Sbr	td->td_retval[1] = 0;
123295041Sbr
124295041Sbr	return (0);
125295041Sbr}
126295041Sbr
127295041Sbr#include "../../kern/subr_syscall.c"
128295041Sbr
129295041Sbrstatic void
130295041Sbrdump_regs(struct trapframe *frame)
131295041Sbr{
132295041Sbr	int n;
133295041Sbr	int i;
134295041Sbr
135295041Sbr	n = (sizeof(frame->tf_t) / sizeof(frame->tf_t[0]));
136295041Sbr	for (i = 0; i < n; i++)
137295041Sbr		printf("t[%d] == 0x%016lx\n", i, frame->tf_t[i]);
138295041Sbr
139295041Sbr	n = (sizeof(frame->tf_s) / sizeof(frame->tf_s[0]));
140295041Sbr	for (i = 0; i < n; i++)
141295041Sbr		printf("s[%d] == 0x%016lx\n", i, frame->tf_s[i]);
142295041Sbr
143295041Sbr	n = (sizeof(frame->tf_a) / sizeof(frame->tf_a[0]));
144295041Sbr	for (i = 0; i < n; i++)
145295041Sbr		printf("a[%d] == 0x%016lx\n", i, frame->tf_a[i]);
146295041Sbr
147295041Sbr	printf("sepc == 0x%016lx\n", frame->tf_sepc);
148295041Sbr	printf("sstatus == 0x%016lx\n", frame->tf_sstatus);
149295041Sbr}
150295041Sbr
151295041Sbrstatic void
152295041Sbrsvc_handler(struct trapframe *frame)
153295041Sbr{
154295041Sbr	struct syscall_args sa;
155295041Sbr	struct thread *td;
156295041Sbr	int error;
157295041Sbr
158295041Sbr	td = curthread;
159295041Sbr	td->td_frame = frame;
160295041Sbr
161295041Sbr	error = syscallenter(td, &sa);
162295041Sbr	syscallret(td, error, &sa);
163295041Sbr}
164295041Sbr
165295041Sbrstatic void
166295041Sbrdata_abort(struct trapframe *frame, int lower)
167295041Sbr{
168295041Sbr	struct vm_map *map;
169295041Sbr	uint64_t sbadaddr;
170295041Sbr	struct thread *td;
171295041Sbr	struct pcb *pcb;
172295041Sbr	vm_prot_t ftype;
173295041Sbr	vm_offset_t va;
174295041Sbr	struct proc *p;
175295041Sbr	int ucode;
176295041Sbr	int error;
177295041Sbr	int sig;
178295041Sbr
179296614Sbr#ifdef KDB
180296614Sbr	if (kdb_active) {
181296614Sbr		kdb_reenter();
182296614Sbr		return;
183296614Sbr	}
184296614Sbr#endif
185296614Sbr
186295041Sbr	td = curthread;
187295041Sbr	pcb = td->td_pcb;
188295041Sbr
189295041Sbr	/*
190295041Sbr	 * Special case for fuswintr and suswintr. These can't sleep so
191295041Sbr	 * handle them early on in the trap handler.
192295041Sbr	 */
193295041Sbr	if (__predict_false(pcb->pcb_onfault == (vm_offset_t)&fsu_intr_fault)) {
194295041Sbr		frame->tf_sepc = pcb->pcb_onfault;
195295041Sbr		return;
196295041Sbr	}
197295041Sbr
198295041Sbr	sbadaddr = frame->tf_sbadaddr;
199295041Sbr
200295041Sbr	p = td->td_proc;
201295041Sbr
202295041Sbr	if (lower)
203295041Sbr		map = &td->td_proc->p_vmspace->vm_map;
204295041Sbr	else {
205295041Sbr		/* The top bit tells us which range to use */
206295041Sbr		if ((sbadaddr >> 63) == 1)
207295041Sbr			map = kernel_map;
208295041Sbr		else
209295041Sbr			map = &td->td_proc->p_vmspace->vm_map;
210295041Sbr	}
211295041Sbr
212295041Sbr	va = trunc_page(sbadaddr);
213295041Sbr
214295041Sbr	if (frame->tf_scause == EXCP_STORE_ACCESS_FAULT) {
215295041Sbr		ftype = (VM_PROT_READ | VM_PROT_WRITE);
216295041Sbr	} else {
217295041Sbr		ftype = (VM_PROT_READ);
218295041Sbr	}
219295041Sbr
220295041Sbr	if (map != kernel_map) {
221295041Sbr		/*
222295041Sbr		 * Keep swapout from messing with us during this
223295041Sbr		 *	critical time.
224295041Sbr		 */
225295041Sbr		PROC_LOCK(p);
226295041Sbr		++p->p_lock;
227295041Sbr		PROC_UNLOCK(p);
228295041Sbr
229295041Sbr		/* Fault in the user page: */
230295041Sbr		error = vm_fault(map, va, ftype, VM_FAULT_NORMAL);
231295041Sbr
232295041Sbr		PROC_LOCK(p);
233295041Sbr		--p->p_lock;
234295041Sbr		PROC_UNLOCK(p);
235295041Sbr	} else {
236295041Sbr		/*
237295041Sbr		 * Don't have to worry about process locking or stacks in the
238295041Sbr		 * kernel.
239295041Sbr		 */
240295041Sbr		error = vm_fault(map, va, ftype, VM_FAULT_NORMAL);
241295041Sbr	}
242295041Sbr
243295041Sbr	if (error != KERN_SUCCESS) {
244295041Sbr		if (lower) {
245295041Sbr			sig = SIGSEGV;
246295041Sbr			if (error == KERN_PROTECTION_FAILURE)
247295041Sbr				ucode = SEGV_ACCERR;
248295041Sbr			else
249295041Sbr				ucode = SEGV_MAPERR;
250295041Sbr			call_trapsignal(td, sig, ucode, (void *)sbadaddr);
251295041Sbr		} else {
252295041Sbr			if (td->td_intr_nesting_level == 0 &&
253295041Sbr			    pcb->pcb_onfault != 0) {
254295041Sbr				frame->tf_a[0] = error;
255295041Sbr				frame->tf_sepc = pcb->pcb_onfault;
256295041Sbr				return;
257295041Sbr			}
258295041Sbr			dump_regs(frame);
259295041Sbr			panic("vm_fault failed: %lx, va 0x%016lx",
260295041Sbr				frame->tf_sepc, sbadaddr);
261295041Sbr		}
262295041Sbr	}
263295041Sbr
264295041Sbr	if (lower)
265295041Sbr		userret(td, frame);
266295041Sbr}
267295041Sbr
268295041Sbrvoid
269295041Sbrdo_trap_supervisor(struct trapframe *frame)
270295041Sbr{
271295041Sbr	uint64_t exception;
272295041Sbr
273295041Sbr	exception = (frame->tf_scause & EXCP_MASK);
274295041Sbr	if (frame->tf_scause & EXCP_INTR) {
275295041Sbr		/* Interrupt */
276295041Sbr		riscv_cpu_intr(frame);
277295041Sbr		return;
278295041Sbr	}
279295041Sbr
280300618Sbr#ifdef KDTRACE_HOOKS
281300618Sbr	if (dtrace_trap_func != NULL && (*dtrace_trap_func)(frame, exception))
282300618Sbr		return;
283300618Sbr#endif
284300618Sbr
285295041Sbr	CTR3(KTR_TRAP, "do_trap_supervisor: curthread: %p, sepc: %lx, frame: %p",
286295041Sbr	    curthread, frame->tf_sepc, frame);
287295041Sbr
288295041Sbr	switch(exception) {
289295041Sbr	case EXCP_LOAD_ACCESS_FAULT:
290295041Sbr	case EXCP_STORE_ACCESS_FAULT:
291295041Sbr	case EXCP_INSTR_ACCESS_FAULT:
292295041Sbr		data_abort(frame, 0);
293295041Sbr		break;
294295893Sbr	case EXCP_INSTR_BREAKPOINT:
295300618Sbr#ifdef KDTRACE_HOOKS
296300618Sbr		if (dtrace_invop_jump_addr != 0) {
297300618Sbr			dtrace_invop_jump_addr(frame);
298300618Sbr			break;
299300618Sbr		}
300300618Sbr#endif
301295893Sbr#ifdef KDB
302295893Sbr		kdb_trap(exception, 0, frame);
303295893Sbr#else
304295893Sbr		dump_regs(frame);
305295893Sbr		panic("No debugger in kernel.\n");
306295893Sbr#endif
307296614Sbr		break;
308295893Sbr	case EXCP_INSTR_ILLEGAL:
309295893Sbr		dump_regs(frame);
310300618Sbr		panic("Illegal instruction at 0x%016lx\n", frame->tf_sepc);
311295893Sbr		break;
312295041Sbr	default:
313295041Sbr		dump_regs(frame);
314295041Sbr		panic("Unknown kernel exception %x badaddr %lx\n",
315295041Sbr			exception, frame->tf_sbadaddr);
316295041Sbr	}
317295041Sbr}
318295041Sbr
319295041Sbrvoid
320295041Sbrdo_trap_user(struct trapframe *frame)
321295041Sbr{
322295041Sbr	uint64_t exception;
323295893Sbr	struct thread *td;
324295041Sbr
325295893Sbr	td = curthread;
326295893Sbr	td->td_frame = frame;
327295893Sbr
328295041Sbr	exception = (frame->tf_scause & EXCP_MASK);
329295041Sbr	if (frame->tf_scause & EXCP_INTR) {
330295041Sbr		/* Interrupt */
331295041Sbr		riscv_cpu_intr(frame);
332295041Sbr		return;
333295041Sbr	}
334295041Sbr
335295041Sbr	CTR3(KTR_TRAP, "do_trap_user: curthread: %p, sepc: %lx, frame: %p",
336295041Sbr	    curthread, frame->tf_sepc, frame);
337295041Sbr
338295041Sbr	switch(exception) {
339295041Sbr	case EXCP_LOAD_ACCESS_FAULT:
340295041Sbr	case EXCP_STORE_ACCESS_FAULT:
341295041Sbr	case EXCP_INSTR_ACCESS_FAULT:
342295041Sbr		data_abort(frame, 1);
343295041Sbr		break;
344295041Sbr	case EXCP_UMODE_ENV_CALL:
345295041Sbr		frame->tf_sepc += 4;	/* Next instruction */
346295041Sbr		svc_handler(frame);
347295041Sbr		break;
348295893Sbr	case EXCP_INSTR_ILLEGAL:
349295893Sbr		call_trapsignal(td, SIGILL, ILL_ILLTRP, (void *)frame->tf_sepc);
350295893Sbr		userret(td, frame);
351295893Sbr		break;
352295893Sbr	case EXCP_INSTR_BREAKPOINT:
353295893Sbr		call_trapsignal(td, SIGTRAP, TRAP_BRKPT, (void *)frame->tf_sepc);
354295893Sbr		userret(td, frame);
355295893Sbr		break;
356295041Sbr	default:
357295041Sbr		dump_regs(frame);
358295041Sbr		panic("Unknown userland exception %x badaddr %lx\n",
359295041Sbr			exception, frame->tf_sbadaddr);
360295041Sbr	}
361295041Sbr}
362