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