trap.c revision 295041
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 295041 2016-01-29 15:12:31Z 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#include <machine/vmparam.h> 61295041Sbr 62295041Sbr#include <machine/resource.h> 63295041Sbr#include <machine/intr.h> 64295041Sbr 65295041Sbrextern register_t fsu_intr_fault; 66295041Sbr 67295041Sbr/* Called from exception.S */ 68295041Sbrvoid do_trap_supervisor(struct trapframe *); 69295041Sbrvoid do_trap_user(struct trapframe *); 70295041Sbr 71295041Sbrstatic __inline void 72295041Sbrcall_trapsignal(struct thread *td, int sig, int code, void *addr) 73295041Sbr{ 74295041Sbr ksiginfo_t ksi; 75295041Sbr 76295041Sbr ksiginfo_init_trap(&ksi); 77295041Sbr ksi.ksi_signo = sig; 78295041Sbr ksi.ksi_code = code; 79295041Sbr ksi.ksi_addr = addr; 80295041Sbr trapsignal(td, &ksi); 81295041Sbr} 82295041Sbr 83295041Sbrint 84295041Sbrcpu_fetch_syscall_args(struct thread *td, struct syscall_args *sa) 85295041Sbr{ 86295041Sbr struct proc *p; 87295041Sbr register_t *ap; 88295041Sbr int nap; 89295041Sbr 90295041Sbr nap = 8; 91295041Sbr p = td->td_proc; 92295041Sbr ap = &td->td_frame->tf_a[0]; 93295041Sbr 94295041Sbr sa->code = td->td_frame->tf_t[0]; 95295041Sbr 96295041Sbr if (sa->code == SYS_syscall || sa->code == SYS___syscall) { 97295041Sbr sa->code = *ap++; 98295041Sbr nap--; 99295041Sbr } 100295041Sbr 101295041Sbr if (p->p_sysent->sv_mask) 102295041Sbr sa->code &= p->p_sysent->sv_mask; 103295041Sbr if (sa->code >= p->p_sysent->sv_size) 104295041Sbr sa->callp = &p->p_sysent->sv_table[0]; 105295041Sbr else 106295041Sbr sa->callp = &p->p_sysent->sv_table[sa->code]; 107295041Sbr 108295041Sbr sa->narg = sa->callp->sy_narg; 109295041Sbr memcpy(sa->args, ap, nap * sizeof(register_t)); 110295041Sbr if (sa->narg > nap) 111295041Sbr panic("TODO: Could we have more then 8 args?"); 112295041Sbr 113295041Sbr td->td_retval[0] = 0; 114295041Sbr td->td_retval[1] = 0; 115295041Sbr 116295041Sbr return (0); 117295041Sbr} 118295041Sbr 119295041Sbr#include "../../kern/subr_syscall.c" 120295041Sbr 121295041Sbrstatic void 122295041Sbrdump_regs(struct trapframe *frame) 123295041Sbr{ 124295041Sbr int n; 125295041Sbr int i; 126295041Sbr 127295041Sbr n = (sizeof(frame->tf_t) / sizeof(frame->tf_t[0])); 128295041Sbr for (i = 0; i < n; i++) 129295041Sbr printf("t[%d] == 0x%016lx\n", i, frame->tf_t[i]); 130295041Sbr 131295041Sbr n = (sizeof(frame->tf_s) / sizeof(frame->tf_s[0])); 132295041Sbr for (i = 0; i < n; i++) 133295041Sbr printf("s[%d] == 0x%016lx\n", i, frame->tf_s[i]); 134295041Sbr 135295041Sbr n = (sizeof(frame->tf_a) / sizeof(frame->tf_a[0])); 136295041Sbr for (i = 0; i < n; i++) 137295041Sbr printf("a[%d] == 0x%016lx\n", i, frame->tf_a[i]); 138295041Sbr 139295041Sbr printf("sepc == 0x%016lx\n", frame->tf_sepc); 140295041Sbr printf("sstatus == 0x%016lx\n", frame->tf_sstatus); 141295041Sbr} 142295041Sbr 143295041Sbrstatic void 144295041Sbrsvc_handler(struct trapframe *frame) 145295041Sbr{ 146295041Sbr struct syscall_args sa; 147295041Sbr struct thread *td; 148295041Sbr int error; 149295041Sbr 150295041Sbr td = curthread; 151295041Sbr td->td_frame = frame; 152295041Sbr 153295041Sbr error = syscallenter(td, &sa); 154295041Sbr syscallret(td, error, &sa); 155295041Sbr} 156295041Sbr 157295041Sbrstatic void 158295041Sbrdata_abort(struct trapframe *frame, int lower) 159295041Sbr{ 160295041Sbr struct vm_map *map; 161295041Sbr uint64_t sbadaddr; 162295041Sbr struct thread *td; 163295041Sbr struct pcb *pcb; 164295041Sbr vm_prot_t ftype; 165295041Sbr vm_offset_t va; 166295041Sbr struct proc *p; 167295041Sbr int ucode; 168295041Sbr int error; 169295041Sbr int sig; 170295041Sbr 171295041Sbr td = curthread; 172295041Sbr pcb = td->td_pcb; 173295041Sbr 174295041Sbr /* 175295041Sbr * Special case for fuswintr and suswintr. These can't sleep so 176295041Sbr * handle them early on in the trap handler. 177295041Sbr */ 178295041Sbr if (__predict_false(pcb->pcb_onfault == (vm_offset_t)&fsu_intr_fault)) { 179295041Sbr frame->tf_sepc = pcb->pcb_onfault; 180295041Sbr return; 181295041Sbr } 182295041Sbr 183295041Sbr sbadaddr = frame->tf_sbadaddr; 184295041Sbr 185295041Sbr p = td->td_proc; 186295041Sbr 187295041Sbr if (lower) 188295041Sbr map = &td->td_proc->p_vmspace->vm_map; 189295041Sbr else { 190295041Sbr /* The top bit tells us which range to use */ 191295041Sbr if ((sbadaddr >> 63) == 1) 192295041Sbr map = kernel_map; 193295041Sbr else 194295041Sbr map = &td->td_proc->p_vmspace->vm_map; 195295041Sbr } 196295041Sbr 197295041Sbr va = trunc_page(sbadaddr); 198295041Sbr 199295041Sbr if (frame->tf_scause == EXCP_STORE_ACCESS_FAULT) { 200295041Sbr ftype = (VM_PROT_READ | VM_PROT_WRITE); 201295041Sbr } else { 202295041Sbr ftype = (VM_PROT_READ); 203295041Sbr } 204295041Sbr 205295041Sbr if (map != kernel_map) { 206295041Sbr /* 207295041Sbr * Keep swapout from messing with us during this 208295041Sbr * critical time. 209295041Sbr */ 210295041Sbr PROC_LOCK(p); 211295041Sbr ++p->p_lock; 212295041Sbr PROC_UNLOCK(p); 213295041Sbr 214295041Sbr /* Fault in the user page: */ 215295041Sbr error = vm_fault(map, va, ftype, VM_FAULT_NORMAL); 216295041Sbr 217295041Sbr PROC_LOCK(p); 218295041Sbr --p->p_lock; 219295041Sbr PROC_UNLOCK(p); 220295041Sbr } else { 221295041Sbr /* 222295041Sbr * Don't have to worry about process locking or stacks in the 223295041Sbr * kernel. 224295041Sbr */ 225295041Sbr error = vm_fault(map, va, ftype, VM_FAULT_NORMAL); 226295041Sbr } 227295041Sbr 228295041Sbr if (error != KERN_SUCCESS) { 229295041Sbr if (lower) { 230295041Sbr sig = SIGSEGV; 231295041Sbr if (error == KERN_PROTECTION_FAILURE) 232295041Sbr ucode = SEGV_ACCERR; 233295041Sbr else 234295041Sbr ucode = SEGV_MAPERR; 235295041Sbr call_trapsignal(td, sig, ucode, (void *)sbadaddr); 236295041Sbr } else { 237295041Sbr if (td->td_intr_nesting_level == 0 && 238295041Sbr pcb->pcb_onfault != 0) { 239295041Sbr frame->tf_a[0] = error; 240295041Sbr frame->tf_sepc = pcb->pcb_onfault; 241295041Sbr return; 242295041Sbr } 243295041Sbr dump_regs(frame); 244295041Sbr panic("vm_fault failed: %lx, va 0x%016lx", 245295041Sbr frame->tf_sepc, sbadaddr); 246295041Sbr } 247295041Sbr } 248295041Sbr 249295041Sbr if (lower) 250295041Sbr userret(td, frame); 251295041Sbr} 252295041Sbr 253295041Sbrvoid 254295041Sbrdo_trap_supervisor(struct trapframe *frame) 255295041Sbr{ 256295041Sbr uint64_t exception; 257295041Sbr 258295041Sbr exception = (frame->tf_scause & EXCP_MASK); 259295041Sbr if (frame->tf_scause & EXCP_INTR) { 260295041Sbr /* Interrupt */ 261295041Sbr riscv_cpu_intr(frame); 262295041Sbr return; 263295041Sbr } 264295041Sbr 265295041Sbr CTR3(KTR_TRAP, "do_trap_supervisor: curthread: %p, sepc: %lx, frame: %p", 266295041Sbr curthread, frame->tf_sepc, frame); 267295041Sbr 268295041Sbr switch(exception) { 269295041Sbr case EXCP_LOAD_ACCESS_FAULT: 270295041Sbr case EXCP_STORE_ACCESS_FAULT: 271295041Sbr case EXCP_INSTR_ACCESS_FAULT: 272295041Sbr data_abort(frame, 0); 273295041Sbr break; 274295041Sbr default: 275295041Sbr dump_regs(frame); 276295041Sbr panic("Unknown kernel exception %x badaddr %lx\n", 277295041Sbr exception, frame->tf_sbadaddr); 278295041Sbr } 279295041Sbr} 280295041Sbr 281295041Sbrvoid 282295041Sbrdo_trap_user(struct trapframe *frame) 283295041Sbr{ 284295041Sbr uint64_t exception; 285295041Sbr 286295041Sbr exception = (frame->tf_scause & EXCP_MASK); 287295041Sbr if (frame->tf_scause & EXCP_INTR) { 288295041Sbr /* Interrupt */ 289295041Sbr riscv_cpu_intr(frame); 290295041Sbr return; 291295041Sbr } 292295041Sbr 293295041Sbr CTR3(KTR_TRAP, "do_trap_user: curthread: %p, sepc: %lx, frame: %p", 294295041Sbr curthread, frame->tf_sepc, frame); 295295041Sbr 296295041Sbr switch(exception) { 297295041Sbr case EXCP_LOAD_ACCESS_FAULT: 298295041Sbr case EXCP_STORE_ACCESS_FAULT: 299295041Sbr case EXCP_INSTR_ACCESS_FAULT: 300295041Sbr data_abort(frame, 1); 301295041Sbr break; 302295041Sbr case EXCP_UMODE_ENV_CALL: 303295041Sbr frame->tf_sepc += 4; /* Next instruction */ 304295041Sbr svc_handler(frame); 305295041Sbr break; 306295041Sbr default: 307295041Sbr dump_regs(frame); 308295041Sbr panic("Unknown userland exception %x badaddr %lx\n", 309295041Sbr exception, frame->tf_sbadaddr); 310295041Sbr } 311295041Sbr} 312