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