trap.c revision 296614
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 296614 2016-03-10 15:51:43Z 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 67295041Sbrextern register_t fsu_intr_fault; 68295041Sbr 69295041Sbr/* Called from exception.S */ 70295041Sbrvoid do_trap_supervisor(struct trapframe *); 71295041Sbrvoid do_trap_user(struct trapframe *); 72295041Sbr 73295041Sbrstatic __inline void 74295041Sbrcall_trapsignal(struct thread *td, int sig, int code, void *addr) 75295041Sbr{ 76295041Sbr ksiginfo_t ksi; 77295041Sbr 78295041Sbr ksiginfo_init_trap(&ksi); 79295041Sbr ksi.ksi_signo = sig; 80295041Sbr ksi.ksi_code = code; 81295041Sbr ksi.ksi_addr = addr; 82295041Sbr trapsignal(td, &ksi); 83295041Sbr} 84295041Sbr 85295041Sbrint 86295041Sbrcpu_fetch_syscall_args(struct thread *td, struct syscall_args *sa) 87295041Sbr{ 88295041Sbr struct proc *p; 89295041Sbr register_t *ap; 90295041Sbr int nap; 91295041Sbr 92295041Sbr nap = 8; 93295041Sbr p = td->td_proc; 94295041Sbr ap = &td->td_frame->tf_a[0]; 95295041Sbr 96295041Sbr sa->code = td->td_frame->tf_t[0]; 97295041Sbr 98295041Sbr if (sa->code == SYS_syscall || sa->code == SYS___syscall) { 99295041Sbr sa->code = *ap++; 100295041Sbr nap--; 101295041Sbr } 102295041Sbr 103295041Sbr if (p->p_sysent->sv_mask) 104295041Sbr sa->code &= p->p_sysent->sv_mask; 105295041Sbr if (sa->code >= p->p_sysent->sv_size) 106295041Sbr sa->callp = &p->p_sysent->sv_table[0]; 107295041Sbr else 108295041Sbr sa->callp = &p->p_sysent->sv_table[sa->code]; 109295041Sbr 110295041Sbr sa->narg = sa->callp->sy_narg; 111295041Sbr memcpy(sa->args, ap, nap * sizeof(register_t)); 112295041Sbr if (sa->narg > nap) 113295041Sbr panic("TODO: Could we have more then 8 args?"); 114295041Sbr 115295041Sbr td->td_retval[0] = 0; 116295041Sbr td->td_retval[1] = 0; 117295041Sbr 118295041Sbr return (0); 119295041Sbr} 120295041Sbr 121295041Sbr#include "../../kern/subr_syscall.c" 122295041Sbr 123295041Sbrstatic void 124295041Sbrdump_regs(struct trapframe *frame) 125295041Sbr{ 126295041Sbr int n; 127295041Sbr int i; 128295041Sbr 129295041Sbr n = (sizeof(frame->tf_t) / sizeof(frame->tf_t[0])); 130295041Sbr for (i = 0; i < n; i++) 131295041Sbr printf("t[%d] == 0x%016lx\n", i, frame->tf_t[i]); 132295041Sbr 133295041Sbr n = (sizeof(frame->tf_s) / sizeof(frame->tf_s[0])); 134295041Sbr for (i = 0; i < n; i++) 135295041Sbr printf("s[%d] == 0x%016lx\n", i, frame->tf_s[i]); 136295041Sbr 137295041Sbr n = (sizeof(frame->tf_a) / sizeof(frame->tf_a[0])); 138295041Sbr for (i = 0; i < n; i++) 139295041Sbr printf("a[%d] == 0x%016lx\n", i, frame->tf_a[i]); 140295041Sbr 141295041Sbr printf("sepc == 0x%016lx\n", frame->tf_sepc); 142295041Sbr printf("sstatus == 0x%016lx\n", frame->tf_sstatus); 143295041Sbr} 144295041Sbr 145295041Sbrstatic void 146295041Sbrsvc_handler(struct trapframe *frame) 147295041Sbr{ 148295041Sbr struct syscall_args sa; 149295041Sbr struct thread *td; 150295041Sbr int error; 151295041Sbr 152295041Sbr td = curthread; 153295041Sbr td->td_frame = frame; 154295041Sbr 155295041Sbr error = syscallenter(td, &sa); 156295041Sbr syscallret(td, error, &sa); 157295041Sbr} 158295041Sbr 159295041Sbrstatic void 160295041Sbrdata_abort(struct trapframe *frame, int lower) 161295041Sbr{ 162295041Sbr struct vm_map *map; 163295041Sbr uint64_t sbadaddr; 164295041Sbr struct thread *td; 165295041Sbr struct pcb *pcb; 166295041Sbr vm_prot_t ftype; 167295041Sbr vm_offset_t va; 168295041Sbr struct proc *p; 169295041Sbr int ucode; 170295041Sbr int error; 171295041Sbr int sig; 172295041Sbr 173296614Sbr#ifdef KDB 174296614Sbr if (kdb_active) { 175296614Sbr kdb_reenter(); 176296614Sbr return; 177296614Sbr } 178296614Sbr#endif 179296614Sbr 180295041Sbr td = curthread; 181295041Sbr pcb = td->td_pcb; 182295041Sbr 183295041Sbr /* 184295041Sbr * Special case for fuswintr and suswintr. These can't sleep so 185295041Sbr * handle them early on in the trap handler. 186295041Sbr */ 187295041Sbr if (__predict_false(pcb->pcb_onfault == (vm_offset_t)&fsu_intr_fault)) { 188295041Sbr frame->tf_sepc = pcb->pcb_onfault; 189295041Sbr return; 190295041Sbr } 191295041Sbr 192295041Sbr sbadaddr = frame->tf_sbadaddr; 193295041Sbr 194295041Sbr p = td->td_proc; 195295041Sbr 196295041Sbr if (lower) 197295041Sbr map = &td->td_proc->p_vmspace->vm_map; 198295041Sbr else { 199295041Sbr /* The top bit tells us which range to use */ 200295041Sbr if ((sbadaddr >> 63) == 1) 201295041Sbr map = kernel_map; 202295041Sbr else 203295041Sbr map = &td->td_proc->p_vmspace->vm_map; 204295041Sbr } 205295041Sbr 206295041Sbr va = trunc_page(sbadaddr); 207295041Sbr 208295041Sbr if (frame->tf_scause == EXCP_STORE_ACCESS_FAULT) { 209295041Sbr ftype = (VM_PROT_READ | VM_PROT_WRITE); 210295041Sbr } else { 211295041Sbr ftype = (VM_PROT_READ); 212295041Sbr } 213295041Sbr 214295041Sbr if (map != kernel_map) { 215295041Sbr /* 216295041Sbr * Keep swapout from messing with us during this 217295041Sbr * critical time. 218295041Sbr */ 219295041Sbr PROC_LOCK(p); 220295041Sbr ++p->p_lock; 221295041Sbr PROC_UNLOCK(p); 222295041Sbr 223295041Sbr /* Fault in the user page: */ 224295041Sbr error = vm_fault(map, va, ftype, VM_FAULT_NORMAL); 225295041Sbr 226295041Sbr PROC_LOCK(p); 227295041Sbr --p->p_lock; 228295041Sbr PROC_UNLOCK(p); 229295041Sbr } else { 230295041Sbr /* 231295041Sbr * Don't have to worry about process locking or stacks in the 232295041Sbr * kernel. 233295041Sbr */ 234295041Sbr error = vm_fault(map, va, ftype, VM_FAULT_NORMAL); 235295041Sbr } 236295041Sbr 237295041Sbr if (error != KERN_SUCCESS) { 238295041Sbr if (lower) { 239295041Sbr sig = SIGSEGV; 240295041Sbr if (error == KERN_PROTECTION_FAILURE) 241295041Sbr ucode = SEGV_ACCERR; 242295041Sbr else 243295041Sbr ucode = SEGV_MAPERR; 244295041Sbr call_trapsignal(td, sig, ucode, (void *)sbadaddr); 245295041Sbr } else { 246295041Sbr if (td->td_intr_nesting_level == 0 && 247295041Sbr pcb->pcb_onfault != 0) { 248295041Sbr frame->tf_a[0] = error; 249295041Sbr frame->tf_sepc = pcb->pcb_onfault; 250295041Sbr return; 251295041Sbr } 252295041Sbr dump_regs(frame); 253295041Sbr panic("vm_fault failed: %lx, va 0x%016lx", 254295041Sbr frame->tf_sepc, sbadaddr); 255295041Sbr } 256295041Sbr } 257295041Sbr 258295041Sbr if (lower) 259295041Sbr userret(td, frame); 260295041Sbr} 261295041Sbr 262295041Sbrvoid 263295041Sbrdo_trap_supervisor(struct trapframe *frame) 264295041Sbr{ 265295041Sbr uint64_t exception; 266295041Sbr 267295041Sbr exception = (frame->tf_scause & EXCP_MASK); 268295041Sbr if (frame->tf_scause & EXCP_INTR) { 269295041Sbr /* Interrupt */ 270295041Sbr riscv_cpu_intr(frame); 271295041Sbr return; 272295041Sbr } 273295041Sbr 274295041Sbr CTR3(KTR_TRAP, "do_trap_supervisor: curthread: %p, sepc: %lx, frame: %p", 275295041Sbr curthread, frame->tf_sepc, frame); 276295041Sbr 277295041Sbr switch(exception) { 278295041Sbr case EXCP_LOAD_ACCESS_FAULT: 279295041Sbr case EXCP_STORE_ACCESS_FAULT: 280295041Sbr case EXCP_INSTR_ACCESS_FAULT: 281295041Sbr data_abort(frame, 0); 282295041Sbr break; 283295893Sbr case EXCP_INSTR_BREAKPOINT: 284295893Sbr#ifdef KDB 285295893Sbr kdb_trap(exception, 0, frame); 286295893Sbr#else 287295893Sbr dump_regs(frame); 288295893Sbr panic("No debugger in kernel.\n"); 289295893Sbr#endif 290296614Sbr break; 291295893Sbr case EXCP_INSTR_ILLEGAL: 292295893Sbr dump_regs(frame); 293295893Sbr panic("Illegal instruction at %x\n", frame->tf_sepc); 294295893Sbr break; 295295041Sbr default: 296295041Sbr dump_regs(frame); 297295041Sbr panic("Unknown kernel exception %x badaddr %lx\n", 298295041Sbr exception, frame->tf_sbadaddr); 299295041Sbr } 300295041Sbr} 301295041Sbr 302295041Sbrvoid 303295041Sbrdo_trap_user(struct trapframe *frame) 304295041Sbr{ 305295041Sbr uint64_t exception; 306295893Sbr struct thread *td; 307295041Sbr 308295893Sbr td = curthread; 309295893Sbr td->td_frame = frame; 310295893Sbr 311295041Sbr exception = (frame->tf_scause & EXCP_MASK); 312295041Sbr if (frame->tf_scause & EXCP_INTR) { 313295041Sbr /* Interrupt */ 314295041Sbr riscv_cpu_intr(frame); 315295041Sbr return; 316295041Sbr } 317295041Sbr 318295041Sbr CTR3(KTR_TRAP, "do_trap_user: curthread: %p, sepc: %lx, frame: %p", 319295041Sbr curthread, frame->tf_sepc, frame); 320295041Sbr 321295041Sbr switch(exception) { 322295041Sbr case EXCP_LOAD_ACCESS_FAULT: 323295041Sbr case EXCP_STORE_ACCESS_FAULT: 324295041Sbr case EXCP_INSTR_ACCESS_FAULT: 325295041Sbr data_abort(frame, 1); 326295041Sbr break; 327295041Sbr case EXCP_UMODE_ENV_CALL: 328295041Sbr frame->tf_sepc += 4; /* Next instruction */ 329295041Sbr svc_handler(frame); 330295041Sbr break; 331295893Sbr case EXCP_INSTR_ILLEGAL: 332295893Sbr call_trapsignal(td, SIGILL, ILL_ILLTRP, (void *)frame->tf_sepc); 333295893Sbr userret(td, frame); 334295893Sbr break; 335295893Sbr case EXCP_INSTR_BREAKPOINT: 336295893Sbr call_trapsignal(td, SIGTRAP, TRAP_BRKPT, (void *)frame->tf_sepc); 337295893Sbr userret(td, frame); 338295893Sbr break; 339295041Sbr default: 340295041Sbr dump_regs(frame); 341295041Sbr panic("Unknown userland exception %x badaddr %lx\n", 342295041Sbr exception, frame->tf_sbadaddr); 343295041Sbr } 344295041Sbr} 345