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: stable/11/sys/riscv/riscv/trap.c 321343 2017-07-21 18:06:57Z kib $");
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
92321343Skibcpu_fetch_syscall_args(struct thread *td)
93295041Sbr{
94295041Sbr	struct proc *p;
95295041Sbr	register_t *ap;
96321343Skib	struct syscall_args *sa;
97295041Sbr	int nap;
98295041Sbr
99295041Sbr	nap = 8;
100295041Sbr	p = td->td_proc;
101321343Skib	sa = &td->td_sa;
102295041Sbr	ap = &td->td_frame->tf_a[0];
103295041Sbr
104295041Sbr	sa->code = td->td_frame->tf_t[0];
105295041Sbr
106295041Sbr	if (sa->code == SYS_syscall || sa->code == SYS___syscall) {
107295041Sbr		sa->code = *ap++;
108295041Sbr		nap--;
109295041Sbr	}
110295041Sbr
111295041Sbr	if (p->p_sysent->sv_mask)
112295041Sbr		sa->code &= p->p_sysent->sv_mask;
113295041Sbr	if (sa->code >= p->p_sysent->sv_size)
114295041Sbr		sa->callp = &p->p_sysent->sv_table[0];
115295041Sbr	else
116295041Sbr		sa->callp = &p->p_sysent->sv_table[sa->code];
117295041Sbr
118295041Sbr	sa->narg = sa->callp->sy_narg;
119295041Sbr	memcpy(sa->args, ap, nap * sizeof(register_t));
120295041Sbr	if (sa->narg > nap)
121295041Sbr		panic("TODO: Could we have more then 8 args?");
122295041Sbr
123295041Sbr	td->td_retval[0] = 0;
124295041Sbr	td->td_retval[1] = 0;
125295041Sbr
126295041Sbr	return (0);
127295041Sbr}
128295041Sbr
129295041Sbr#include "../../kern/subr_syscall.c"
130295041Sbr
131295041Sbrstatic void
132295041Sbrdump_regs(struct trapframe *frame)
133295041Sbr{
134295041Sbr	int n;
135295041Sbr	int i;
136295041Sbr
137295041Sbr	n = (sizeof(frame->tf_t) / sizeof(frame->tf_t[0]));
138295041Sbr	for (i = 0; i < n; i++)
139295041Sbr		printf("t[%d] == 0x%016lx\n", i, frame->tf_t[i]);
140295041Sbr
141295041Sbr	n = (sizeof(frame->tf_s) / sizeof(frame->tf_s[0]));
142295041Sbr	for (i = 0; i < n; i++)
143295041Sbr		printf("s[%d] == 0x%016lx\n", i, frame->tf_s[i]);
144295041Sbr
145295041Sbr	n = (sizeof(frame->tf_a) / sizeof(frame->tf_a[0]));
146295041Sbr	for (i = 0; i < n; i++)
147295041Sbr		printf("a[%d] == 0x%016lx\n", i, frame->tf_a[i]);
148295041Sbr
149295041Sbr	printf("sepc == 0x%016lx\n", frame->tf_sepc);
150295041Sbr	printf("sstatus == 0x%016lx\n", frame->tf_sstatus);
151295041Sbr}
152295041Sbr
153295041Sbrstatic void
154295041Sbrsvc_handler(struct trapframe *frame)
155295041Sbr{
156295041Sbr	struct thread *td;
157295041Sbr	int error;
158295041Sbr
159295041Sbr	td = curthread;
160295041Sbr	td->td_frame = frame;
161295041Sbr
162321343Skib	error = syscallenter(td);
163321343Skib	syscallret(td, error);
164295041Sbr}
165295041Sbr
166295041Sbrstatic void
167295041Sbrdata_abort(struct trapframe *frame, int lower)
168295041Sbr{
169295041Sbr	struct vm_map *map;
170295041Sbr	uint64_t sbadaddr;
171295041Sbr	struct thread *td;
172295041Sbr	struct pcb *pcb;
173295041Sbr	vm_prot_t ftype;
174295041Sbr	vm_offset_t va;
175295041Sbr	struct proc *p;
176295041Sbr	int ucode;
177295041Sbr	int error;
178295041Sbr	int sig;
179295041Sbr
180296614Sbr#ifdef KDB
181296614Sbr	if (kdb_active) {
182296614Sbr		kdb_reenter();
183296614Sbr		return;
184296614Sbr	}
185296614Sbr#endif
186296614Sbr
187295041Sbr	td = curthread;
188295041Sbr	pcb = td->td_pcb;
189295041Sbr
190295041Sbr	/*
191295041Sbr	 * Special case for fuswintr and suswintr. These can't sleep so
192295041Sbr	 * handle them early on in the trap handler.
193295041Sbr	 */
194295041Sbr	if (__predict_false(pcb->pcb_onfault == (vm_offset_t)&fsu_intr_fault)) {
195295041Sbr		frame->tf_sepc = pcb->pcb_onfault;
196295041Sbr		return;
197295041Sbr	}
198295041Sbr
199295041Sbr	sbadaddr = frame->tf_sbadaddr;
200295041Sbr
201295041Sbr	p = td->td_proc;
202295041Sbr
203295041Sbr	if (lower)
204295041Sbr		map = &td->td_proc->p_vmspace->vm_map;
205295041Sbr	else {
206295041Sbr		/* The top bit tells us which range to use */
207295041Sbr		if ((sbadaddr >> 63) == 1)
208295041Sbr			map = kernel_map;
209295041Sbr		else
210295041Sbr			map = &td->td_proc->p_vmspace->vm_map;
211295041Sbr	}
212295041Sbr
213295041Sbr	va = trunc_page(sbadaddr);
214295041Sbr
215295041Sbr	if (frame->tf_scause == EXCP_STORE_ACCESS_FAULT) {
216295041Sbr		ftype = (VM_PROT_READ | VM_PROT_WRITE);
217295041Sbr	} else {
218295041Sbr		ftype = (VM_PROT_READ);
219295041Sbr	}
220295041Sbr
221295041Sbr	if (map != kernel_map) {
222295041Sbr		/*
223295041Sbr		 * Keep swapout from messing with us during this
224295041Sbr		 *	critical time.
225295041Sbr		 */
226295041Sbr		PROC_LOCK(p);
227295041Sbr		++p->p_lock;
228295041Sbr		PROC_UNLOCK(p);
229295041Sbr
230295041Sbr		/* Fault in the user page: */
231295041Sbr		error = vm_fault(map, va, ftype, VM_FAULT_NORMAL);
232295041Sbr
233295041Sbr		PROC_LOCK(p);
234295041Sbr		--p->p_lock;
235295041Sbr		PROC_UNLOCK(p);
236295041Sbr	} else {
237295041Sbr		/*
238295041Sbr		 * Don't have to worry about process locking or stacks in the
239295041Sbr		 * kernel.
240295041Sbr		 */
241295041Sbr		error = vm_fault(map, va, ftype, VM_FAULT_NORMAL);
242295041Sbr	}
243295041Sbr
244295041Sbr	if (error != KERN_SUCCESS) {
245295041Sbr		if (lower) {
246295041Sbr			sig = SIGSEGV;
247295041Sbr			if (error == KERN_PROTECTION_FAILURE)
248295041Sbr				ucode = SEGV_ACCERR;
249295041Sbr			else
250295041Sbr				ucode = SEGV_MAPERR;
251295041Sbr			call_trapsignal(td, sig, ucode, (void *)sbadaddr);
252295041Sbr		} else {
253295041Sbr			if (td->td_intr_nesting_level == 0 &&
254295041Sbr			    pcb->pcb_onfault != 0) {
255295041Sbr				frame->tf_a[0] = error;
256295041Sbr				frame->tf_sepc = pcb->pcb_onfault;
257295041Sbr				return;
258295041Sbr			}
259295041Sbr			dump_regs(frame);
260295041Sbr			panic("vm_fault failed: %lx, va 0x%016lx",
261295041Sbr				frame->tf_sepc, sbadaddr);
262295041Sbr		}
263295041Sbr	}
264295041Sbr
265295041Sbr	if (lower)
266295041Sbr		userret(td, frame);
267295041Sbr}
268295041Sbr
269295041Sbrvoid
270295041Sbrdo_trap_supervisor(struct trapframe *frame)
271295041Sbr{
272295041Sbr	uint64_t exception;
273295041Sbr
274295041Sbr	exception = (frame->tf_scause & EXCP_MASK);
275295041Sbr	if (frame->tf_scause & EXCP_INTR) {
276295041Sbr		/* Interrupt */
277295041Sbr		riscv_cpu_intr(frame);
278295041Sbr		return;
279295041Sbr	}
280295041Sbr
281300618Sbr#ifdef KDTRACE_HOOKS
282300618Sbr	if (dtrace_trap_func != NULL && (*dtrace_trap_func)(frame, exception))
283300618Sbr		return;
284300618Sbr#endif
285300618Sbr
286295041Sbr	CTR3(KTR_TRAP, "do_trap_supervisor: curthread: %p, sepc: %lx, frame: %p",
287295041Sbr	    curthread, frame->tf_sepc, frame);
288295041Sbr
289295041Sbr	switch(exception) {
290295041Sbr	case EXCP_LOAD_ACCESS_FAULT:
291295041Sbr	case EXCP_STORE_ACCESS_FAULT:
292295041Sbr	case EXCP_INSTR_ACCESS_FAULT:
293295041Sbr		data_abort(frame, 0);
294295041Sbr		break;
295295893Sbr	case EXCP_INSTR_BREAKPOINT:
296300618Sbr#ifdef KDTRACE_HOOKS
297300618Sbr		if (dtrace_invop_jump_addr != 0) {
298300618Sbr			dtrace_invop_jump_addr(frame);
299300618Sbr			break;
300300618Sbr		}
301300618Sbr#endif
302295893Sbr#ifdef KDB
303295893Sbr		kdb_trap(exception, 0, frame);
304295893Sbr#else
305295893Sbr		dump_regs(frame);
306295893Sbr		panic("No debugger in kernel.\n");
307295893Sbr#endif
308296614Sbr		break;
309295893Sbr	case EXCP_INSTR_ILLEGAL:
310295893Sbr		dump_regs(frame);
311300618Sbr		panic("Illegal instruction at 0x%016lx\n", frame->tf_sepc);
312295893Sbr		break;
313295041Sbr	default:
314295041Sbr		dump_regs(frame);
315295041Sbr		panic("Unknown kernel exception %x badaddr %lx\n",
316295041Sbr			exception, frame->tf_sbadaddr);
317295041Sbr	}
318295041Sbr}
319295041Sbr
320295041Sbrvoid
321295041Sbrdo_trap_user(struct trapframe *frame)
322295041Sbr{
323295041Sbr	uint64_t exception;
324295893Sbr	struct thread *td;
325295041Sbr
326295893Sbr	td = curthread;
327295893Sbr	td->td_frame = frame;
328295893Sbr
329295041Sbr	exception = (frame->tf_scause & EXCP_MASK);
330295041Sbr	if (frame->tf_scause & EXCP_INTR) {
331295041Sbr		/* Interrupt */
332295041Sbr		riscv_cpu_intr(frame);
333295041Sbr		return;
334295041Sbr	}
335295041Sbr
336295041Sbr	CTR3(KTR_TRAP, "do_trap_user: curthread: %p, sepc: %lx, frame: %p",
337295041Sbr	    curthread, frame->tf_sepc, frame);
338295041Sbr
339295041Sbr	switch(exception) {
340295041Sbr	case EXCP_LOAD_ACCESS_FAULT:
341295041Sbr	case EXCP_STORE_ACCESS_FAULT:
342295041Sbr	case EXCP_INSTR_ACCESS_FAULT:
343295041Sbr		data_abort(frame, 1);
344295041Sbr		break;
345295041Sbr	case EXCP_UMODE_ENV_CALL:
346295041Sbr		frame->tf_sepc += 4;	/* Next instruction */
347295041Sbr		svc_handler(frame);
348295041Sbr		break;
349295893Sbr	case EXCP_INSTR_ILLEGAL:
350295893Sbr		call_trapsignal(td, SIGILL, ILL_ILLTRP, (void *)frame->tf_sepc);
351295893Sbr		userret(td, frame);
352295893Sbr		break;
353295893Sbr	case EXCP_INSTR_BREAKPOINT:
354295893Sbr		call_trapsignal(td, SIGTRAP, TRAP_BRKPT, (void *)frame->tf_sepc);
355295893Sbr		userret(td, frame);
356295893Sbr		break;
357295041Sbr	default:
358295041Sbr		dump_regs(frame);
359295041Sbr		panic("Unknown userland exception %x badaddr %lx\n",
360295041Sbr			exception, frame->tf_sbadaddr);
361295041Sbr	}
362295041Sbr}
363