syscall.c revision 250255
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 250255 2013-05-04 21:26:11Z kientzle $"); 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)"}, 163129198Scognet {dab_buserr, "External Linefetch Abort (P)"}, 164129198Scognet {NULL, "Translation Fault (P)"}, 165129198Scognet {dab_buserr, "External Non-Linefetch Abort (S)"}, 166129198Scognet {NULL, "Domain Fault (S)"}, 167129198Scognet {dab_buserr, "External Non-Linefetch Abort (P)"}, 168129198Scognet {NULL, "Domain Fault (P)"}, 169129198Scognet {dab_buserr, "External Translation Abort (L1)"}, 170129198Scognet {NULL, "Permission Fault (S)"}, 171129198Scognet {dab_buserr, "External Translation Abort (L2)"}, 172129198Scognet {NULL, "Permission Fault (P)"} 173129198Scognet}; 174129198Scognet 175129198Scognet/* Determine if a fault came from user mode */ 176129198Scognet#define TRAP_USERMODE(tf) ((tf->tf_spsr & PSR_MODE) == PSR_USR32_MODE) 177129198Scognet 178129198Scognet/* Determine if 'x' is a permission fault */ 179129198Scognet#define IS_PERMISSION_FAULT(x) \ 180129198Scognet (((1 << ((x) & FAULT_TYPE_MASK)) & \ 181129198Scognet ((1 << FAULT_PERM_P) | (1 << FAULT_PERM_S))) != 0) 182129198Scognet 183129198Scognetstatic __inline void 184129198Scognetcall_trapsignal(struct thread *td, int sig, u_long code) 185129198Scognet{ 186151316Sdavidxu ksiginfo_t ksi; 187129198Scognet 188151316Sdavidxu ksiginfo_init_trap(&ksi); 189151316Sdavidxu ksi.ksi_signo = sig; 190151316Sdavidxu ksi.ksi_code = (int)code; 191151316Sdavidxu trapsignal(td, &ksi); 192129198Scognet} 193129198Scognet 194129198Scognetstatic __inline int 195129198Scognetdata_abort_fixup(trapframe_t *tf, u_int fsr, u_int far, struct thread *td, struct ksig *ksig) 196129198Scognet{ 197129198Scognet#ifdef CPU_ABORT_FIXUP_REQUIRED 198129198Scognet int error; 199129198Scognet 200129198Scognet /* Call the cpu specific data abort fixup routine */ 201129198Scognet error = cpu_dataabt_fixup(tf); 202129198Scognet if (__predict_true(error != ABORT_FIXUP_FAILED)) 203129198Scognet return (error); 204129198Scognet 205129198Scognet /* 206129198Scognet * Oops, couldn't fix up the instruction 207129198Scognet */ 208129198Scognet printf("data_abort_fixup: fixup for %s mode data abort failed.\n", 209129198Scognet TRAP_USERMODE(tf) ? "user" : "kernel"); 210129198Scognet printf("pc = 0x%08x, opcode 0x%08x, insn = ", tf->tf_pc, 211129198Scognet *((u_int *)tf->tf_pc)); 212129198Scognet disassemble(tf->tf_pc); 213129198Scognet 214129198Scognet /* Die now if this happened in kernel mode */ 215129198Scognet if (!TRAP_USERMODE(tf)) 216129198Scognet dab_fatal(tf, fsr, far, td, NULL, ksig); 217129198Scognet 218129198Scognet return (error); 219129198Scognet#else 220129198Scognet return (ABORT_FIXUP_OK); 221129198Scognet#endif /* CPU_ABORT_FIXUP_REQUIRED */ 222129198Scognet} 223129198Scognet 224129198Scognetvoid 225129198Scognetdata_abort_handler(trapframe_t *tf) 226129198Scognet{ 227129198Scognet struct vm_map *map; 228129198Scognet struct pcb *pcb; 229129198Scognet struct thread *td; 230129198Scognet u_int user, far, fsr; 231129198Scognet vm_prot_t ftype; 232129198Scognet void *onfault; 233129198Scognet vm_offset_t va; 234129198Scognet int error = 0; 235129198Scognet struct ksig ksig; 236137275Scognet struct proc *p; 237137275Scognet 238129198Scognet 239129198Scognet /* Grab FAR/FSR before enabling interrupts */ 240129198Scognet far = cpu_faultaddress(); 241129198Scognet fsr = cpu_faultstatus(); 242135656Scognet#if 0 243250255Skientzle printf("data abort: fault address=%p (from pc=%p lr=%p)\n", 244250255Skientzle (void*)far, (void*)tf->tf_pc, (void*)tf->tf_svc_lr); 245135656Scognet#endif 246129198Scognet 247135656Scognet /* Update vmmeter statistics */ 248129198Scognet#if 0 249129198Scognet vmexp.traps++; 250129198Scognet#endif 251129198Scognet 252135656Scognet td = curthread; 253137275Scognet p = td->td_proc; 254129198Scognet 255170291Sattilio PCPU_INC(cnt.v_trap); 256129198Scognet /* Data abort came from user mode? */ 257129198Scognet user = TRAP_USERMODE(tf); 258129198Scognet 259135656Scognet if (user) { 260155455Sphk td->td_pticks = 0; 261155455Sphk td->td_frame = tf; 262135656Scognet if (td->td_ucred != td->td_proc->p_ucred) 263135656Scognet cred_update_thread(td); 264135656Scognet 265135656Scognet } 266129198Scognet /* Grab the current pcb */ 267129198Scognet pcb = td->td_pcb; 268135656Scognet /* Re-enable interrupts if they were enabled previously */ 269157616Scognet if (td->td_md.md_spinlock_count == 0) { 270157616Scognet if (__predict_true(tf->tf_spsr & I32_bit) == 0) 271157616Scognet enable_interrupts(I32_bit); 272157616Scognet if (__predict_true(tf->tf_spsr & F32_bit) == 0) 273157616Scognet enable_interrupts(F32_bit); 274157616Scognet } 275157616Scognet 276135656Scognet 277129198Scognet /* Invoke the appropriate handler, if necessary */ 278129198Scognet if (__predict_false(data_aborts[fsr & FAULT_TYPE_MASK].func != NULL)) { 279129198Scognet if ((data_aborts[fsr & FAULT_TYPE_MASK].func)(tf, fsr, far, 280135656Scognet td, &ksig)) { 281129198Scognet goto do_trapsignal; 282135656Scognet } 283129198Scognet goto out; 284129198Scognet } 285129198Scognet 286129198Scognet /* 287129198Scognet * At this point, we're dealing with one of the following data aborts: 288129198Scognet * 289129198Scognet * FAULT_TRANS_S - Translation -- Section 290129198Scognet * FAULT_TRANS_P - Translation -- Page 291129198Scognet * FAULT_DOMAIN_S - Domain -- Section 292129198Scognet * FAULT_DOMAIN_P - Domain -- Page 293129198Scognet * FAULT_PERM_S - Permission -- Section 294129198Scognet * FAULT_PERM_P - Permission -- Page 295129198Scognet * 296129198Scognet * These are the main virtual memory-related faults signalled by 297129198Scognet * the MMU. 298129198Scognet */ 299129198Scognet 300129198Scognet /* fusubailout is used by [fs]uswintr to avoid page faulting */ 301129198Scognet if (__predict_false(pcb->pcb_onfault == fusubailout)) { 302129198Scognet tf->tf_r0 = EFAULT; 303129198Scognet tf->tf_pc = (register_t)(intptr_t) pcb->pcb_onfault; 304129198Scognet return; 305129198Scognet } 306129198Scognet 307129198Scognet /* 308129198Scognet * Make sure the Program Counter is sane. We could fall foul of 309129198Scognet * someone executing Thumb code, in which case the PC might not 310129198Scognet * be word-aligned. This would cause a kernel alignment fault 311129198Scognet * further down if we have to decode the current instruction. 312129198Scognet * XXX: It would be nice to be able to support Thumb at some point. 313129198Scognet */ 314129198Scognet if (__predict_false((tf->tf_pc & 3) != 0)) { 315129198Scognet if (user) { 316129198Scognet /* 317129198Scognet * Give the user an illegal instruction signal. 318129198Scognet */ 319129198Scognet /* Deliver a SIGILL to the process */ 320129198Scognet ksig.signb = SIGILL; 321129198Scognet ksig.code = 0; 322129198Scognet goto do_trapsignal; 323129198Scognet } 324129198Scognet 325129198Scognet /* 326129198Scognet * The kernel never executes Thumb code. 327129198Scognet */ 328129198Scognet printf("\ndata_abort_fault: Misaligned Kernel-mode " 329129198Scognet "Program Counter\n"); 330129198Scognet dab_fatal(tf, fsr, far, td, &ksig); 331129198Scognet } 332129198Scognet 333129198Scognet /* See if the cpu state needs to be fixed up */ 334129198Scognet switch (data_abort_fixup(tf, fsr, far, td, &ksig)) { 335129198Scognet case ABORT_FIXUP_RETURN: 336129198Scognet return; 337129198Scognet case ABORT_FIXUP_FAILED: 338129198Scognet /* Deliver a SIGILL to the process */ 339129198Scognet ksig.signb = SIGILL; 340129198Scognet ksig.code = 0; 341129198Scognet goto do_trapsignal; 342129198Scognet default: 343129198Scognet break; 344129198Scognet } 345129198Scognet 346129198Scognet va = trunc_page((vm_offset_t)far); 347129198Scognet 348129198Scognet /* 349129198Scognet * It is only a kernel address space fault iff: 350129198Scognet * 1. user == 0 and 351129198Scognet * 2. pcb_onfault not set or 352129198Scognet * 3. pcb_onfault set and not LDRT/LDRBT/STRT/STRBT instruction. 353129198Scognet */ 354129198Scognet if (user == 0 && (va >= VM_MIN_KERNEL_ADDRESS || 355129198Scognet (va < VM_MIN_ADDRESS && vector_page == ARM_VECTORS_LOW)) && 356129198Scognet __predict_true((pcb->pcb_onfault == NULL || 357129198Scognet (ReadWord(tf->tf_pc) & 0x05200000) != 0x04200000))) { 358129198Scognet map = kernel_map; 359129198Scognet 360129198Scognet /* Was the fault due to the FPE/IPKDB ? */ 361129198Scognet if (__predict_false((tf->tf_spsr & PSR_MODE)==PSR_UND32_MODE)) { 362129198Scognet 363129198Scognet /* 364129198Scognet * Force exit via userret() 365129198Scognet * This is necessary as the FPE is an extension to 366129198Scognet * userland that actually runs in a priveledged mode 367129198Scognet * but uses USR mode permissions for its accesses. 368129198Scognet */ 369129198Scognet user = 1; 370129198Scognet ksig.signb = SIGSEGV; 371129198Scognet ksig.code = 0; 372129198Scognet goto do_trapsignal; 373129198Scognet } 374129198Scognet } else { 375129198Scognet map = &td->td_proc->p_vmspace->vm_map; 376129198Scognet } 377129198Scognet 378129198Scognet /* 379129198Scognet * We need to know whether the page should be mapped 380129198Scognet * as R or R/W. The MMU does not give us the info as 381129198Scognet * to whether the fault was caused by a read or a write. 382129198Scognet * 383129198Scognet * However, we know that a permission fault can only be 384129198Scognet * the result of a write to a read-only location, so 385129198Scognet * we can deal with those quickly. 386129198Scognet * 387129198Scognet * Otherwise we need to disassemble the instruction 388129198Scognet * responsible to determine if it was a write. 389129198Scognet */ 390129198Scognet if (IS_PERMISSION_FAULT(fsr)) { 391236991Simp ftype = VM_PROT_WRITE; 392129198Scognet } else { 393129198Scognet u_int insn = ReadWord(tf->tf_pc); 394129198Scognet 395129198Scognet if (((insn & 0x0c100000) == 0x04000000) || /* STR/STRB */ 396129198Scognet ((insn & 0x0e1000b0) == 0x000000b0) || /* STRH/STRD */ 397129198Scognet ((insn & 0x0a100000) == 0x08000000)) /* STM/CDT */ 398129198Scognet { 399236991Simp ftype = VM_PROT_WRITE; 400129198Scognet } 401129198Scognet else 402129198Scognet if ((insn & 0x0fb00ff0) == 0x01000090) /* SWP */ 403236991Simp ftype = VM_PROT_READ | VM_PROT_WRITE; 404129198Scognet else 405236991Simp ftype = VM_PROT_READ; 406129198Scognet } 407129198Scognet 408129198Scognet /* 409129198Scognet * See if the fault is as a result of ref/mod emulation, 410129198Scognet * or domain mismatch. 411129198Scognet */ 412129198Scognet#ifdef DEBUG 413129198Scognet last_fault_code = fsr; 414129198Scognet#endif 415147416Scognet if (pmap_fault_fixup(vmspace_pmap(td->td_proc->p_vmspace), va, ftype, 416147416Scognet user)) { 417129198Scognet goto out; 418129198Scognet } 419129198Scognet 420129198Scognet onfault = pcb->pcb_onfault; 421129198Scognet pcb->pcb_onfault = NULL; 422137275Scognet if (map != kernel_map) { 423137275Scognet PROC_LOCK(p); 424137275Scognet p->p_lock++; 425137275Scognet PROC_UNLOCK(p); 426137275Scognet } 427199868Salc error = vm_fault(map, va, ftype, VM_FAULT_NORMAL); 428129198Scognet pcb->pcb_onfault = onfault; 429129198Scognet 430137275Scognet if (map != kernel_map) { 431137275Scognet PROC_LOCK(p); 432146600Scognet p->p_lock--; 433137275Scognet PROC_UNLOCK(p); 434137275Scognet } 435156174Scognet if (__predict_true(error == 0)) 436156174Scognet goto out; 437129198Scognet if (user == 0) { 438129198Scognet if (pcb->pcb_onfault) { 439129198Scognet tf->tf_r0 = error; 440129198Scognet tf->tf_pc = (register_t)(intptr_t) pcb->pcb_onfault; 441129198Scognet return; 442129198Scognet } 443129198Scognet 444129198Scognet printf("\nvm_fault(%p, %x, %x, 0) -> %x\n", map, va, ftype, 445129198Scognet error); 446129198Scognet dab_fatal(tf, fsr, far, td, &ksig); 447129198Scognet } 448129198Scognet 449129198Scognet 450129198Scognet if (error == ENOMEM) { 451129198Scognet printf("VM: pid %d (%s), uid %d killed: " 452173600Sjulian "out of swap\n", td->td_proc->p_pid, td->td_name, 453129198Scognet (td->td_proc->p_ucred) ? 454129198Scognet td->td_proc->p_ucred->cr_uid : -1); 455129198Scognet ksig.signb = SIGKILL; 456129198Scognet } else { 457129198Scognet ksig.signb = SIGSEGV; 458129198Scognet } 459129198Scognet ksig.code = 0; 460129198Scognetdo_trapsignal: 461129198Scognet call_trapsignal(td, ksig.signb, ksig.code); 462129198Scognetout: 463129198Scognet /* If returning to user mode, make sure to invoke userret() */ 464129198Scognet if (user) 465155455Sphk userret(td, tf); 466129198Scognet} 467129198Scognet 468129198Scognet/* 469129198Scognet * dab_fatal() handles the following data aborts: 470129198Scognet * 471129198Scognet * FAULT_WRTBUF_0 - Vector Exception 472129198Scognet * FAULT_WRTBUF_1 - Terminal Exception 473129198Scognet * 474129198Scognet * We should never see these on a properly functioning system. 475129198Scognet * 476129198Scognet * This function is also called by the other handlers if they 477129198Scognet * detect a fatal problem. 478129198Scognet * 479129198Scognet * Note: If 'l' is NULL, we assume we're dealing with a prefetch abort. 480129198Scognet */ 481129198Scognetstatic int 482129198Scognetdab_fatal(trapframe_t *tf, u_int fsr, u_int far, struct thread *td, struct ksig *ksig) 483129198Scognet{ 484129198Scognet const char *mode; 485129198Scognet 486129198Scognet mode = TRAP_USERMODE(tf) ? "user" : "kernel"; 487129198Scognet 488157616Scognet disable_interrupts(I32_bit|F32_bit); 489129198Scognet if (td != NULL) { 490129198Scognet printf("Fatal %s mode data abort: '%s'\n", mode, 491129198Scognet data_aborts[fsr & FAULT_TYPE_MASK].desc); 492129198Scognet printf("trapframe: %p\nFSR=%08x, FAR=", tf, fsr); 493129198Scognet if ((fsr & FAULT_IMPRECISE) == 0) 494129198Scognet printf("%08x, ", far); 495129198Scognet else 496129198Scognet printf("Invalid, "); 497129198Scognet printf("spsr=%08x\n", tf->tf_spsr); 498129198Scognet } else { 499129198Scognet printf("Fatal %s mode prefetch abort at 0x%08x\n", 500129198Scognet mode, tf->tf_pc); 501129198Scognet printf("trapframe: %p, spsr=%08x\n", tf, tf->tf_spsr); 502129198Scognet } 503129198Scognet 504129198Scognet printf("r0 =%08x, r1 =%08x, r2 =%08x, r3 =%08x\n", 505129198Scognet tf->tf_r0, tf->tf_r1, tf->tf_r2, tf->tf_r3); 506129198Scognet printf("r4 =%08x, r5 =%08x, r6 =%08x, r7 =%08x\n", 507129198Scognet tf->tf_r4, tf->tf_r5, tf->tf_r6, tf->tf_r7); 508129198Scognet printf("r8 =%08x, r9 =%08x, r10=%08x, r11=%08x\n", 509129198Scognet tf->tf_r8, tf->tf_r9, tf->tf_r10, tf->tf_r11); 510129198Scognet printf("r12=%08x, ", tf->tf_r12); 511129198Scognet 512129198Scognet if (TRAP_USERMODE(tf)) 513129198Scognet printf("usp=%08x, ulr=%08x", 514129198Scognet tf->tf_usr_sp, tf->tf_usr_lr); 515129198Scognet else 516129198Scognet printf("ssp=%08x, slr=%08x", 517129198Scognet tf->tf_svc_sp, tf->tf_svc_lr); 518129198Scognet printf(", pc =%08x\n\n", tf->tf_pc); 519129198Scognet 520147544Scognet#ifdef KDB 521190844Sraj if (debugger_on_panic || kdb_active) 522190844Sraj kdb_trap(fsr, 0, tf); 523129198Scognet#endif 524129198Scognet panic("Fatal abort"); 525129198Scognet /*NOTREACHED*/ 526129198Scognet} 527129198Scognet 528129198Scognet/* 529129198Scognet * dab_align() handles the following data aborts: 530129198Scognet * 531129198Scognet * FAULT_ALIGN_0 - Alignment fault 532190845Sraj * FAULT_ALIGN_1 - Alignment fault 533129198Scognet * 534129198Scognet * These faults are fatal if they happen in kernel mode. Otherwise, we 535129198Scognet * deliver a bus error to the process. 536129198Scognet */ 537129198Scognetstatic int 538129198Scognetdab_align(trapframe_t *tf, u_int fsr, u_int far, struct thread *td, struct ksig *ksig) 539129198Scognet{ 540129198Scognet 541129198Scognet /* Alignment faults are always fatal if they occur in kernel mode */ 542137275Scognet if (!TRAP_USERMODE(tf)) { 543137275Scognet if (!td || !td->td_pcb->pcb_onfault) 544137275Scognet dab_fatal(tf, fsr, far, td, ksig); 545137275Scognet tf->tf_r0 = EFAULT; 546137275Scognet tf->tf_pc = (int)td->td_pcb->pcb_onfault; 547137275Scognet return (0); 548137275Scognet } 549129198Scognet 550129198Scognet /* pcb_onfault *must* be NULL at this point */ 551129198Scognet 552129198Scognet /* See if the cpu state needs to be fixed up */ 553129198Scognet (void) data_abort_fixup(tf, fsr, far, td, ksig); 554129198Scognet 555129198Scognet /* Deliver a bus error signal to the process */ 556129198Scognet ksig->code = 0; 557129198Scognet ksig->signb = SIGBUS; 558129198Scognet td->td_frame = tf; 559129198Scognet 560129198Scognet return (1); 561129198Scognet} 562129198Scognet 563129198Scognet/* 564129198Scognet * dab_buserr() handles the following data aborts: 565129198Scognet * 566129198Scognet * FAULT_BUSERR_0 - External Abort on Linefetch -- Section 567129198Scognet * FAULT_BUSERR_1 - External Abort on Linefetch -- Page 568129198Scognet * FAULT_BUSERR_2 - External Abort on Non-linefetch -- Section 569129198Scognet * FAULT_BUSERR_3 - External Abort on Non-linefetch -- Page 570129198Scognet * FAULT_BUSTRNL1 - External abort on Translation -- Level 1 571129198Scognet * FAULT_BUSTRNL2 - External abort on Translation -- Level 2 572129198Scognet * 573129198Scognet * If pcb_onfault is set, flag the fault and return to the handler. 574129198Scognet * If the fault occurred in user mode, give the process a SIGBUS. 575129198Scognet * 576129198Scognet * Note: On XScale, FAULT_BUSERR_0, FAULT_BUSERR_1, and FAULT_BUSERR_2 577129198Scognet * can be flagged as imprecise in the FSR. This causes a real headache 578129198Scognet * since some of the machine state is lost. In this case, tf->tf_pc 579129198Scognet * may not actually point to the offending instruction. In fact, if 580129198Scognet * we've taken a double abort fault, it generally points somewhere near 581129198Scognet * the top of "data_abort_entry" in exception.S. 582129198Scognet * 583129198Scognet * In all other cases, these data aborts are considered fatal. 584129198Scognet */ 585129198Scognetstatic int 586129198Scognetdab_buserr(trapframe_t *tf, u_int fsr, u_int far, struct thread *td, struct ksig *ksig) 587129198Scognet{ 588129198Scognet struct pcb *pcb = td->td_pcb; 589129198Scognet 590129198Scognet#ifdef __XSCALE__ 591129198Scognet if ((fsr & FAULT_IMPRECISE) != 0 && 592129198Scognet (tf->tf_spsr & PSR_MODE) == PSR_ABT32_MODE) { 593129198Scognet /* 594129198Scognet * Oops, an imprecise, double abort fault. We've lost the 595129198Scognet * r14_abt/spsr_abt values corresponding to the original 596129198Scognet * abort, and the spsr saved in the trapframe indicates 597129198Scognet * ABT mode. 598129198Scognet */ 599129198Scognet tf->tf_spsr &= ~PSR_MODE; 600129198Scognet 601129198Scognet /* 602129198Scognet * We use a simple heuristic to determine if the double abort 603129198Scognet * happened as a result of a kernel or user mode access. 604129198Scognet * If the current trapframe is at the top of the kernel stack, 605129198Scognet * the fault _must_ have come from user mode. 606129198Scognet */ 607129198Scognet if (tf != ((trapframe_t *)pcb->un_32.pcb32_sp) - 1) { 608129198Scognet /* 609129198Scognet * Kernel mode. We're either about to die a 610129198Scognet * spectacular death, or pcb_onfault will come 611129198Scognet * to our rescue. Either way, the current value 612129198Scognet * of tf->tf_pc is irrelevant. 613129198Scognet */ 614129198Scognet tf->tf_spsr |= PSR_SVC32_MODE; 615129198Scognet if (pcb->pcb_onfault == NULL) 616129198Scognet printf("\nKernel mode double abort!\n"); 617129198Scognet } else { 618129198Scognet /* 619129198Scognet * User mode. We've lost the program counter at the 620129198Scognet * time of the fault (not that it was accurate anyway; 621129198Scognet * it's not called an imprecise fault for nothing). 622129198Scognet * About all we can do is copy r14_usr to tf_pc and 623129198Scognet * hope for the best. The process is about to get a 624129198Scognet * SIGBUS, so it's probably history anyway. 625129198Scognet */ 626129198Scognet tf->tf_spsr |= PSR_USR32_MODE; 627129198Scognet tf->tf_pc = tf->tf_usr_lr; 628129198Scognet } 629129198Scognet } 630129198Scognet 631129198Scognet /* FAR is invalid for imprecise exceptions */ 632129198Scognet if ((fsr & FAULT_IMPRECISE) != 0) 633129198Scognet far = 0; 634129198Scognet#endif /* __XSCALE__ */ 635129198Scognet 636129198Scognet if (pcb->pcb_onfault) { 637129198Scognet tf->tf_r0 = EFAULT; 638129198Scognet tf->tf_pc = (register_t)(intptr_t) pcb->pcb_onfault; 639129198Scognet return (0); 640129198Scognet } 641129198Scognet 642129198Scognet /* See if the cpu state needs to be fixed up */ 643129198Scognet (void) data_abort_fixup(tf, fsr, far, td, ksig); 644129198Scognet 645129198Scognet /* 646129198Scognet * At this point, if the fault happened in kernel mode, we're toast 647129198Scognet */ 648129198Scognet if (!TRAP_USERMODE(tf)) 649129198Scognet dab_fatal(tf, fsr, far, td, ksig); 650129198Scognet 651129198Scognet /* Deliver a bus error signal to the process */ 652129198Scognet ksig->signb = SIGBUS; 653129198Scognet ksig->code = 0; 654129198Scognet td->td_frame = tf; 655129198Scognet 656129198Scognet return (1); 657129198Scognet} 658129198Scognet 659129198Scognetstatic __inline int 660129198Scognetprefetch_abort_fixup(trapframe_t *tf, struct ksig *ksig) 661129198Scognet{ 662129198Scognet#ifdef CPU_ABORT_FIXUP_REQUIRED 663129198Scognet int error; 664129198Scognet 665129198Scognet /* Call the cpu specific prefetch abort fixup routine */ 666129198Scognet error = cpu_prefetchabt_fixup(tf); 667129198Scognet if (__predict_true(error != ABORT_FIXUP_FAILED)) 668129198Scognet return (error); 669129198Scognet 670129198Scognet /* 671129198Scognet * Oops, couldn't fix up the instruction 672129198Scognet */ 673129198Scognet printf( 674129198Scognet "prefetch_abort_fixup: fixup for %s mode prefetch abort failed.\n", 675129198Scognet TRAP_USERMODE(tf) ? "user" : "kernel"); 676129198Scognet printf("pc = 0x%08x, opcode 0x%08x, insn = ", tf->tf_pc, 677129198Scognet *((u_int *)tf->tf_pc)); 678129198Scognet disassemble(tf->tf_pc); 679129198Scognet 680129198Scognet /* Die now if this happened in kernel mode */ 681129198Scognet if (!TRAP_USERMODE(tf)) 682129198Scognet dab_fatal(tf, 0, tf->tf_pc, NULL, ksig); 683129198Scognet 684129198Scognet return (error); 685129198Scognet#else 686129198Scognet return (ABORT_FIXUP_OK); 687129198Scognet#endif /* CPU_ABORT_FIXUP_REQUIRED */ 688129198Scognet} 689129198Scognet 690129198Scognet/* 691129198Scognet * void prefetch_abort_handler(trapframe_t *tf) 692129198Scognet * 693129198Scognet * Abort handler called when instruction execution occurs at 694129198Scognet * a non existent or restricted (access permissions) memory page. 695129198Scognet * If the address is invalid and we were in SVC mode then panic as 696129198Scognet * the kernel should never prefetch abort. 697129198Scognet * If the address is invalid and the page is mapped then the user process 698129198Scognet * does no have read permission so send it a signal. 699129198Scognet * Otherwise fault the page in and try again. 700129198Scognet */ 701129198Scognetvoid 702129198Scognetprefetch_abort_handler(trapframe_t *tf) 703129198Scognet{ 704129198Scognet struct thread *td; 705137275Scognet struct proc * p; 706129198Scognet struct vm_map *map; 707129198Scognet vm_offset_t fault_pc, va; 708129198Scognet int error = 0; 709129198Scognet struct ksig ksig; 710129198Scognet 711137275Scognet 712129198Scognet#if 0 713129198Scognet /* Update vmmeter statistics */ 714129198Scognet uvmexp.traps++; 715129198Scognet#endif 716135656Scognet#if 0 717135656Scognet printf("prefetch abort handler: %p %p\n", (void*)tf->tf_pc, 718135656Scognet (void*)tf->tf_usr_lr); 719135656Scognet#endif 720135656Scognet 721135656Scognet td = curthread; 722137275Scognet p = td->td_proc; 723170291Sattilio PCPU_INC(cnt.v_trap); 724135656Scognet 725135656Scognet if (TRAP_USERMODE(tf)) { 726137275Scognet td->td_frame = tf; 727135656Scognet if (td->td_ucred != td->td_proc->p_ucred) 728135656Scognet cred_update_thread(td); 729135656Scognet } 730135656Scognet fault_pc = tf->tf_pc; 731157616Scognet if (td->td_md.md_spinlock_count == 0) { 732157616Scognet if (__predict_true(tf->tf_spsr & I32_bit) == 0) 733157616Scognet enable_interrupts(I32_bit); 734157616Scognet if (__predict_true(tf->tf_spsr & F32_bit) == 0) 735157616Scognet enable_interrupts(F32_bit); 736157616Scognet } 737129198Scognet 738129198Scognet /* See if the cpu state needs to be fixed up */ 739129198Scognet switch (prefetch_abort_fixup(tf, &ksig)) { 740129198Scognet case ABORT_FIXUP_RETURN: 741129198Scognet return; 742129198Scognet case ABORT_FIXUP_FAILED: 743129198Scognet /* Deliver a SIGILL to the process */ 744129198Scognet ksig.signb = SIGILL; 745129198Scognet ksig.code = 0; 746129198Scognet td->td_frame = tf; 747129198Scognet goto do_trapsignal; 748129198Scognet default: 749129198Scognet break; 750129198Scognet } 751129198Scognet 752129198Scognet /* Prefetch aborts cannot happen in kernel mode */ 753129198Scognet if (__predict_false(!TRAP_USERMODE(tf))) 754129198Scognet dab_fatal(tf, 0, tf->tf_pc, NULL, &ksig); 755155455Sphk td->td_pticks = 0; 756129198Scognet 757135656Scognet 758129198Scognet /* Ok validate the address, can only execute in USER space */ 759129198Scognet if (__predict_false(fault_pc >= VM_MAXUSER_ADDRESS || 760129198Scognet (fault_pc < VM_MIN_ADDRESS && vector_page == ARM_VECTORS_LOW))) { 761129198Scognet ksig.signb = SIGSEGV; 762129198Scognet ksig.code = 0; 763129198Scognet goto do_trapsignal; 764129198Scognet } 765129198Scognet 766129198Scognet map = &td->td_proc->p_vmspace->vm_map; 767129198Scognet va = trunc_page(fault_pc); 768129198Scognet 769129198Scognet /* 770129198Scognet * See if the pmap can handle this fault on its own... 771129198Scognet */ 772129198Scognet#ifdef DEBUG 773129198Scognet last_fault_code = -1; 774129198Scognet#endif 775129198Scognet if (pmap_fault_fixup(map->pmap, va, VM_PROT_READ, 1)) 776129198Scognet goto out; 777129198Scognet 778137275Scognet if (map != kernel_map) { 779137275Scognet PROC_LOCK(p); 780137275Scognet p->p_lock++; 781137275Scognet PROC_UNLOCK(p); 782137275Scognet } 783137275Scognet 784135656Scognet error = vm_fault(map, va, VM_PROT_READ | VM_PROT_EXECUTE, 785129198Scognet VM_FAULT_NORMAL); 786137275Scognet if (map != kernel_map) { 787137275Scognet PROC_LOCK(p); 788137275Scognet p->p_lock--; 789137275Scognet PROC_UNLOCK(p); 790137275Scognet } 791137275Scognet 792129198Scognet if (__predict_true(error == 0)) 793129198Scognet goto out; 794129198Scognet 795129198Scognet if (error == ENOMEM) { 796129198Scognet printf("VM: pid %d (%s), uid %d killed: " 797173600Sjulian "out of swap\n", td->td_proc->p_pid, td->td_name, 798129198Scognet (td->td_proc->p_ucred) ? 799129198Scognet td->td_proc->p_ucred->cr_uid : -1); 800129198Scognet ksig.signb = SIGKILL; 801129198Scognet } else { 802129198Scognet ksig.signb = SIGSEGV; 803129198Scognet } 804129198Scognet ksig.code = 0; 805129198Scognet 806129198Scognetdo_trapsignal: 807129198Scognet call_trapsignal(td, ksig.signb, ksig.code); 808129198Scognet 809129198Scognetout: 810155455Sphk userret(td, tf); 811135656Scognet 812129198Scognet} 813129198Scognet 814129198Scognetextern int badaddr_read_1(const uint8_t *, uint8_t *); 815129198Scognetextern int badaddr_read_2(const uint16_t *, uint16_t *); 816129198Scognetextern int badaddr_read_4(const uint32_t *, uint32_t *); 817129198Scognet/* 818129198Scognet * Tentatively read an 8, 16, or 32-bit value from 'addr'. 819129198Scognet * If the read succeeds, the value is written to 'rptr' and zero is returned. 820129198Scognet * Else, return EFAULT. 821129198Scognet */ 822129198Scognetint 823129198Scognetbadaddr_read(void *addr, size_t size, void *rptr) 824129198Scognet{ 825129198Scognet union { 826129198Scognet uint8_t v1; 827129198Scognet uint16_t v2; 828129198Scognet uint32_t v4; 829129198Scognet } u; 830129198Scognet int rv; 831129198Scognet 832129198Scognet cpu_drain_writebuf(); 833129198Scognet 834129198Scognet /* Read from the test address. */ 835129198Scognet switch (size) { 836129198Scognet case sizeof(uint8_t): 837129198Scognet rv = badaddr_read_1(addr, &u.v1); 838129198Scognet if (rv == 0 && rptr) 839129198Scognet *(uint8_t *) rptr = u.v1; 840129198Scognet break; 841129198Scognet 842129198Scognet case sizeof(uint16_t): 843129198Scognet rv = badaddr_read_2(addr, &u.v2); 844129198Scognet if (rv == 0 && rptr) 845129198Scognet *(uint16_t *) rptr = u.v2; 846129198Scognet break; 847129198Scognet 848129198Scognet case sizeof(uint32_t): 849129198Scognet rv = badaddr_read_4(addr, &u.v4); 850129198Scognet if (rv == 0 && rptr) 851129198Scognet *(uint32_t *) rptr = u.v4; 852129198Scognet break; 853129198Scognet 854129198Scognet default: 855129198Scognet panic("badaddr: invalid size (%lu)", (u_long) size); 856129198Scognet } 857129198Scognet 858129198Scognet /* Return EFAULT if the address was invalid, else zero */ 859129198Scognet return (rv); 860129198Scognet} 861129198Scognet 862225973Skibint 863225973Skibcpu_fetch_syscall_args(struct thread *td, struct syscall_args *sa) 864225973Skib{ 865225973Skib struct proc *p; 866225973Skib register_t *ap; 867225973Skib int error; 868225973Skib 869245551Sandrew#ifdef __ARM_EABI__ 870245551Sandrew sa->code = td->td_frame->tf_r7; 871245551Sandrew#else 872225973Skib sa->code = sa->insn & 0x000fffff; 873245551Sandrew#endif 874225973Skib ap = &td->td_frame->tf_r0; 875225973Skib if (sa->code == SYS_syscall) { 876225973Skib sa->code = *ap++; 877225973Skib sa->nap--; 878225973Skib } else if (sa->code == SYS___syscall) { 879225973Skib sa->code = ap[_QUAD_LOWWORD]; 880225973Skib sa->nap -= 2; 881225973Skib ap += 2; 882225973Skib } 883225973Skib p = td->td_proc; 884225973Skib if (p->p_sysent->sv_mask) 885225973Skib sa->code &= p->p_sysent->sv_mask; 886225973Skib if (sa->code >= p->p_sysent->sv_size) 887225973Skib sa->callp = &p->p_sysent->sv_table[0]; 888225973Skib else 889225973Skib sa->callp = &p->p_sysent->sv_table[sa->code]; 890225973Skib sa->narg = sa->callp->sy_narg; 891225973Skib error = 0; 892225973Skib memcpy(sa->args, ap, sa->nap * sizeof(register_t)); 893225973Skib if (sa->narg > sa->nap) { 894225973Skib error = copyin((void *)td->td_frame->tf_usr_sp, sa->args + 895225973Skib sa->nap, (sa->narg - sa->nap) * sizeof(register_t)); 896225973Skib } 897225973Skib if (error == 0) { 898225973Skib td->td_retval[0] = 0; 899225973Skib td->td_retval[1] = 0; 900225973Skib } 901225973Skib return (error); 902225973Skib} 903225973Skib 904225973Skib#include "../../kern/subr_syscall.c" 905225973Skib 906129198Scognetstatic void 907239191Sandrewsyscall(struct thread *td, trapframe_t *frame) 908129198Scognet{ 909225973Skib struct syscall_args sa; 910225973Skib int error; 911129198Scognet 912245551Sandrew#ifndef __ARM_EABI__ 913239191Sandrew sa.insn = *(uint32_t *)(frame->tf_pc - INSN_SIZE); 914239191Sandrew switch (sa.insn & SWI_OS_MASK) { 915129198Scognet case 0: /* XXX: we need our own one. */ 916129198Scognet break; 917129198Scognet default: 918151316Sdavidxu call_trapsignal(td, SIGILL, 0); 919155455Sphk userret(td, frame); 920129198Scognet return; 921129198Scognet } 922245551Sandrew#endif 923245551Sandrew sa.nap = 4; 924160773Sjhb 925225973Skib error = syscallenter(td, &sa); 926225973Skib KASSERT(error != 0 || td->td_ar == NULL, 927225973Skib ("returning from syscall with td_ar set!")); 928225973Skib syscallret(td, error, &sa); 929129198Scognet} 930129198Scognet 931129198Scognetvoid 932129198Scognetswi_handler(trapframe_t *frame) 933129198Scognet{ 934129198Scognet struct thread *td = curthread; 935129198Scognet 936137275Scognet td->td_frame = frame; 937135656Scognet 938155455Sphk td->td_pticks = 0; 939129198Scognet /* 940129198Scognet * Make sure the program counter is correctly aligned so we 941129198Scognet * don't take an alignment fault trying to read the opcode. 942129198Scognet */ 943129198Scognet if (__predict_false(((frame->tf_pc - INSN_SIZE) & 3) != 0)) { 944151316Sdavidxu call_trapsignal(td, SIGILL, 0); 945155455Sphk userret(td, frame); 946129198Scognet return; 947129198Scognet } 948137275Scognet /* 949137275Scognet * Enable interrupts if they were enabled before the exception. 950137275Scognet * Since all syscalls *should* come from user mode it will always 951236991Simp * be safe to enable them, but check anyway. 952236991Simp */ 953157616Scognet if (td->td_md.md_spinlock_count == 0) { 954157616Scognet if (__predict_true(frame->tf_spsr & I32_bit) == 0) 955157616Scognet enable_interrupts(I32_bit); 956157616Scognet if (__predict_true(frame->tf_spsr & F32_bit) == 0) 957157616Scognet enable_interrupts(F32_bit); 958157616Scognet } 959236991Simp 960239191Sandrew syscall(td, frame); 961129198Scognet} 962129198Scognet 963