trap.c revision 296614
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 296614 2016-03-10 15:51:43Z 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
67295041Sbrextern register_t fsu_intr_fault;
68295041Sbr
69295041Sbr/* Called from exception.S */
70295041Sbrvoid do_trap_supervisor(struct trapframe *);
71295041Sbrvoid do_trap_user(struct trapframe *);
72295041Sbr
73295041Sbrstatic __inline void
74295041Sbrcall_trapsignal(struct thread *td, int sig, int code, void *addr)
75295041Sbr{
76295041Sbr	ksiginfo_t ksi;
77295041Sbr
78295041Sbr	ksiginfo_init_trap(&ksi);
79295041Sbr	ksi.ksi_signo = sig;
80295041Sbr	ksi.ksi_code = code;
81295041Sbr	ksi.ksi_addr = addr;
82295041Sbr	trapsignal(td, &ksi);
83295041Sbr}
84295041Sbr
85295041Sbrint
86295041Sbrcpu_fetch_syscall_args(struct thread *td, struct syscall_args *sa)
87295041Sbr{
88295041Sbr	struct proc *p;
89295041Sbr	register_t *ap;
90295041Sbr	int nap;
91295041Sbr
92295041Sbr	nap = 8;
93295041Sbr	p = td->td_proc;
94295041Sbr	ap = &td->td_frame->tf_a[0];
95295041Sbr
96295041Sbr	sa->code = td->td_frame->tf_t[0];
97295041Sbr
98295041Sbr	if (sa->code == SYS_syscall || sa->code == SYS___syscall) {
99295041Sbr		sa->code = *ap++;
100295041Sbr		nap--;
101295041Sbr	}
102295041Sbr
103295041Sbr	if (p->p_sysent->sv_mask)
104295041Sbr		sa->code &= p->p_sysent->sv_mask;
105295041Sbr	if (sa->code >= p->p_sysent->sv_size)
106295041Sbr		sa->callp = &p->p_sysent->sv_table[0];
107295041Sbr	else
108295041Sbr		sa->callp = &p->p_sysent->sv_table[sa->code];
109295041Sbr
110295041Sbr	sa->narg = sa->callp->sy_narg;
111295041Sbr	memcpy(sa->args, ap, nap * sizeof(register_t));
112295041Sbr	if (sa->narg > nap)
113295041Sbr		panic("TODO: Could we have more then 8 args?");
114295041Sbr
115295041Sbr	td->td_retval[0] = 0;
116295041Sbr	td->td_retval[1] = 0;
117295041Sbr
118295041Sbr	return (0);
119295041Sbr}
120295041Sbr
121295041Sbr#include "../../kern/subr_syscall.c"
122295041Sbr
123295041Sbrstatic void
124295041Sbrdump_regs(struct trapframe *frame)
125295041Sbr{
126295041Sbr	int n;
127295041Sbr	int i;
128295041Sbr
129295041Sbr	n = (sizeof(frame->tf_t) / sizeof(frame->tf_t[0]));
130295041Sbr	for (i = 0; i < n; i++)
131295041Sbr		printf("t[%d] == 0x%016lx\n", i, frame->tf_t[i]);
132295041Sbr
133295041Sbr	n = (sizeof(frame->tf_s) / sizeof(frame->tf_s[0]));
134295041Sbr	for (i = 0; i < n; i++)
135295041Sbr		printf("s[%d] == 0x%016lx\n", i, frame->tf_s[i]);
136295041Sbr
137295041Sbr	n = (sizeof(frame->tf_a) / sizeof(frame->tf_a[0]));
138295041Sbr	for (i = 0; i < n; i++)
139295041Sbr		printf("a[%d] == 0x%016lx\n", i, frame->tf_a[i]);
140295041Sbr
141295041Sbr	printf("sepc == 0x%016lx\n", frame->tf_sepc);
142295041Sbr	printf("sstatus == 0x%016lx\n", frame->tf_sstatus);
143295041Sbr}
144295041Sbr
145295041Sbrstatic void
146295041Sbrsvc_handler(struct trapframe *frame)
147295041Sbr{
148295041Sbr	struct syscall_args sa;
149295041Sbr	struct thread *td;
150295041Sbr	int error;
151295041Sbr
152295041Sbr	td = curthread;
153295041Sbr	td->td_frame = frame;
154295041Sbr
155295041Sbr	error = syscallenter(td, &sa);
156295041Sbr	syscallret(td, error, &sa);
157295041Sbr}
158295041Sbr
159295041Sbrstatic void
160295041Sbrdata_abort(struct trapframe *frame, int lower)
161295041Sbr{
162295041Sbr	struct vm_map *map;
163295041Sbr	uint64_t sbadaddr;
164295041Sbr	struct thread *td;
165295041Sbr	struct pcb *pcb;
166295041Sbr	vm_prot_t ftype;
167295041Sbr	vm_offset_t va;
168295041Sbr	struct proc *p;
169295041Sbr	int ucode;
170295041Sbr	int error;
171295041Sbr	int sig;
172295041Sbr
173296614Sbr#ifdef KDB
174296614Sbr	if (kdb_active) {
175296614Sbr		kdb_reenter();
176296614Sbr		return;
177296614Sbr	}
178296614Sbr#endif
179296614Sbr
180295041Sbr	td = curthread;
181295041Sbr	pcb = td->td_pcb;
182295041Sbr
183295041Sbr	/*
184295041Sbr	 * Special case for fuswintr and suswintr. These can't sleep so
185295041Sbr	 * handle them early on in the trap handler.
186295041Sbr	 */
187295041Sbr	if (__predict_false(pcb->pcb_onfault == (vm_offset_t)&fsu_intr_fault)) {
188295041Sbr		frame->tf_sepc = pcb->pcb_onfault;
189295041Sbr		return;
190295041Sbr	}
191295041Sbr
192295041Sbr	sbadaddr = frame->tf_sbadaddr;
193295041Sbr
194295041Sbr	p = td->td_proc;
195295041Sbr
196295041Sbr	if (lower)
197295041Sbr		map = &td->td_proc->p_vmspace->vm_map;
198295041Sbr	else {
199295041Sbr		/* The top bit tells us which range to use */
200295041Sbr		if ((sbadaddr >> 63) == 1)
201295041Sbr			map = kernel_map;
202295041Sbr		else
203295041Sbr			map = &td->td_proc->p_vmspace->vm_map;
204295041Sbr	}
205295041Sbr
206295041Sbr	va = trunc_page(sbadaddr);
207295041Sbr
208295041Sbr	if (frame->tf_scause == EXCP_STORE_ACCESS_FAULT) {
209295041Sbr		ftype = (VM_PROT_READ | VM_PROT_WRITE);
210295041Sbr	} else {
211295041Sbr		ftype = (VM_PROT_READ);
212295041Sbr	}
213295041Sbr
214295041Sbr	if (map != kernel_map) {
215295041Sbr		/*
216295041Sbr		 * Keep swapout from messing with us during this
217295041Sbr		 *	critical time.
218295041Sbr		 */
219295041Sbr		PROC_LOCK(p);
220295041Sbr		++p->p_lock;
221295041Sbr		PROC_UNLOCK(p);
222295041Sbr
223295041Sbr		/* Fault in the user page: */
224295041Sbr		error = vm_fault(map, va, ftype, VM_FAULT_NORMAL);
225295041Sbr
226295041Sbr		PROC_LOCK(p);
227295041Sbr		--p->p_lock;
228295041Sbr		PROC_UNLOCK(p);
229295041Sbr	} else {
230295041Sbr		/*
231295041Sbr		 * Don't have to worry about process locking or stacks in the
232295041Sbr		 * kernel.
233295041Sbr		 */
234295041Sbr		error = vm_fault(map, va, ftype, VM_FAULT_NORMAL);
235295041Sbr	}
236295041Sbr
237295041Sbr	if (error != KERN_SUCCESS) {
238295041Sbr		if (lower) {
239295041Sbr			sig = SIGSEGV;
240295041Sbr			if (error == KERN_PROTECTION_FAILURE)
241295041Sbr				ucode = SEGV_ACCERR;
242295041Sbr			else
243295041Sbr				ucode = SEGV_MAPERR;
244295041Sbr			call_trapsignal(td, sig, ucode, (void *)sbadaddr);
245295041Sbr		} else {
246295041Sbr			if (td->td_intr_nesting_level == 0 &&
247295041Sbr			    pcb->pcb_onfault != 0) {
248295041Sbr				frame->tf_a[0] = error;
249295041Sbr				frame->tf_sepc = pcb->pcb_onfault;
250295041Sbr				return;
251295041Sbr			}
252295041Sbr			dump_regs(frame);
253295041Sbr			panic("vm_fault failed: %lx, va 0x%016lx",
254295041Sbr				frame->tf_sepc, sbadaddr);
255295041Sbr		}
256295041Sbr	}
257295041Sbr
258295041Sbr	if (lower)
259295041Sbr		userret(td, frame);
260295041Sbr}
261295041Sbr
262295041Sbrvoid
263295041Sbrdo_trap_supervisor(struct trapframe *frame)
264295041Sbr{
265295041Sbr	uint64_t exception;
266295041Sbr
267295041Sbr	exception = (frame->tf_scause & EXCP_MASK);
268295041Sbr	if (frame->tf_scause & EXCP_INTR) {
269295041Sbr		/* Interrupt */
270295041Sbr		riscv_cpu_intr(frame);
271295041Sbr		return;
272295041Sbr	}
273295041Sbr
274295041Sbr	CTR3(KTR_TRAP, "do_trap_supervisor: curthread: %p, sepc: %lx, frame: %p",
275295041Sbr	    curthread, frame->tf_sepc, frame);
276295041Sbr
277295041Sbr	switch(exception) {
278295041Sbr	case EXCP_LOAD_ACCESS_FAULT:
279295041Sbr	case EXCP_STORE_ACCESS_FAULT:
280295041Sbr	case EXCP_INSTR_ACCESS_FAULT:
281295041Sbr		data_abort(frame, 0);
282295041Sbr		break;
283295893Sbr	case EXCP_INSTR_BREAKPOINT:
284295893Sbr#ifdef KDB
285295893Sbr		kdb_trap(exception, 0, frame);
286295893Sbr#else
287295893Sbr		dump_regs(frame);
288295893Sbr		panic("No debugger in kernel.\n");
289295893Sbr#endif
290296614Sbr		break;
291295893Sbr	case EXCP_INSTR_ILLEGAL:
292295893Sbr		dump_regs(frame);
293295893Sbr		panic("Illegal instruction at %x\n", frame->tf_sepc);
294295893Sbr		break;
295295041Sbr	default:
296295041Sbr		dump_regs(frame);
297295041Sbr		panic("Unknown kernel exception %x badaddr %lx\n",
298295041Sbr			exception, frame->tf_sbadaddr);
299295041Sbr	}
300295041Sbr}
301295041Sbr
302295041Sbrvoid
303295041Sbrdo_trap_user(struct trapframe *frame)
304295041Sbr{
305295041Sbr	uint64_t exception;
306295893Sbr	struct thread *td;
307295041Sbr
308295893Sbr	td = curthread;
309295893Sbr	td->td_frame = frame;
310295893Sbr
311295041Sbr	exception = (frame->tf_scause & EXCP_MASK);
312295041Sbr	if (frame->tf_scause & EXCP_INTR) {
313295041Sbr		/* Interrupt */
314295041Sbr		riscv_cpu_intr(frame);
315295041Sbr		return;
316295041Sbr	}
317295041Sbr
318295041Sbr	CTR3(KTR_TRAP, "do_trap_user: curthread: %p, sepc: %lx, frame: %p",
319295041Sbr	    curthread, frame->tf_sepc, frame);
320295041Sbr
321295041Sbr	switch(exception) {
322295041Sbr	case EXCP_LOAD_ACCESS_FAULT:
323295041Sbr	case EXCP_STORE_ACCESS_FAULT:
324295041Sbr	case EXCP_INSTR_ACCESS_FAULT:
325295041Sbr		data_abort(frame, 1);
326295041Sbr		break;
327295041Sbr	case EXCP_UMODE_ENV_CALL:
328295041Sbr		frame->tf_sepc += 4;	/* Next instruction */
329295041Sbr		svc_handler(frame);
330295041Sbr		break;
331295893Sbr	case EXCP_INSTR_ILLEGAL:
332295893Sbr		call_trapsignal(td, SIGILL, ILL_ILLTRP, (void *)frame->tf_sepc);
333295893Sbr		userret(td, frame);
334295893Sbr		break;
335295893Sbr	case EXCP_INSTR_BREAKPOINT:
336295893Sbr		call_trapsignal(td, SIGTRAP, TRAP_BRKPT, (void *)frame->tf_sepc);
337295893Sbr		userret(td, frame);
338295893Sbr		break;
339295041Sbr	default:
340295041Sbr		dump_regs(frame);
341295041Sbr		panic("Unknown userland exception %x badaddr %lx\n",
342295041Sbr			exception, frame->tf_sbadaddr);
343295041Sbr	}
344295041Sbr}
345