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