syscall.c revision 253142
1129198Scognet/* $NetBSD: fault.c,v 1.45 2003/11/20 14:44:36 scw Exp $ */ 2129198Scognet 3139735Simp/*- 4129198Scognet * Copyright 2004 Olivier Houchard 5129198Scognet * Copyright 2003 Wasabi Systems, Inc. 6129198Scognet * All rights reserved. 7129198Scognet * 8129198Scognet * Written by Steve C. Woodford for Wasabi Systems, Inc. 9129198Scognet * 10129198Scognet * Redistribution and use in source and binary forms, with or without 11129198Scognet * modification, are permitted provided that the following conditions 12129198Scognet * are met: 13129198Scognet * 1. Redistributions of source code must retain the above copyright 14129198Scognet * notice, this list of conditions and the following disclaimer. 15129198Scognet * 2. Redistributions in binary form must reproduce the above copyright 16129198Scognet * notice, this list of conditions and the following disclaimer in the 17129198Scognet * documentation and/or other materials provided with the distribution. 18129198Scognet * 3. All advertising materials mentioning features or use of this software 19129198Scognet * must display the following acknowledgement: 20129198Scognet * This product includes software developed for the NetBSD Project by 21129198Scognet * Wasabi Systems, Inc. 22129198Scognet * 4. The name of Wasabi Systems, Inc. may not be used to endorse 23129198Scognet * or promote products derived from this software without specific prior 24129198Scognet * written permission. 25129198Scognet * 26129198Scognet * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 27129198Scognet * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28129198Scognet * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29129198Scognet * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 30129198Scognet * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31129198Scognet * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32129198Scognet * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33129198Scognet * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34129198Scognet * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35129198Scognet * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36129198Scognet * POSSIBILITY OF SUCH DAMAGE. 37129198Scognet */ 38139735Simp/*- 39129198Scognet * Copyright (c) 1994-1997 Mark Brinicombe. 40129198Scognet * Copyright (c) 1994 Brini. 41129198Scognet * All rights reserved. 42129198Scognet * 43129198Scognet * This code is derived from software written for Brini by Mark Brinicombe 44129198Scognet * 45129198Scognet * Redistribution and use in source and binary forms, with or without 46129198Scognet * modification, are permitted provided that the following conditions 47129198Scognet * are met: 48129198Scognet * 1. Redistributions of source code must retain the above copyright 49129198Scognet * notice, this list of conditions and the following disclaimer. 50129198Scognet * 2. Redistributions in binary form must reproduce the above copyright 51129198Scognet * notice, this list of conditions and the following disclaimer in the 52129198Scognet * documentation and/or other materials provided with the distribution. 53129198Scognet * 3. All advertising materials mentioning features or use of this software 54129198Scognet * must display the following acknowledgement: 55129198Scognet * This product includes software developed by Brini. 56129198Scognet * 4. The name of the company nor the name of the author may be used to 57129198Scognet * endorse or promote products derived from this software without specific 58129198Scognet * prior written permission. 59129198Scognet * 60129198Scognet * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED 61129198Scognet * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 62129198Scognet * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 63129198Scognet * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 64129198Scognet * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 65129198Scognet * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 66129198Scognet * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 67129198Scognet * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 68129198Scognet * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 69129198Scognet * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 70129198Scognet * SUCH DAMAGE. 71129198Scognet * 72129198Scognet * RiscBSD kernel project 73129198Scognet * 74129198Scognet * fault.c 75129198Scognet * 76129198Scognet * Fault handlers 77129198Scognet * 78129198Scognet * Created : 28/11/94 79129198Scognet */ 80129198Scognet 81129198Scognet 82135656Scognet#include "opt_ktrace.h" 83135656Scognet 84129198Scognet#include <sys/cdefs.h> 85129198Scognet__FBSDID("$FreeBSD: head/sys/arm/arm/trap.c 253142 2013-07-10 10:15:38Z ray $"); 86129198Scognet 87129198Scognet#include <sys/param.h> 88129198Scognet#include <sys/systm.h> 89129198Scognet#include <sys/proc.h> 90129198Scognet#include <sys/kernel.h> 91129198Scognet#include <sys/lock.h> 92129198Scognet#include <sys/mutex.h> 93129198Scognet#include <sys/syscall.h> 94129198Scognet#include <sys/sysent.h> 95138328Scognet#include <sys/signalvar.h> 96138709Scognet#include <sys/ktr.h> 97135656Scognet#ifdef KTRACE 98135656Scognet#include <sys/uio.h> 99135656Scognet#include <sys/ktrace.h> 100135656Scognet#endif 101140001Scognet#include <sys/ptrace.h> 102140001Scognet#include <sys/pioctl.h> 103129198Scognet 104129198Scognet#include <vm/vm.h> 105129198Scognet#include <vm/pmap.h> 106129198Scognet#include <vm/vm_kern.h> 107129198Scognet#include <vm/vm_map.h> 108129198Scognet#include <vm/vm_extern.h> 109129198Scognet 110129198Scognet#include <machine/cpuconf.h> 111129198Scognet#include <machine/vmparam.h> 112129198Scognet#include <machine/frame.h> 113129198Scognet#include <machine/cpu.h> 114129198Scognet#include <machine/intr.h> 115138129Sdas#include <machine/pcb.h> 116129198Scognet#include <machine/proc.h> 117129198Scognet#include <machine/swi.h> 118147544Scognet 119155306Scognet#include <security/audit/audit.h> 120155306Scognet 121147544Scognet#ifdef KDB 122147544Scognet#include <sys/kdb.h> 123129198Scognet#endif 124129198Scognet 125129198Scognet 126129198Scognetvoid swi_handler(trapframe_t *); 127129198Scognetvoid undefinedinstruction(trapframe_t *); 128129198Scognet 129129198Scognet#include <machine/disassem.h> 130129198Scognet#include <machine/machdep.h> 131236991Simp 132129198Scognetextern char fusubailout[]; 133129198Scognet 134129198Scognet#ifdef DEBUG 135129198Scognetint last_fault_code; /* For the benefit of pmap_fault_fixup() */ 136129198Scognet#endif 137129198Scognet 138146619Scognet#if defined(CPU_ARM7TDMI) 139129198Scognet/* These CPUs may need data/prefetch abort fixups */ 140129198Scognet#define CPU_ABORT_FIXUP_REQUIRED 141129198Scognet#endif 142129198Scognet 143129198Scognetstruct ksig { 144129198Scognet int signb; 145129198Scognet u_long code; 146129198Scognet}; 147129198Scognetstruct data_abort { 148129198Scognet int (*func)(trapframe_t *, u_int, u_int, struct thread *, struct ksig *); 149129198Scognet const char *desc; 150129198Scognet}; 151129198Scognet 152129198Scognetstatic int dab_fatal(trapframe_t *, u_int, u_int, struct thread *, struct ksig *); 153129198Scognetstatic int dab_align(trapframe_t *, u_int, u_int, struct thread *, struct ksig *); 154129198Scognetstatic int dab_buserr(trapframe_t *, u_int, u_int, struct thread *, struct ksig *); 155129198Scognet 156129198Scognetstatic const struct data_abort data_aborts[] = { 157129198Scognet {dab_fatal, "Vector Exception"}, 158129198Scognet {dab_align, "Alignment Fault 1"}, 159129198Scognet {dab_fatal, "Terminal Exception"}, 160129198Scognet {dab_align, "Alignment Fault 3"}, 161129198Scognet {dab_buserr, "External Linefetch Abort (S)"}, 162129198Scognet {NULL, "Translation Fault (S)"}, 163250928Sgber#if (ARM_MMU_V6 + ARM_MMU_V7) != 0 164250928Sgber {NULL, "Translation Flag Fault"}, 165250928Sgber#else 166129198Scognet {dab_buserr, "External Linefetch Abort (P)"}, 167250928Sgber#endif 168129198Scognet {NULL, "Translation Fault (P)"}, 169129198Scognet {dab_buserr, "External Non-Linefetch Abort (S)"}, 170129198Scognet {NULL, "Domain Fault (S)"}, 171129198Scognet {dab_buserr, "External Non-Linefetch Abort (P)"}, 172129198Scognet {NULL, "Domain Fault (P)"}, 173129198Scognet {dab_buserr, "External Translation Abort (L1)"}, 174129198Scognet {NULL, "Permission Fault (S)"}, 175129198Scognet {dab_buserr, "External Translation Abort (L2)"}, 176129198Scognet {NULL, "Permission Fault (P)"} 177129198Scognet}; 178129198Scognet 179129198Scognet/* Determine if a fault came from user mode */ 180129198Scognet#define TRAP_USERMODE(tf) ((tf->tf_spsr & PSR_MODE) == PSR_USR32_MODE) 181129198Scognet 182129198Scognet/* Determine if 'x' is a permission fault */ 183129198Scognet#define IS_PERMISSION_FAULT(x) \ 184129198Scognet (((1 << ((x) & FAULT_TYPE_MASK)) & \ 185129198Scognet ((1 << FAULT_PERM_P) | (1 << FAULT_PERM_S))) != 0) 186129198Scognet 187129198Scognetstatic __inline void 188129198Scognetcall_trapsignal(struct thread *td, int sig, u_long code) 189129198Scognet{ 190151316Sdavidxu ksiginfo_t ksi; 191129198Scognet 192151316Sdavidxu ksiginfo_init_trap(&ksi); 193151316Sdavidxu ksi.ksi_signo = sig; 194151316Sdavidxu ksi.ksi_code = (int)code; 195151316Sdavidxu trapsignal(td, &ksi); 196129198Scognet} 197129198Scognet 198129198Scognetstatic __inline int 199129198Scognetdata_abort_fixup(trapframe_t *tf, u_int fsr, u_int far, struct thread *td, struct ksig *ksig) 200129198Scognet{ 201129198Scognet#ifdef CPU_ABORT_FIXUP_REQUIRED 202129198Scognet int error; 203129198Scognet 204129198Scognet /* Call the cpu specific data abort fixup routine */ 205129198Scognet error = cpu_dataabt_fixup(tf); 206129198Scognet if (__predict_true(error != ABORT_FIXUP_FAILED)) 207129198Scognet return (error); 208129198Scognet 209129198Scognet /* 210129198Scognet * Oops, couldn't fix up the instruction 211129198Scognet */ 212129198Scognet printf("data_abort_fixup: fixup for %s mode data abort failed.\n", 213129198Scognet TRAP_USERMODE(tf) ? "user" : "kernel"); 214129198Scognet printf("pc = 0x%08x, opcode 0x%08x, insn = ", tf->tf_pc, 215129198Scognet *((u_int *)tf->tf_pc)); 216129198Scognet disassemble(tf->tf_pc); 217129198Scognet 218129198Scognet /* Die now if this happened in kernel mode */ 219129198Scognet if (!TRAP_USERMODE(tf)) 220129198Scognet dab_fatal(tf, fsr, far, td, NULL, ksig); 221129198Scognet 222129198Scognet return (error); 223129198Scognet#else 224129198Scognet return (ABORT_FIXUP_OK); 225129198Scognet#endif /* CPU_ABORT_FIXUP_REQUIRED */ 226129198Scognet} 227129198Scognet 228129198Scognetvoid 229129198Scognetdata_abort_handler(trapframe_t *tf) 230129198Scognet{ 231129198Scognet struct vm_map *map; 232129198Scognet struct pcb *pcb; 233129198Scognet struct thread *td; 234129198Scognet u_int user, far, fsr; 235129198Scognet vm_prot_t ftype; 236129198Scognet void *onfault; 237129198Scognet vm_offset_t va; 238129198Scognet int error = 0; 239129198Scognet struct ksig ksig; 240137275Scognet struct proc *p; 241129198Scognet 242253142Sray 243129198Scognet /* Grab FAR/FSR before enabling interrupts */ 244129198Scognet far = cpu_faultaddress(); 245129198Scognet fsr = cpu_faultstatus(); 246135656Scognet#if 0 247250255Skientzle printf("data abort: fault address=%p (from pc=%p lr=%p)\n", 248250255Skientzle (void*)far, (void*)tf->tf_pc, (void*)tf->tf_svc_lr); 249135656Scognet#endif 250129198Scognet 251135656Scognet /* Update vmmeter statistics */ 252129198Scognet#if 0 253129198Scognet vmexp.traps++; 254129198Scognet#endif 255129198Scognet 256135656Scognet td = curthread; 257137275Scognet p = td->td_proc; 258129198Scognet 259170291Sattilio PCPU_INC(cnt.v_trap); 260129198Scognet /* Data abort came from user mode? */ 261129198Scognet user = TRAP_USERMODE(tf); 262129198Scognet 263135656Scognet if (user) { 264155455Sphk td->td_pticks = 0; 265253142Sray td->td_frame = tf; 266135656Scognet if (td->td_ucred != td->td_proc->p_ucred) 267135656Scognet cred_update_thread(td); 268253142Sray 269135656Scognet } 270129198Scognet /* Grab the current pcb */ 271129198Scognet pcb = td->td_pcb; 272135656Scognet /* Re-enable interrupts if they were enabled previously */ 273157616Scognet if (td->td_md.md_spinlock_count == 0) { 274157616Scognet if (__predict_true(tf->tf_spsr & I32_bit) == 0) 275157616Scognet enable_interrupts(I32_bit); 276157616Scognet if (__predict_true(tf->tf_spsr & F32_bit) == 0) 277157616Scognet enable_interrupts(F32_bit); 278157616Scognet } 279135656Scognet 280253142Sray 281129198Scognet /* Invoke the appropriate handler, if necessary */ 282129198Scognet if (__predict_false(data_aborts[fsr & FAULT_TYPE_MASK].func != NULL)) { 283129198Scognet if ((data_aborts[fsr & FAULT_TYPE_MASK].func)(tf, fsr, far, 284135656Scognet td, &ksig)) { 285129198Scognet goto do_trapsignal; 286135656Scognet } 287129198Scognet goto out; 288129198Scognet } 289129198Scognet 290129198Scognet /* 291129198Scognet * At this point, we're dealing with one of the following data aborts: 292129198Scognet * 293129198Scognet * FAULT_TRANS_S - Translation -- Section 294129198Scognet * FAULT_TRANS_P - Translation -- Page 295129198Scognet * FAULT_DOMAIN_S - Domain -- Section 296129198Scognet * FAULT_DOMAIN_P - Domain -- Page 297129198Scognet * FAULT_PERM_S - Permission -- Section 298129198Scognet * FAULT_PERM_P - Permission -- Page 299129198Scognet * 300129198Scognet * These are the main virtual memory-related faults signalled by 301129198Scognet * the MMU. 302129198Scognet */ 303129198Scognet 304129198Scognet /* fusubailout is used by [fs]uswintr to avoid page faulting */ 305129198Scognet if (__predict_false(pcb->pcb_onfault == fusubailout)) { 306129198Scognet tf->tf_r0 = EFAULT; 307129198Scognet tf->tf_pc = (register_t)(intptr_t) pcb->pcb_onfault; 308129198Scognet return; 309129198Scognet } 310129198Scognet 311129198Scognet /* 312129198Scognet * Make sure the Program Counter is sane. We could fall foul of 313129198Scognet * someone executing Thumb code, in which case the PC might not 314129198Scognet * be word-aligned. This would cause a kernel alignment fault 315129198Scognet * further down if we have to decode the current instruction. 316129198Scognet * XXX: It would be nice to be able to support Thumb at some point. 317129198Scognet */ 318129198Scognet if (__predict_false((tf->tf_pc & 3) != 0)) { 319129198Scognet if (user) { 320129198Scognet /* 321129198Scognet * Give the user an illegal instruction signal. 322129198Scognet */ 323129198Scognet /* Deliver a SIGILL to the process */ 324129198Scognet ksig.signb = SIGILL; 325129198Scognet ksig.code = 0; 326129198Scognet goto do_trapsignal; 327129198Scognet } 328129198Scognet 329129198Scognet /* 330129198Scognet * The kernel never executes Thumb code. 331129198Scognet */ 332129198Scognet printf("\ndata_abort_fault: Misaligned Kernel-mode " 333129198Scognet "Program Counter\n"); 334129198Scognet dab_fatal(tf, fsr, far, td, &ksig); 335129198Scognet } 336129198Scognet 337129198Scognet /* See if the cpu state needs to be fixed up */ 338129198Scognet switch (data_abort_fixup(tf, fsr, far, td, &ksig)) { 339129198Scognet case ABORT_FIXUP_RETURN: 340129198Scognet return; 341129198Scognet case ABORT_FIXUP_FAILED: 342129198Scognet /* Deliver a SIGILL to the process */ 343129198Scognet ksig.signb = SIGILL; 344129198Scognet ksig.code = 0; 345129198Scognet goto do_trapsignal; 346129198Scognet default: 347129198Scognet break; 348129198Scognet } 349129198Scognet 350129198Scognet va = trunc_page((vm_offset_t)far); 351129198Scognet 352129198Scognet /* 353129198Scognet * It is only a kernel address space fault iff: 354129198Scognet * 1. user == 0 and 355129198Scognet * 2. pcb_onfault not set or 356129198Scognet * 3. pcb_onfault set and not LDRT/LDRBT/STRT/STRBT instruction. 357129198Scognet */ 358129198Scognet if (user == 0 && (va >= VM_MIN_KERNEL_ADDRESS || 359129198Scognet (va < VM_MIN_ADDRESS && vector_page == ARM_VECTORS_LOW)) && 360129198Scognet __predict_true((pcb->pcb_onfault == NULL || 361129198Scognet (ReadWord(tf->tf_pc) & 0x05200000) != 0x04200000))) { 362129198Scognet map = kernel_map; 363129198Scognet 364129198Scognet /* Was the fault due to the FPE/IPKDB ? */ 365129198Scognet if (__predict_false((tf->tf_spsr & PSR_MODE)==PSR_UND32_MODE)) { 366129198Scognet 367129198Scognet /* 368129198Scognet * Force exit via userret() 369129198Scognet * This is necessary as the FPE is an extension to 370129198Scognet * userland that actually runs in a priveledged mode 371129198Scognet * but uses USR mode permissions for its accesses. 372129198Scognet */ 373129198Scognet user = 1; 374129198Scognet ksig.signb = SIGSEGV; 375129198Scognet ksig.code = 0; 376129198Scognet goto do_trapsignal; 377129198Scognet } 378129198Scognet } else { 379129198Scognet map = &td->td_proc->p_vmspace->vm_map; 380129198Scognet } 381129198Scognet 382129198Scognet /* 383129198Scognet * We need to know whether the page should be mapped 384129198Scognet * as R or R/W. The MMU does not give us the info as 385129198Scognet * to whether the fault was caused by a read or a write. 386129198Scognet * 387129198Scognet * However, we know that a permission fault can only be 388129198Scognet * the result of a write to a read-only location, so 389129198Scognet * we can deal with those quickly. 390129198Scognet * 391129198Scognet * Otherwise we need to disassemble the instruction 392129198Scognet * responsible to determine if it was a write. 393129198Scognet */ 394250929Sgber if (IS_PERMISSION_FAULT(fsr)) 395236991Simp ftype = VM_PROT_WRITE; 396250929Sgber else { 397129198Scognet u_int insn = ReadWord(tf->tf_pc); 398129198Scognet 399129198Scognet if (((insn & 0x0c100000) == 0x04000000) || /* STR/STRB */ 400129198Scognet ((insn & 0x0e1000b0) == 0x000000b0) || /* STRH/STRD */ 401250929Sgber ((insn & 0x0a100000) == 0x08000000)) { /* STM/CDT */ 402236991Simp ftype = VM_PROT_WRITE; 403250929Sgber } else { 404250929Sgber if ((insn & 0x0fb00ff0) == 0x01000090) /* SWP */ 405250929Sgber ftype = VM_PROT_READ | VM_PROT_WRITE; 406250929Sgber else 407250929Sgber ftype = VM_PROT_READ; 408250929Sgber } 409129198Scognet } 410129198Scognet 411129198Scognet /* 412129198Scognet * See if the fault is as a result of ref/mod emulation, 413129198Scognet * or domain mismatch. 414129198Scognet */ 415129198Scognet#ifdef DEBUG 416129198Scognet last_fault_code = fsr; 417129198Scognet#endif 418147416Scognet if (pmap_fault_fixup(vmspace_pmap(td->td_proc->p_vmspace), va, ftype, 419147416Scognet user)) { 420129198Scognet goto out; 421129198Scognet } 422129198Scognet 423129198Scognet onfault = pcb->pcb_onfault; 424129198Scognet pcb->pcb_onfault = NULL; 425137275Scognet if (map != kernel_map) { 426137275Scognet PROC_LOCK(p); 427137275Scognet p->p_lock++; 428137275Scognet PROC_UNLOCK(p); 429137275Scognet } 430199868Salc error = vm_fault(map, va, ftype, VM_FAULT_NORMAL); 431129198Scognet pcb->pcb_onfault = onfault; 432129198Scognet 433137275Scognet if (map != kernel_map) { 434137275Scognet PROC_LOCK(p); 435146600Scognet p->p_lock--; 436137275Scognet PROC_UNLOCK(p); 437137275Scognet } 438156174Scognet if (__predict_true(error == 0)) 439156174Scognet goto out; 440129198Scognet if (user == 0) { 441129198Scognet if (pcb->pcb_onfault) { 442129198Scognet tf->tf_r0 = error; 443129198Scognet tf->tf_pc = (register_t)(intptr_t) pcb->pcb_onfault; 444129198Scognet return; 445129198Scognet } 446129198Scognet 447129198Scognet printf("\nvm_fault(%p, %x, %x, 0) -> %x\n", map, va, ftype, 448129198Scognet error); 449129198Scognet dab_fatal(tf, fsr, far, td, &ksig); 450129198Scognet } 451129198Scognet 452129198Scognet 453129198Scognet if (error == ENOMEM) { 454129198Scognet printf("VM: pid %d (%s), uid %d killed: " 455173600Sjulian "out of swap\n", td->td_proc->p_pid, td->td_name, 456129198Scognet (td->td_proc->p_ucred) ? 457129198Scognet td->td_proc->p_ucred->cr_uid : -1); 458129198Scognet ksig.signb = SIGKILL; 459129198Scognet } else { 460129198Scognet ksig.signb = SIGSEGV; 461129198Scognet } 462129198Scognet ksig.code = 0; 463129198Scognetdo_trapsignal: 464129198Scognet call_trapsignal(td, ksig.signb, ksig.code); 465129198Scognetout: 466129198Scognet /* If returning to user mode, make sure to invoke userret() */ 467129198Scognet if (user) 468155455Sphk userret(td, tf); 469129198Scognet} 470129198Scognet 471129198Scognet/* 472129198Scognet * dab_fatal() handles the following data aborts: 473129198Scognet * 474129198Scognet * FAULT_WRTBUF_0 - Vector Exception 475129198Scognet * FAULT_WRTBUF_1 - Terminal Exception 476129198Scognet * 477129198Scognet * We should never see these on a properly functioning system. 478129198Scognet * 479129198Scognet * This function is also called by the other handlers if they 480129198Scognet * detect a fatal problem. 481129198Scognet * 482129198Scognet * Note: If 'l' is NULL, we assume we're dealing with a prefetch abort. 483129198Scognet */ 484129198Scognetstatic int 485129198Scognetdab_fatal(trapframe_t *tf, u_int fsr, u_int far, struct thread *td, struct ksig *ksig) 486129198Scognet{ 487129198Scognet const char *mode; 488129198Scognet 489129198Scognet mode = TRAP_USERMODE(tf) ? "user" : "kernel"; 490129198Scognet 491157616Scognet disable_interrupts(I32_bit|F32_bit); 492129198Scognet if (td != NULL) { 493129198Scognet printf("Fatal %s mode data abort: '%s'\n", mode, 494129198Scognet data_aborts[fsr & FAULT_TYPE_MASK].desc); 495129198Scognet printf("trapframe: %p\nFSR=%08x, FAR=", tf, fsr); 496129198Scognet if ((fsr & FAULT_IMPRECISE) == 0) 497129198Scognet printf("%08x, ", far); 498129198Scognet else 499129198Scognet printf("Invalid, "); 500129198Scognet printf("spsr=%08x\n", tf->tf_spsr); 501129198Scognet } else { 502129198Scognet printf("Fatal %s mode prefetch abort at 0x%08x\n", 503129198Scognet mode, tf->tf_pc); 504129198Scognet printf("trapframe: %p, spsr=%08x\n", tf, tf->tf_spsr); 505129198Scognet } 506129198Scognet 507129198Scognet printf("r0 =%08x, r1 =%08x, r2 =%08x, r3 =%08x\n", 508129198Scognet tf->tf_r0, tf->tf_r1, tf->tf_r2, tf->tf_r3); 509129198Scognet printf("r4 =%08x, r5 =%08x, r6 =%08x, r7 =%08x\n", 510129198Scognet tf->tf_r4, tf->tf_r5, tf->tf_r6, tf->tf_r7); 511129198Scognet printf("r8 =%08x, r9 =%08x, r10=%08x, r11=%08x\n", 512129198Scognet tf->tf_r8, tf->tf_r9, tf->tf_r10, tf->tf_r11); 513129198Scognet printf("r12=%08x, ", tf->tf_r12); 514129198Scognet 515129198Scognet if (TRAP_USERMODE(tf)) 516129198Scognet printf("usp=%08x, ulr=%08x", 517129198Scognet tf->tf_usr_sp, tf->tf_usr_lr); 518129198Scognet else 519129198Scognet printf("ssp=%08x, slr=%08x", 520129198Scognet tf->tf_svc_sp, tf->tf_svc_lr); 521129198Scognet printf(", pc =%08x\n\n", tf->tf_pc); 522129198Scognet 523147544Scognet#ifdef KDB 524190844Sraj if (debugger_on_panic || kdb_active) 525190844Sraj kdb_trap(fsr, 0, tf); 526129198Scognet#endif 527129198Scognet panic("Fatal abort"); 528129198Scognet /*NOTREACHED*/ 529129198Scognet} 530129198Scognet 531129198Scognet/* 532129198Scognet * dab_align() handles the following data aborts: 533129198Scognet * 534129198Scognet * FAULT_ALIGN_0 - Alignment fault 535190845Sraj * FAULT_ALIGN_1 - Alignment fault 536129198Scognet * 537129198Scognet * These faults are fatal if they happen in kernel mode. Otherwise, we 538129198Scognet * deliver a bus error to the process. 539129198Scognet */ 540129198Scognetstatic int 541129198Scognetdab_align(trapframe_t *tf, u_int fsr, u_int far, struct thread *td, struct ksig *ksig) 542129198Scognet{ 543129198Scognet 544129198Scognet /* Alignment faults are always fatal if they occur in kernel mode */ 545137275Scognet if (!TRAP_USERMODE(tf)) { 546137275Scognet if (!td || !td->td_pcb->pcb_onfault) 547137275Scognet dab_fatal(tf, fsr, far, td, ksig); 548137275Scognet tf->tf_r0 = EFAULT; 549137275Scognet tf->tf_pc = (int)td->td_pcb->pcb_onfault; 550137275Scognet return (0); 551137275Scognet } 552129198Scognet 553129198Scognet /* pcb_onfault *must* be NULL at this point */ 554129198Scognet 555129198Scognet /* See if the cpu state needs to be fixed up */ 556129198Scognet (void) data_abort_fixup(tf, fsr, far, td, ksig); 557129198Scognet 558129198Scognet /* Deliver a bus error signal to the process */ 559129198Scognet ksig->code = 0; 560129198Scognet ksig->signb = SIGBUS; 561129198Scognet td->td_frame = tf; 562129198Scognet 563129198Scognet return (1); 564129198Scognet} 565129198Scognet 566129198Scognet/* 567129198Scognet * dab_buserr() handles the following data aborts: 568129198Scognet * 569129198Scognet * FAULT_BUSERR_0 - External Abort on Linefetch -- Section 570129198Scognet * FAULT_BUSERR_1 - External Abort on Linefetch -- Page 571129198Scognet * FAULT_BUSERR_2 - External Abort on Non-linefetch -- Section 572129198Scognet * FAULT_BUSERR_3 - External Abort on Non-linefetch -- Page 573129198Scognet * FAULT_BUSTRNL1 - External abort on Translation -- Level 1 574129198Scognet * FAULT_BUSTRNL2 - External abort on Translation -- Level 2 575129198Scognet * 576129198Scognet * If pcb_onfault is set, flag the fault and return to the handler. 577129198Scognet * If the fault occurred in user mode, give the process a SIGBUS. 578129198Scognet * 579129198Scognet * Note: On XScale, FAULT_BUSERR_0, FAULT_BUSERR_1, and FAULT_BUSERR_2 580129198Scognet * can be flagged as imprecise in the FSR. This causes a real headache 581129198Scognet * since some of the machine state is lost. In this case, tf->tf_pc 582129198Scognet * may not actually point to the offending instruction. In fact, if 583129198Scognet * we've taken a double abort fault, it generally points somewhere near 584129198Scognet * the top of "data_abort_entry" in exception.S. 585129198Scognet * 586129198Scognet * In all other cases, these data aborts are considered fatal. 587129198Scognet */ 588129198Scognetstatic int 589129198Scognetdab_buserr(trapframe_t *tf, u_int fsr, u_int far, struct thread *td, struct ksig *ksig) 590129198Scognet{ 591129198Scognet struct pcb *pcb = td->td_pcb; 592129198Scognet 593129198Scognet#ifdef __XSCALE__ 594129198Scognet if ((fsr & FAULT_IMPRECISE) != 0 && 595129198Scognet (tf->tf_spsr & PSR_MODE) == PSR_ABT32_MODE) { 596129198Scognet /* 597129198Scognet * Oops, an imprecise, double abort fault. We've lost the 598129198Scognet * r14_abt/spsr_abt values corresponding to the original 599129198Scognet * abort, and the spsr saved in the trapframe indicates 600129198Scognet * ABT mode. 601129198Scognet */ 602129198Scognet tf->tf_spsr &= ~PSR_MODE; 603129198Scognet 604129198Scognet /* 605129198Scognet * We use a simple heuristic to determine if the double abort 606129198Scognet * happened as a result of a kernel or user mode access. 607129198Scognet * If the current trapframe is at the top of the kernel stack, 608129198Scognet * the fault _must_ have come from user mode. 609129198Scognet */ 610129198Scognet if (tf != ((trapframe_t *)pcb->un_32.pcb32_sp) - 1) { 611129198Scognet /* 612129198Scognet * Kernel mode. We're either about to die a 613129198Scognet * spectacular death, or pcb_onfault will come 614129198Scognet * to our rescue. Either way, the current value 615129198Scognet * of tf->tf_pc is irrelevant. 616129198Scognet */ 617129198Scognet tf->tf_spsr |= PSR_SVC32_MODE; 618129198Scognet if (pcb->pcb_onfault == NULL) 619129198Scognet printf("\nKernel mode double abort!\n"); 620129198Scognet } else { 621129198Scognet /* 622129198Scognet * User mode. We've lost the program counter at the 623129198Scognet * time of the fault (not that it was accurate anyway; 624129198Scognet * it's not called an imprecise fault for nothing). 625129198Scognet * About all we can do is copy r14_usr to tf_pc and 626129198Scognet * hope for the best. The process is about to get a 627129198Scognet * SIGBUS, so it's probably history anyway. 628129198Scognet */ 629129198Scognet tf->tf_spsr |= PSR_USR32_MODE; 630129198Scognet tf->tf_pc = tf->tf_usr_lr; 631129198Scognet } 632129198Scognet } 633129198Scognet 634129198Scognet /* FAR is invalid for imprecise exceptions */ 635129198Scognet if ((fsr & FAULT_IMPRECISE) != 0) 636129198Scognet far = 0; 637129198Scognet#endif /* __XSCALE__ */ 638129198Scognet 639129198Scognet if (pcb->pcb_onfault) { 640129198Scognet tf->tf_r0 = EFAULT; 641129198Scognet tf->tf_pc = (register_t)(intptr_t) pcb->pcb_onfault; 642129198Scognet return (0); 643129198Scognet } 644129198Scognet 645129198Scognet /* See if the cpu state needs to be fixed up */ 646129198Scognet (void) data_abort_fixup(tf, fsr, far, td, ksig); 647129198Scognet 648129198Scognet /* 649129198Scognet * At this point, if the fault happened in kernel mode, we're toast 650129198Scognet */ 651129198Scognet if (!TRAP_USERMODE(tf)) 652129198Scognet dab_fatal(tf, fsr, far, td, ksig); 653129198Scognet 654129198Scognet /* Deliver a bus error signal to the process */ 655129198Scognet ksig->signb = SIGBUS; 656129198Scognet ksig->code = 0; 657129198Scognet td->td_frame = tf; 658129198Scognet 659129198Scognet return (1); 660129198Scognet} 661129198Scognet 662129198Scognetstatic __inline int 663129198Scognetprefetch_abort_fixup(trapframe_t *tf, struct ksig *ksig) 664129198Scognet{ 665129198Scognet#ifdef CPU_ABORT_FIXUP_REQUIRED 666129198Scognet int error; 667129198Scognet 668129198Scognet /* Call the cpu specific prefetch abort fixup routine */ 669129198Scognet error = cpu_prefetchabt_fixup(tf); 670129198Scognet if (__predict_true(error != ABORT_FIXUP_FAILED)) 671129198Scognet return (error); 672129198Scognet 673129198Scognet /* 674129198Scognet * Oops, couldn't fix up the instruction 675129198Scognet */ 676129198Scognet printf( 677129198Scognet "prefetch_abort_fixup: fixup for %s mode prefetch abort failed.\n", 678129198Scognet TRAP_USERMODE(tf) ? "user" : "kernel"); 679129198Scognet printf("pc = 0x%08x, opcode 0x%08x, insn = ", tf->tf_pc, 680129198Scognet *((u_int *)tf->tf_pc)); 681129198Scognet disassemble(tf->tf_pc); 682129198Scognet 683129198Scognet /* Die now if this happened in kernel mode */ 684129198Scognet if (!TRAP_USERMODE(tf)) 685129198Scognet dab_fatal(tf, 0, tf->tf_pc, NULL, ksig); 686129198Scognet 687129198Scognet return (error); 688129198Scognet#else 689129198Scognet return (ABORT_FIXUP_OK); 690129198Scognet#endif /* CPU_ABORT_FIXUP_REQUIRED */ 691129198Scognet} 692129198Scognet 693129198Scognet/* 694129198Scognet * void prefetch_abort_handler(trapframe_t *tf) 695129198Scognet * 696129198Scognet * Abort handler called when instruction execution occurs at 697129198Scognet * a non existent or restricted (access permissions) memory page. 698129198Scognet * If the address is invalid and we were in SVC mode then panic as 699129198Scognet * the kernel should never prefetch abort. 700129198Scognet * If the address is invalid and the page is mapped then the user process 701129198Scognet * does no have read permission so send it a signal. 702129198Scognet * Otherwise fault the page in and try again. 703129198Scognet */ 704129198Scognetvoid 705129198Scognetprefetch_abort_handler(trapframe_t *tf) 706129198Scognet{ 707129198Scognet struct thread *td; 708137275Scognet struct proc * p; 709129198Scognet struct vm_map *map; 710129198Scognet vm_offset_t fault_pc, va; 711129198Scognet int error = 0; 712129198Scognet struct ksig ksig; 713129198Scognet 714137275Scognet 715129198Scognet#if 0 716129198Scognet /* Update vmmeter statistics */ 717129198Scognet uvmexp.traps++; 718129198Scognet#endif 719135656Scognet#if 0 720135656Scognet printf("prefetch abort handler: %p %p\n", (void*)tf->tf_pc, 721135656Scognet (void*)tf->tf_usr_lr); 722135656Scognet#endif 723253142Sray 724135656Scognet td = curthread; 725137275Scognet p = td->td_proc; 726170291Sattilio PCPU_INC(cnt.v_trap); 727135656Scognet 728135656Scognet if (TRAP_USERMODE(tf)) { 729137275Scognet td->td_frame = tf; 730135656Scognet if (td->td_ucred != td->td_proc->p_ucred) 731135656Scognet cred_update_thread(td); 732135656Scognet } 733135656Scognet fault_pc = tf->tf_pc; 734157616Scognet if (td->td_md.md_spinlock_count == 0) { 735157616Scognet if (__predict_true(tf->tf_spsr & I32_bit) == 0) 736157616Scognet enable_interrupts(I32_bit); 737157616Scognet if (__predict_true(tf->tf_spsr & F32_bit) == 0) 738157616Scognet enable_interrupts(F32_bit); 739157616Scognet } 740129198Scognet 741129198Scognet /* See if the cpu state needs to be fixed up */ 742129198Scognet switch (prefetch_abort_fixup(tf, &ksig)) { 743129198Scognet case ABORT_FIXUP_RETURN: 744129198Scognet return; 745129198Scognet case ABORT_FIXUP_FAILED: 746129198Scognet /* Deliver a SIGILL to the process */ 747129198Scognet ksig.signb = SIGILL; 748129198Scognet ksig.code = 0; 749129198Scognet td->td_frame = tf; 750129198Scognet goto do_trapsignal; 751129198Scognet default: 752129198Scognet break; 753129198Scognet } 754129198Scognet 755129198Scognet /* Prefetch aborts cannot happen in kernel mode */ 756129198Scognet if (__predict_false(!TRAP_USERMODE(tf))) 757129198Scognet dab_fatal(tf, 0, tf->tf_pc, NULL, &ksig); 758155455Sphk td->td_pticks = 0; 759129198Scognet 760135656Scognet 761129198Scognet /* Ok validate the address, can only execute in USER space */ 762129198Scognet if (__predict_false(fault_pc >= VM_MAXUSER_ADDRESS || 763129198Scognet (fault_pc < VM_MIN_ADDRESS && vector_page == ARM_VECTORS_LOW))) { 764129198Scognet ksig.signb = SIGSEGV; 765129198Scognet ksig.code = 0; 766129198Scognet goto do_trapsignal; 767129198Scognet } 768129198Scognet 769129198Scognet map = &td->td_proc->p_vmspace->vm_map; 770129198Scognet va = trunc_page(fault_pc); 771129198Scognet 772129198Scognet /* 773129198Scognet * See if the pmap can handle this fault on its own... 774129198Scognet */ 775129198Scognet#ifdef DEBUG 776129198Scognet last_fault_code = -1; 777129198Scognet#endif 778129198Scognet if (pmap_fault_fixup(map->pmap, va, VM_PROT_READ, 1)) 779129198Scognet goto out; 780129198Scognet 781137275Scognet if (map != kernel_map) { 782137275Scognet PROC_LOCK(p); 783137275Scognet p->p_lock++; 784137275Scognet PROC_UNLOCK(p); 785137275Scognet } 786137275Scognet 787135656Scognet error = vm_fault(map, va, VM_PROT_READ | VM_PROT_EXECUTE, 788129198Scognet VM_FAULT_NORMAL); 789137275Scognet if (map != kernel_map) { 790137275Scognet PROC_LOCK(p); 791137275Scognet p->p_lock--; 792137275Scognet PROC_UNLOCK(p); 793137275Scognet } 794137275Scognet 795129198Scognet if (__predict_true(error == 0)) 796129198Scognet goto out; 797129198Scognet 798129198Scognet if (error == ENOMEM) { 799129198Scognet printf("VM: pid %d (%s), uid %d killed: " 800173600Sjulian "out of swap\n", td->td_proc->p_pid, td->td_name, 801129198Scognet (td->td_proc->p_ucred) ? 802129198Scognet td->td_proc->p_ucred->cr_uid : -1); 803129198Scognet ksig.signb = SIGKILL; 804129198Scognet } else { 805129198Scognet ksig.signb = SIGSEGV; 806129198Scognet } 807129198Scognet ksig.code = 0; 808129198Scognet 809129198Scognetdo_trapsignal: 810129198Scognet call_trapsignal(td, ksig.signb, ksig.code); 811129198Scognet 812129198Scognetout: 813155455Sphk userret(td, tf); 814135656Scognet 815129198Scognet} 816129198Scognet 817129198Scognetextern int badaddr_read_1(const uint8_t *, uint8_t *); 818129198Scognetextern int badaddr_read_2(const uint16_t *, uint16_t *); 819129198Scognetextern int badaddr_read_4(const uint32_t *, uint32_t *); 820129198Scognet/* 821129198Scognet * Tentatively read an 8, 16, or 32-bit value from 'addr'. 822129198Scognet * If the read succeeds, the value is written to 'rptr' and zero is returned. 823129198Scognet * Else, return EFAULT. 824129198Scognet */ 825129198Scognetint 826129198Scognetbadaddr_read(void *addr, size_t size, void *rptr) 827129198Scognet{ 828129198Scognet union { 829129198Scognet uint8_t v1; 830129198Scognet uint16_t v2; 831129198Scognet uint32_t v4; 832129198Scognet } u; 833129198Scognet int rv; 834129198Scognet 835129198Scognet cpu_drain_writebuf(); 836129198Scognet 837129198Scognet /* Read from the test address. */ 838129198Scognet switch (size) { 839129198Scognet case sizeof(uint8_t): 840129198Scognet rv = badaddr_read_1(addr, &u.v1); 841129198Scognet if (rv == 0 && rptr) 842129198Scognet *(uint8_t *) rptr = u.v1; 843129198Scognet break; 844129198Scognet 845129198Scognet case sizeof(uint16_t): 846129198Scognet rv = badaddr_read_2(addr, &u.v2); 847129198Scognet if (rv == 0 && rptr) 848129198Scognet *(uint16_t *) rptr = u.v2; 849129198Scognet break; 850129198Scognet 851129198Scognet case sizeof(uint32_t): 852129198Scognet rv = badaddr_read_4(addr, &u.v4); 853129198Scognet if (rv == 0 && rptr) 854129198Scognet *(uint32_t *) rptr = u.v4; 855129198Scognet break; 856129198Scognet 857129198Scognet default: 858129198Scognet panic("badaddr: invalid size (%lu)", (u_long) size); 859129198Scognet } 860129198Scognet 861129198Scognet /* Return EFAULT if the address was invalid, else zero */ 862129198Scognet return (rv); 863129198Scognet} 864129198Scognet 865225973Skibint 866225973Skibcpu_fetch_syscall_args(struct thread *td, struct syscall_args *sa) 867225973Skib{ 868225973Skib struct proc *p; 869225973Skib register_t *ap; 870225973Skib int error; 871225973Skib 872245551Sandrew#ifdef __ARM_EABI__ 873245551Sandrew sa->code = td->td_frame->tf_r7; 874245551Sandrew#else 875225973Skib sa->code = sa->insn & 0x000fffff; 876245551Sandrew#endif 877225973Skib ap = &td->td_frame->tf_r0; 878225973Skib if (sa->code == SYS_syscall) { 879225973Skib sa->code = *ap++; 880225973Skib sa->nap--; 881225973Skib } else if (sa->code == SYS___syscall) { 882225973Skib sa->code = ap[_QUAD_LOWWORD]; 883225973Skib sa->nap -= 2; 884225973Skib ap += 2; 885225973Skib } 886225973Skib p = td->td_proc; 887225973Skib if (p->p_sysent->sv_mask) 888225973Skib sa->code &= p->p_sysent->sv_mask; 889225973Skib if (sa->code >= p->p_sysent->sv_size) 890225973Skib sa->callp = &p->p_sysent->sv_table[0]; 891225973Skib else 892225973Skib sa->callp = &p->p_sysent->sv_table[sa->code]; 893225973Skib sa->narg = sa->callp->sy_narg; 894225973Skib error = 0; 895225973Skib memcpy(sa->args, ap, sa->nap * sizeof(register_t)); 896225973Skib if (sa->narg > sa->nap) { 897225973Skib error = copyin((void *)td->td_frame->tf_usr_sp, sa->args + 898225973Skib sa->nap, (sa->narg - sa->nap) * sizeof(register_t)); 899225973Skib } 900225973Skib if (error == 0) { 901225973Skib td->td_retval[0] = 0; 902225973Skib td->td_retval[1] = 0; 903225973Skib } 904225973Skib return (error); 905225973Skib} 906225973Skib 907225973Skib#include "../../kern/subr_syscall.c" 908225973Skib 909129198Scognetstatic void 910239191Sandrewsyscall(struct thread *td, trapframe_t *frame) 911129198Scognet{ 912225973Skib struct syscall_args sa; 913225973Skib int error; 914129198Scognet 915245551Sandrew#ifndef __ARM_EABI__ 916239191Sandrew sa.insn = *(uint32_t *)(frame->tf_pc - INSN_SIZE); 917239191Sandrew switch (sa.insn & SWI_OS_MASK) { 918129198Scognet case 0: /* XXX: we need our own one. */ 919129198Scognet break; 920129198Scognet default: 921151316Sdavidxu call_trapsignal(td, SIGILL, 0); 922155455Sphk userret(td, frame); 923129198Scognet return; 924129198Scognet } 925245551Sandrew#endif 926245551Sandrew sa.nap = 4; 927160773Sjhb 928225973Skib error = syscallenter(td, &sa); 929225973Skib KASSERT(error != 0 || td->td_ar == NULL, 930225973Skib ("returning from syscall with td_ar set!")); 931225973Skib syscallret(td, error, &sa); 932129198Scognet} 933129198Scognet 934129198Scognetvoid 935129198Scognetswi_handler(trapframe_t *frame) 936129198Scognet{ 937129198Scognet struct thread *td = curthread; 938129198Scognet 939137275Scognet td->td_frame = frame; 940253142Sray 941155455Sphk td->td_pticks = 0; 942129198Scognet /* 943129198Scognet * Make sure the program counter is correctly aligned so we 944129198Scognet * don't take an alignment fault trying to read the opcode. 945129198Scognet */ 946129198Scognet if (__predict_false(((frame->tf_pc - INSN_SIZE) & 3) != 0)) { 947151316Sdavidxu call_trapsignal(td, SIGILL, 0); 948155455Sphk userret(td, frame); 949129198Scognet return; 950129198Scognet } 951137275Scognet /* 952137275Scognet * Enable interrupts if they were enabled before the exception. 953137275Scognet * Since all syscalls *should* come from user mode it will always 954236991Simp * be safe to enable them, but check anyway. 955236991Simp */ 956157616Scognet if (td->td_md.md_spinlock_count == 0) { 957157616Scognet if (__predict_true(frame->tf_spsr & I32_bit) == 0) 958157616Scognet enable_interrupts(I32_bit); 959157616Scognet if (__predict_true(frame->tf_spsr & F32_bit) == 0) 960157616Scognet enable_interrupts(F32_bit); 961157616Scognet } 962236991Simp 963239191Sandrew syscall(td, frame); 964129198Scognet} 965129198Scognet 966