trap.c revision 295893
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 295893 2016-02-22 14:54:50Z 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>
49295041Sbr
50295041Sbr#include <vm/vm.h>
51295041Sbr#include <vm/pmap.h>
52295041Sbr#include <vm/vm_kern.h>
53295041Sbr#include <vm/vm_map.h>
54295041Sbr#include <vm/vm_param.h>
55295041Sbr#include <vm/vm_extern.h>
56295041Sbr
57295041Sbr#include <machine/frame.h>
58295041Sbr#include <machine/pcb.h>
59295041Sbr#include <machine/pcpu.h>
60295041Sbr
61295041Sbr#include <machine/resource.h>
62295041Sbr#include <machine/intr.h>
63295041Sbr
64295041Sbrextern register_t fsu_intr_fault;
65295041Sbr
66295041Sbr/* Called from exception.S */
67295041Sbrvoid do_trap_supervisor(struct trapframe *);
68295041Sbrvoid do_trap_user(struct trapframe *);
69295041Sbr
70295041Sbrstatic __inline void
71295041Sbrcall_trapsignal(struct thread *td, int sig, int code, void *addr)
72295041Sbr{
73295041Sbr	ksiginfo_t ksi;
74295041Sbr
75295041Sbr	ksiginfo_init_trap(&ksi);
76295041Sbr	ksi.ksi_signo = sig;
77295041Sbr	ksi.ksi_code = code;
78295041Sbr	ksi.ksi_addr = addr;
79295041Sbr	trapsignal(td, &ksi);
80295041Sbr}
81295041Sbr
82295041Sbrint
83295041Sbrcpu_fetch_syscall_args(struct thread *td, struct syscall_args *sa)
84295041Sbr{
85295041Sbr	struct proc *p;
86295041Sbr	register_t *ap;
87295041Sbr	int nap;
88295041Sbr
89295041Sbr	nap = 8;
90295041Sbr	p = td->td_proc;
91295041Sbr	ap = &td->td_frame->tf_a[0];
92295041Sbr
93295041Sbr	sa->code = td->td_frame->tf_t[0];
94295041Sbr
95295041Sbr	if (sa->code == SYS_syscall || sa->code == SYS___syscall) {
96295041Sbr		sa->code = *ap++;
97295041Sbr		nap--;
98295041Sbr	}
99295041Sbr
100295041Sbr	if (p->p_sysent->sv_mask)
101295041Sbr		sa->code &= p->p_sysent->sv_mask;
102295041Sbr	if (sa->code >= p->p_sysent->sv_size)
103295041Sbr		sa->callp = &p->p_sysent->sv_table[0];
104295041Sbr	else
105295041Sbr		sa->callp = &p->p_sysent->sv_table[sa->code];
106295041Sbr
107295041Sbr	sa->narg = sa->callp->sy_narg;
108295041Sbr	memcpy(sa->args, ap, nap * sizeof(register_t));
109295041Sbr	if (sa->narg > nap)
110295041Sbr		panic("TODO: Could we have more then 8 args?");
111295041Sbr
112295041Sbr	td->td_retval[0] = 0;
113295041Sbr	td->td_retval[1] = 0;
114295041Sbr
115295041Sbr	return (0);
116295041Sbr}
117295041Sbr
118295041Sbr#include "../../kern/subr_syscall.c"
119295041Sbr
120295041Sbrstatic void
121295041Sbrdump_regs(struct trapframe *frame)
122295041Sbr{
123295041Sbr	int n;
124295041Sbr	int i;
125295041Sbr
126295041Sbr	n = (sizeof(frame->tf_t) / sizeof(frame->tf_t[0]));
127295041Sbr	for (i = 0; i < n; i++)
128295041Sbr		printf("t[%d] == 0x%016lx\n", i, frame->tf_t[i]);
129295041Sbr
130295041Sbr	n = (sizeof(frame->tf_s) / sizeof(frame->tf_s[0]));
131295041Sbr	for (i = 0; i < n; i++)
132295041Sbr		printf("s[%d] == 0x%016lx\n", i, frame->tf_s[i]);
133295041Sbr
134295041Sbr	n = (sizeof(frame->tf_a) / sizeof(frame->tf_a[0]));
135295041Sbr	for (i = 0; i < n; i++)
136295041Sbr		printf("a[%d] == 0x%016lx\n", i, frame->tf_a[i]);
137295041Sbr
138295041Sbr	printf("sepc == 0x%016lx\n", frame->tf_sepc);
139295041Sbr	printf("sstatus == 0x%016lx\n", frame->tf_sstatus);
140295041Sbr}
141295041Sbr
142295041Sbrstatic void
143295041Sbrsvc_handler(struct trapframe *frame)
144295041Sbr{
145295041Sbr	struct syscall_args sa;
146295041Sbr	struct thread *td;
147295041Sbr	int error;
148295041Sbr
149295041Sbr	td = curthread;
150295041Sbr	td->td_frame = frame;
151295041Sbr
152295041Sbr	error = syscallenter(td, &sa);
153295041Sbr	syscallret(td, error, &sa);
154295041Sbr}
155295041Sbr
156295041Sbrstatic void
157295041Sbrdata_abort(struct trapframe *frame, int lower)
158295041Sbr{
159295041Sbr	struct vm_map *map;
160295041Sbr	uint64_t sbadaddr;
161295041Sbr	struct thread *td;
162295041Sbr	struct pcb *pcb;
163295041Sbr	vm_prot_t ftype;
164295041Sbr	vm_offset_t va;
165295041Sbr	struct proc *p;
166295041Sbr	int ucode;
167295041Sbr	int error;
168295041Sbr	int sig;
169295041Sbr
170295041Sbr	td = curthread;
171295041Sbr	pcb = td->td_pcb;
172295041Sbr
173295041Sbr	/*
174295041Sbr	 * Special case for fuswintr and suswintr. These can't sleep so
175295041Sbr	 * handle them early on in the trap handler.
176295041Sbr	 */
177295041Sbr	if (__predict_false(pcb->pcb_onfault == (vm_offset_t)&fsu_intr_fault)) {
178295041Sbr		frame->tf_sepc = pcb->pcb_onfault;
179295041Sbr		return;
180295041Sbr	}
181295041Sbr
182295041Sbr	sbadaddr = frame->tf_sbadaddr;
183295041Sbr
184295041Sbr	p = td->td_proc;
185295041Sbr
186295041Sbr	if (lower)
187295041Sbr		map = &td->td_proc->p_vmspace->vm_map;
188295041Sbr	else {
189295041Sbr		/* The top bit tells us which range to use */
190295041Sbr		if ((sbadaddr >> 63) == 1)
191295041Sbr			map = kernel_map;
192295041Sbr		else
193295041Sbr			map = &td->td_proc->p_vmspace->vm_map;
194295041Sbr	}
195295041Sbr
196295041Sbr	va = trunc_page(sbadaddr);
197295041Sbr
198295041Sbr	if (frame->tf_scause == EXCP_STORE_ACCESS_FAULT) {
199295041Sbr		ftype = (VM_PROT_READ | VM_PROT_WRITE);
200295041Sbr	} else {
201295041Sbr		ftype = (VM_PROT_READ);
202295041Sbr	}
203295041Sbr
204295041Sbr	if (map != kernel_map) {
205295041Sbr		/*
206295041Sbr		 * Keep swapout from messing with us during this
207295041Sbr		 *	critical time.
208295041Sbr		 */
209295041Sbr		PROC_LOCK(p);
210295041Sbr		++p->p_lock;
211295041Sbr		PROC_UNLOCK(p);
212295041Sbr
213295041Sbr		/* Fault in the user page: */
214295041Sbr		error = vm_fault(map, va, ftype, VM_FAULT_NORMAL);
215295041Sbr
216295041Sbr		PROC_LOCK(p);
217295041Sbr		--p->p_lock;
218295041Sbr		PROC_UNLOCK(p);
219295041Sbr	} else {
220295041Sbr		/*
221295041Sbr		 * Don't have to worry about process locking or stacks in the
222295041Sbr		 * kernel.
223295041Sbr		 */
224295041Sbr		error = vm_fault(map, va, ftype, VM_FAULT_NORMAL);
225295041Sbr	}
226295041Sbr
227295041Sbr	if (error != KERN_SUCCESS) {
228295041Sbr		if (lower) {
229295041Sbr			sig = SIGSEGV;
230295041Sbr			if (error == KERN_PROTECTION_FAILURE)
231295041Sbr				ucode = SEGV_ACCERR;
232295041Sbr			else
233295041Sbr				ucode = SEGV_MAPERR;
234295041Sbr			call_trapsignal(td, sig, ucode, (void *)sbadaddr);
235295041Sbr		} else {
236295041Sbr			if (td->td_intr_nesting_level == 0 &&
237295041Sbr			    pcb->pcb_onfault != 0) {
238295041Sbr				frame->tf_a[0] = error;
239295041Sbr				frame->tf_sepc = pcb->pcb_onfault;
240295041Sbr				return;
241295041Sbr			}
242295041Sbr			dump_regs(frame);
243295041Sbr			panic("vm_fault failed: %lx, va 0x%016lx",
244295041Sbr				frame->tf_sepc, sbadaddr);
245295041Sbr		}
246295041Sbr	}
247295041Sbr
248295041Sbr	if (lower)
249295041Sbr		userret(td, frame);
250295041Sbr}
251295041Sbr
252295041Sbrvoid
253295041Sbrdo_trap_supervisor(struct trapframe *frame)
254295041Sbr{
255295041Sbr	uint64_t exception;
256295041Sbr
257295041Sbr	exception = (frame->tf_scause & EXCP_MASK);
258295041Sbr	if (frame->tf_scause & EXCP_INTR) {
259295041Sbr		/* Interrupt */
260295041Sbr		riscv_cpu_intr(frame);
261295041Sbr		return;
262295041Sbr	}
263295041Sbr
264295041Sbr	CTR3(KTR_TRAP, "do_trap_supervisor: curthread: %p, sepc: %lx, frame: %p",
265295041Sbr	    curthread, frame->tf_sepc, frame);
266295041Sbr
267295041Sbr	switch(exception) {
268295041Sbr	case EXCP_LOAD_ACCESS_FAULT:
269295041Sbr	case EXCP_STORE_ACCESS_FAULT:
270295041Sbr	case EXCP_INSTR_ACCESS_FAULT:
271295041Sbr		data_abort(frame, 0);
272295041Sbr		break;
273295893Sbr	case EXCP_INSTR_BREAKPOINT:
274295893Sbr#ifdef KDB
275295893Sbr		kdb_trap(exception, 0, frame);
276295893Sbr#else
277295893Sbr		dump_regs(frame);
278295893Sbr		panic("No debugger in kernel.\n");
279295893Sbr#endif
280295893Sbr	case EXCP_INSTR_ILLEGAL:
281295893Sbr		dump_regs(frame);
282295893Sbr		panic("Illegal instruction at %x\n", frame->tf_sepc);
283295893Sbr		break;
284295041Sbr	default:
285295041Sbr		dump_regs(frame);
286295041Sbr		panic("Unknown kernel exception %x badaddr %lx\n",
287295041Sbr			exception, frame->tf_sbadaddr);
288295041Sbr	}
289295041Sbr}
290295041Sbr
291295041Sbrvoid
292295041Sbrdo_trap_user(struct trapframe *frame)
293295041Sbr{
294295041Sbr	uint64_t exception;
295295893Sbr	struct thread *td;
296295041Sbr
297295893Sbr	td = curthread;
298295893Sbr	td->td_frame = frame;
299295893Sbr
300295041Sbr	exception = (frame->tf_scause & EXCP_MASK);
301295041Sbr	if (frame->tf_scause & EXCP_INTR) {
302295041Sbr		/* Interrupt */
303295041Sbr		riscv_cpu_intr(frame);
304295041Sbr		return;
305295041Sbr	}
306295041Sbr
307295041Sbr	CTR3(KTR_TRAP, "do_trap_user: curthread: %p, sepc: %lx, frame: %p",
308295041Sbr	    curthread, frame->tf_sepc, frame);
309295041Sbr
310295041Sbr	switch(exception) {
311295041Sbr	case EXCP_LOAD_ACCESS_FAULT:
312295041Sbr	case EXCP_STORE_ACCESS_FAULT:
313295041Sbr	case EXCP_INSTR_ACCESS_FAULT:
314295041Sbr		data_abort(frame, 1);
315295041Sbr		break;
316295041Sbr	case EXCP_UMODE_ENV_CALL:
317295041Sbr		frame->tf_sepc += 4;	/* Next instruction */
318295041Sbr		svc_handler(frame);
319295041Sbr		break;
320295893Sbr	case EXCP_INSTR_ILLEGAL:
321295893Sbr		call_trapsignal(td, SIGILL, ILL_ILLTRP, (void *)frame->tf_sepc);
322295893Sbr		userret(td, frame);
323295893Sbr		break;
324295893Sbr	case EXCP_INSTR_BREAKPOINT:
325295893Sbr		call_trapsignal(td, SIGTRAP, TRAP_BRKPT, (void *)frame->tf_sepc);
326295893Sbr		userret(td, frame);
327295893Sbr		break;
328295041Sbr	default:
329295041Sbr		dump_regs(frame);
330295041Sbr		panic("Unknown userland exception %x badaddr %lx\n",
331295041Sbr			exception, frame->tf_sbadaddr);
332295041Sbr	}
333295041Sbr}
334