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