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: stable/11/sys/riscv/riscv/trap.c 321343 2017-07-21 18:06:57Z kib $"); 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#ifdef KDB 50#include <sys/kdb.h> 51#endif 52 53#include <vm/vm.h> 54#include <vm/pmap.h> 55#include <vm/vm_kern.h> 56#include <vm/vm_map.h> 57#include <vm/vm_param.h> 58#include <vm/vm_extern.h> 59 60#include <machine/frame.h> 61#include <machine/pcb.h> 62#include <machine/pcpu.h> 63 64#include <machine/resource.h> 65#include <machine/intr.h> 66 67#ifdef KDTRACE_HOOKS 68#include <sys/dtrace_bsd.h> 69#endif 70 71int (*dtrace_invop_jump_addr)(struct trapframe *); 72 73extern register_t fsu_intr_fault; 74 75/* Called from exception.S */ 76void do_trap_supervisor(struct trapframe *); 77void do_trap_user(struct trapframe *); 78 79static __inline void 80call_trapsignal(struct thread *td, int sig, int code, void *addr) 81{ 82 ksiginfo_t ksi; 83 84 ksiginfo_init_trap(&ksi); 85 ksi.ksi_signo = sig; 86 ksi.ksi_code = code; 87 ksi.ksi_addr = addr; 88 trapsignal(td, &ksi); 89} 90 91int 92cpu_fetch_syscall_args(struct thread *td) 93{ 94 struct proc *p; 95 register_t *ap; 96 struct syscall_args *sa; 97 int nap; 98 99 nap = 8; 100 p = td->td_proc; 101 sa = &td->td_sa; 102 ap = &td->td_frame->tf_a[0]; 103 104 sa->code = td->td_frame->tf_t[0]; 105 106 if (sa->code == SYS_syscall || sa->code == SYS___syscall) { 107 sa->code = *ap++; 108 nap--; 109 } 110 111 if (p->p_sysent->sv_mask) 112 sa->code &= p->p_sysent->sv_mask; 113 if (sa->code >= p->p_sysent->sv_size) 114 sa->callp = &p->p_sysent->sv_table[0]; 115 else 116 sa->callp = &p->p_sysent->sv_table[sa->code]; 117 118 sa->narg = sa->callp->sy_narg; 119 memcpy(sa->args, ap, nap * sizeof(register_t)); 120 if (sa->narg > nap) 121 panic("TODO: Could we have more then 8 args?"); 122 123 td->td_retval[0] = 0; 124 td->td_retval[1] = 0; 125 126 return (0); 127} 128 129#include "../../kern/subr_syscall.c" 130 131static void 132dump_regs(struct trapframe *frame) 133{ 134 int n; 135 int i; 136 137 n = (sizeof(frame->tf_t) / sizeof(frame->tf_t[0])); 138 for (i = 0; i < n; i++) 139 printf("t[%d] == 0x%016lx\n", i, frame->tf_t[i]); 140 141 n = (sizeof(frame->tf_s) / sizeof(frame->tf_s[0])); 142 for (i = 0; i < n; i++) 143 printf("s[%d] == 0x%016lx\n", i, frame->tf_s[i]); 144 145 n = (sizeof(frame->tf_a) / sizeof(frame->tf_a[0])); 146 for (i = 0; i < n; i++) 147 printf("a[%d] == 0x%016lx\n", i, frame->tf_a[i]); 148 149 printf("sepc == 0x%016lx\n", frame->tf_sepc); 150 printf("sstatus == 0x%016lx\n", frame->tf_sstatus); 151} 152 153static void 154svc_handler(struct trapframe *frame) 155{ 156 struct thread *td; 157 int error; 158 159 td = curthread; 160 td->td_frame = frame; 161 162 error = syscallenter(td); 163 syscallret(td, error); 164} 165 166static void 167data_abort(struct trapframe *frame, int lower) 168{ 169 struct vm_map *map; 170 uint64_t sbadaddr; 171 struct thread *td; 172 struct pcb *pcb; 173 vm_prot_t ftype; 174 vm_offset_t va; 175 struct proc *p; 176 int ucode; 177 int error; 178 int sig; 179 180#ifdef KDB 181 if (kdb_active) { 182 kdb_reenter(); 183 return; 184 } 185#endif 186 187 td = curthread; 188 pcb = td->td_pcb; 189 190 /* 191 * Special case for fuswintr and suswintr. These can't sleep so 192 * handle them early on in the trap handler. 193 */ 194 if (__predict_false(pcb->pcb_onfault == (vm_offset_t)&fsu_intr_fault)) { 195 frame->tf_sepc = pcb->pcb_onfault; 196 return; 197 } 198 199 sbadaddr = frame->tf_sbadaddr; 200 201 p = td->td_proc; 202 203 if (lower) 204 map = &td->td_proc->p_vmspace->vm_map; 205 else { 206 /* The top bit tells us which range to use */ 207 if ((sbadaddr >> 63) == 1) 208 map = kernel_map; 209 else 210 map = &td->td_proc->p_vmspace->vm_map; 211 } 212 213 va = trunc_page(sbadaddr); 214 215 if (frame->tf_scause == EXCP_STORE_ACCESS_FAULT) { 216 ftype = (VM_PROT_READ | VM_PROT_WRITE); 217 } else { 218 ftype = (VM_PROT_READ); 219 } 220 221 if (map != kernel_map) { 222 /* 223 * Keep swapout from messing with us during this 224 * critical time. 225 */ 226 PROC_LOCK(p); 227 ++p->p_lock; 228 PROC_UNLOCK(p); 229 230 /* Fault in the user page: */ 231 error = vm_fault(map, va, ftype, VM_FAULT_NORMAL); 232 233 PROC_LOCK(p); 234 --p->p_lock; 235 PROC_UNLOCK(p); 236 } else { 237 /* 238 * Don't have to worry about process locking or stacks in the 239 * kernel. 240 */ 241 error = vm_fault(map, va, ftype, VM_FAULT_NORMAL); 242 } 243 244 if (error != KERN_SUCCESS) { 245 if (lower) { 246 sig = SIGSEGV; 247 if (error == KERN_PROTECTION_FAILURE) 248 ucode = SEGV_ACCERR; 249 else 250 ucode = SEGV_MAPERR; 251 call_trapsignal(td, sig, ucode, (void *)sbadaddr); 252 } else { 253 if (td->td_intr_nesting_level == 0 && 254 pcb->pcb_onfault != 0) { 255 frame->tf_a[0] = error; 256 frame->tf_sepc = pcb->pcb_onfault; 257 return; 258 } 259 dump_regs(frame); 260 panic("vm_fault failed: %lx, va 0x%016lx", 261 frame->tf_sepc, sbadaddr); 262 } 263 } 264 265 if (lower) 266 userret(td, frame); 267} 268 269void 270do_trap_supervisor(struct trapframe *frame) 271{ 272 uint64_t exception; 273 274 exception = (frame->tf_scause & EXCP_MASK); 275 if (frame->tf_scause & EXCP_INTR) { 276 /* Interrupt */ 277 riscv_cpu_intr(frame); 278 return; 279 } 280 281#ifdef KDTRACE_HOOKS 282 if (dtrace_trap_func != NULL && (*dtrace_trap_func)(frame, exception)) 283 return; 284#endif 285 286 CTR3(KTR_TRAP, "do_trap_supervisor: curthread: %p, sepc: %lx, frame: %p", 287 curthread, frame->tf_sepc, frame); 288 289 switch(exception) { 290 case EXCP_LOAD_ACCESS_FAULT: 291 case EXCP_STORE_ACCESS_FAULT: 292 case EXCP_INSTR_ACCESS_FAULT: 293 data_abort(frame, 0); 294 break; 295 case EXCP_INSTR_BREAKPOINT: 296#ifdef KDTRACE_HOOKS 297 if (dtrace_invop_jump_addr != 0) { 298 dtrace_invop_jump_addr(frame); 299 break; 300 } 301#endif 302#ifdef KDB 303 kdb_trap(exception, 0, frame); 304#else 305 dump_regs(frame); 306 panic("No debugger in kernel.\n"); 307#endif 308 break; 309 case EXCP_INSTR_ILLEGAL: 310 dump_regs(frame); 311 panic("Illegal instruction at 0x%016lx\n", frame->tf_sepc); 312 break; 313 default: 314 dump_regs(frame); 315 panic("Unknown kernel exception %x badaddr %lx\n", 316 exception, frame->tf_sbadaddr); 317 } 318} 319 320void 321do_trap_user(struct trapframe *frame) 322{ 323 uint64_t exception; 324 struct thread *td; 325 326 td = curthread; 327 td->td_frame = frame; 328 329 exception = (frame->tf_scause & EXCP_MASK); 330 if (frame->tf_scause & EXCP_INTR) { 331 /* Interrupt */ 332 riscv_cpu_intr(frame); 333 return; 334 } 335 336 CTR3(KTR_TRAP, "do_trap_user: curthread: %p, sepc: %lx, frame: %p", 337 curthread, frame->tf_sepc, frame); 338 339 switch(exception) { 340 case EXCP_LOAD_ACCESS_FAULT: 341 case EXCP_STORE_ACCESS_FAULT: 342 case EXCP_INSTR_ACCESS_FAULT: 343 data_abort(frame, 1); 344 break; 345 case EXCP_UMODE_ENV_CALL: 346 frame->tf_sepc += 4; /* Next instruction */ 347 svc_handler(frame); 348 break; 349 case EXCP_INSTR_ILLEGAL: 350 call_trapsignal(td, SIGILL, ILL_ILLTRP, (void *)frame->tf_sepc); 351 userret(td, frame); 352 break; 353 case EXCP_INSTR_BREAKPOINT: 354 call_trapsignal(td, SIGTRAP, TRAP_BRKPT, (void *)frame->tf_sepc); 355 userret(td, frame); 356 break; 357 default: 358 dump_regs(frame); 359 panic("Unknown userland exception %x badaddr %lx\n", 360 exception, frame->tf_sbadaddr); 361 } 362} 363