trap.c revision 295041
1/*- 2 * Copyright (c) 2015 Ruslan Bukin <br@bsdpad.com> 3 * All rights reserved. 4 * 5 * Portions of this software were developed by SRI International and the 6 * University of Cambridge Computer Laboratory under DARPA/AFRL contract 7 * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme. 8 * 9 * Portions of this software were developed by the University of Cambridge 10 * Computer Laboratory as part of the CTSRD Project, with support from the 11 * UK Higher Education Innovation Fund (HEIF). 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35#include <sys/cdefs.h> 36__FBSDID("$FreeBSD: head/sys/riscv/riscv/trap.c 295041 2016-01-29 15:12:31Z br $"); 37 38#include <sys/param.h> 39#include <sys/systm.h> 40#include <sys/kernel.h> 41#include <sys/lock.h> 42#include <sys/mutex.h> 43#include <sys/pioctl.h> 44#include <sys/bus.h> 45#include <sys/proc.h> 46#include <sys/ptrace.h> 47#include <sys/syscall.h> 48#include <sys/sysent.h> 49 50#include <vm/vm.h> 51#include <vm/pmap.h> 52#include <vm/vm_kern.h> 53#include <vm/vm_map.h> 54#include <vm/vm_param.h> 55#include <vm/vm_extern.h> 56 57#include <machine/frame.h> 58#include <machine/pcb.h> 59#include <machine/pcpu.h> 60#include <machine/vmparam.h> 61 62#include <machine/resource.h> 63#include <machine/intr.h> 64 65extern register_t fsu_intr_fault; 66 67/* Called from exception.S */ 68void do_trap_supervisor(struct trapframe *); 69void do_trap_user(struct trapframe *); 70 71static __inline void 72call_trapsignal(struct thread *td, int sig, int code, void *addr) 73{ 74 ksiginfo_t ksi; 75 76 ksiginfo_init_trap(&ksi); 77 ksi.ksi_signo = sig; 78 ksi.ksi_code = code; 79 ksi.ksi_addr = addr; 80 trapsignal(td, &ksi); 81} 82 83int 84cpu_fetch_syscall_args(struct thread *td, struct syscall_args *sa) 85{ 86 struct proc *p; 87 register_t *ap; 88 int nap; 89 90 nap = 8; 91 p = td->td_proc; 92 ap = &td->td_frame->tf_a[0]; 93 94 sa->code = td->td_frame->tf_t[0]; 95 96 if (sa->code == SYS_syscall || sa->code == SYS___syscall) { 97 sa->code = *ap++; 98 nap--; 99 } 100 101 if (p->p_sysent->sv_mask) 102 sa->code &= p->p_sysent->sv_mask; 103 if (sa->code >= p->p_sysent->sv_size) 104 sa->callp = &p->p_sysent->sv_table[0]; 105 else 106 sa->callp = &p->p_sysent->sv_table[sa->code]; 107 108 sa->narg = sa->callp->sy_narg; 109 memcpy(sa->args, ap, nap * sizeof(register_t)); 110 if (sa->narg > nap) 111 panic("TODO: Could we have more then 8 args?"); 112 113 td->td_retval[0] = 0; 114 td->td_retval[1] = 0; 115 116 return (0); 117} 118 119#include "../../kern/subr_syscall.c" 120 121static void 122dump_regs(struct trapframe *frame) 123{ 124 int n; 125 int i; 126 127 n = (sizeof(frame->tf_t) / sizeof(frame->tf_t[0])); 128 for (i = 0; i < n; i++) 129 printf("t[%d] == 0x%016lx\n", i, frame->tf_t[i]); 130 131 n = (sizeof(frame->tf_s) / sizeof(frame->tf_s[0])); 132 for (i = 0; i < n; i++) 133 printf("s[%d] == 0x%016lx\n", i, frame->tf_s[i]); 134 135 n = (sizeof(frame->tf_a) / sizeof(frame->tf_a[0])); 136 for (i = 0; i < n; i++) 137 printf("a[%d] == 0x%016lx\n", i, frame->tf_a[i]); 138 139 printf("sepc == 0x%016lx\n", frame->tf_sepc); 140 printf("sstatus == 0x%016lx\n", frame->tf_sstatus); 141} 142 143static void 144svc_handler(struct trapframe *frame) 145{ 146 struct syscall_args sa; 147 struct thread *td; 148 int error; 149 150 td = curthread; 151 td->td_frame = frame; 152 153 error = syscallenter(td, &sa); 154 syscallret(td, error, &sa); 155} 156 157static void 158data_abort(struct trapframe *frame, int lower) 159{ 160 struct vm_map *map; 161 uint64_t sbadaddr; 162 struct thread *td; 163 struct pcb *pcb; 164 vm_prot_t ftype; 165 vm_offset_t va; 166 struct proc *p; 167 int ucode; 168 int error; 169 int sig; 170 171 td = curthread; 172 pcb = td->td_pcb; 173 174 /* 175 * Special case for fuswintr and suswintr. These can't sleep so 176 * handle them early on in the trap handler. 177 */ 178 if (__predict_false(pcb->pcb_onfault == (vm_offset_t)&fsu_intr_fault)) { 179 frame->tf_sepc = pcb->pcb_onfault; 180 return; 181 } 182 183 sbadaddr = frame->tf_sbadaddr; 184 185 p = td->td_proc; 186 187 if (lower) 188 map = &td->td_proc->p_vmspace->vm_map; 189 else { 190 /* The top bit tells us which range to use */ 191 if ((sbadaddr >> 63) == 1) 192 map = kernel_map; 193 else 194 map = &td->td_proc->p_vmspace->vm_map; 195 } 196 197 va = trunc_page(sbadaddr); 198 199 if (frame->tf_scause == EXCP_STORE_ACCESS_FAULT) { 200 ftype = (VM_PROT_READ | VM_PROT_WRITE); 201 } else { 202 ftype = (VM_PROT_READ); 203 } 204 205 if (map != kernel_map) { 206 /* 207 * Keep swapout from messing with us during this 208 * critical time. 209 */ 210 PROC_LOCK(p); 211 ++p->p_lock; 212 PROC_UNLOCK(p); 213 214 /* Fault in the user page: */ 215 error = vm_fault(map, va, ftype, VM_FAULT_NORMAL); 216 217 PROC_LOCK(p); 218 --p->p_lock; 219 PROC_UNLOCK(p); 220 } else { 221 /* 222 * Don't have to worry about process locking or stacks in the 223 * kernel. 224 */ 225 error = vm_fault(map, va, ftype, VM_FAULT_NORMAL); 226 } 227 228 if (error != KERN_SUCCESS) { 229 if (lower) { 230 sig = SIGSEGV; 231 if (error == KERN_PROTECTION_FAILURE) 232 ucode = SEGV_ACCERR; 233 else 234 ucode = SEGV_MAPERR; 235 call_trapsignal(td, sig, ucode, (void *)sbadaddr); 236 } else { 237 if (td->td_intr_nesting_level == 0 && 238 pcb->pcb_onfault != 0) { 239 frame->tf_a[0] = error; 240 frame->tf_sepc = pcb->pcb_onfault; 241 return; 242 } 243 dump_regs(frame); 244 panic("vm_fault failed: %lx, va 0x%016lx", 245 frame->tf_sepc, sbadaddr); 246 } 247 } 248 249 if (lower) 250 userret(td, frame); 251} 252 253void 254do_trap_supervisor(struct trapframe *frame) 255{ 256 uint64_t exception; 257 258 exception = (frame->tf_scause & EXCP_MASK); 259 if (frame->tf_scause & EXCP_INTR) { 260 /* Interrupt */ 261 riscv_cpu_intr(frame); 262 return; 263 } 264 265 CTR3(KTR_TRAP, "do_trap_supervisor: curthread: %p, sepc: %lx, frame: %p", 266 curthread, frame->tf_sepc, frame); 267 268 switch(exception) { 269 case EXCP_LOAD_ACCESS_FAULT: 270 case EXCP_STORE_ACCESS_FAULT: 271 case EXCP_INSTR_ACCESS_FAULT: 272 data_abort(frame, 0); 273 break; 274 default: 275 dump_regs(frame); 276 panic("Unknown kernel exception %x badaddr %lx\n", 277 exception, frame->tf_sbadaddr); 278 } 279} 280 281void 282do_trap_user(struct trapframe *frame) 283{ 284 uint64_t exception; 285 286 exception = (frame->tf_scause & EXCP_MASK); 287 if (frame->tf_scause & EXCP_INTR) { 288 /* Interrupt */ 289 riscv_cpu_intr(frame); 290 return; 291 } 292 293 CTR3(KTR_TRAP, "do_trap_user: curthread: %p, sepc: %lx, frame: %p", 294 curthread, frame->tf_sepc, frame); 295 296 switch(exception) { 297 case EXCP_LOAD_ACCESS_FAULT: 298 case EXCP_STORE_ACCESS_FAULT: 299 case EXCP_INSTR_ACCESS_FAULT: 300 data_abort(frame, 1); 301 break; 302 case EXCP_UMODE_ENV_CALL: 303 frame->tf_sepc += 4; /* Next instruction */ 304 svc_handler(frame); 305 break; 306 default: 307 dump_regs(frame); 308 panic("Unknown userland exception %x badaddr %lx\n", 309 exception, frame->tf_sbadaddr); 310 } 311} 312