syscall.c revision 138129
1129198Scognet/* $NetBSD: fault.c,v 1.45 2003/11/20 14:44:36 scw Exp $ */ 2129198Scognet 3129198Scognet/* 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 */ 38129198Scognet/* 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 138129 2004-11-27 06:51:39Z das $"); 86129198Scognet 87129198Scognet#include <sys/types.h> 88129198Scognet 89129198Scognet#include <sys/param.h> 90129198Scognet#include <sys/systm.h> 91129198Scognet#include <sys/proc.h> 92129198Scognet#include <sys/kernel.h> 93129198Scognet#include <sys/lock.h> 94129198Scognet#include <sys/mutex.h> 95129198Scognet#include <sys/syscall.h> 96129198Scognet#include <sys/sysent.h> 97135656Scognet#ifdef KTRACE 98135656Scognet#include <sys/uio.h> 99135656Scognet#include <sys/ktrace.h> 100135656Scognet#endif 101129198Scognet 102129198Scognet#include <vm/vm.h> 103129198Scognet#include <vm/pmap.h> 104129198Scognet#include <vm/vm_kern.h> 105129198Scognet#include <vm/vm_map.h> 106129198Scognet#include <vm/vm_extern.h> 107129198Scognet 108129198Scognet#include <machine/cpuconf.h> 109129198Scognet#include <machine/vmparam.h> 110129198Scognet#include <machine/frame.h> 111129198Scognet#include <machine/katelib.h> 112129198Scognet#include <machine/cpu.h> 113129198Scognet#include <machine/intr.h> 114138129Sdas#include <machine/pcb.h> 115129198Scognet#include <machine/proc.h> 116129198Scognet#include <machine/swi.h> 117129198Scognet#if !defined(DDB) 118129198Scognet#define kdb_trap kgdb_trap 119129198Scognet#endif 120129198Scognet 121129198Scognet 122129198Scognet 123129198Scognetvoid swi_handler(trapframe_t *); 124129198Scognetvoid undefinedinstruction(trapframe_t *); 125129198Scognet 126129198Scognet#include <machine/disassem.h> 127129198Scognet#include <machine/machdep.h> 128129198Scognet 129129198Scognetextern char fusubailout[]; 130129198Scognet 131129198Scognet#ifdef DEBUG 132129198Scognetint last_fault_code; /* For the benefit of pmap_fault_fixup() */ 133129198Scognet#endif 134129198Scognet 135129198Scognet#if defined(CPU_ARM3) || defined(CPU_ARM6) || \ 136129198Scognet defined(CPU_ARM7) || defined(CPU_ARM7TDMI) 137129198Scognet/* These CPUs may need data/prefetch abort fixups */ 138129198Scognet#define CPU_ABORT_FIXUP_REQUIRED 139129198Scognet#endif 140129198Scognet 141129198Scognetstruct ksig { 142129198Scognet int signb; 143129198Scognet u_long code; 144129198Scognet}; 145129198Scognetstruct data_abort { 146129198Scognet int (*func)(trapframe_t *, u_int, u_int, struct thread *, struct ksig *); 147129198Scognet const char *desc; 148129198Scognet}; 149129198Scognet 150129198Scognetstatic int dab_fatal(trapframe_t *, u_int, u_int, struct thread *, struct ksig *); 151129198Scognetstatic int dab_align(trapframe_t *, u_int, u_int, struct thread *, struct ksig *); 152129198Scognetstatic int dab_buserr(trapframe_t *, u_int, u_int, struct thread *, struct ksig *); 153129198Scognet 154129198Scognetstatic const struct data_abort data_aborts[] = { 155129198Scognet {dab_fatal, "Vector Exception"}, 156129198Scognet {dab_align, "Alignment Fault 1"}, 157129198Scognet {dab_fatal, "Terminal Exception"}, 158129198Scognet {dab_align, "Alignment Fault 3"}, 159129198Scognet {dab_buserr, "External Linefetch Abort (S)"}, 160129198Scognet {NULL, "Translation Fault (S)"}, 161129198Scognet {dab_buserr, "External Linefetch Abort (P)"}, 162129198Scognet {NULL, "Translation Fault (P)"}, 163129198Scognet {dab_buserr, "External Non-Linefetch Abort (S)"}, 164129198Scognet {NULL, "Domain Fault (S)"}, 165129198Scognet {dab_buserr, "External Non-Linefetch Abort (P)"}, 166129198Scognet {NULL, "Domain Fault (P)"}, 167129198Scognet {dab_buserr, "External Translation Abort (L1)"}, 168129198Scognet {NULL, "Permission Fault (S)"}, 169129198Scognet {dab_buserr, "External Translation Abort (L2)"}, 170129198Scognet {NULL, "Permission Fault (P)"} 171129198Scognet}; 172129198Scognet 173129198Scognet/* Determine if a fault came from user mode */ 174129198Scognet#define TRAP_USERMODE(tf) ((tf->tf_spsr & PSR_MODE) == PSR_USR32_MODE) 175129198Scognet 176129198Scognet/* Determine if 'x' is a permission fault */ 177129198Scognet#define IS_PERMISSION_FAULT(x) \ 178129198Scognet (((1 << ((x) & FAULT_TYPE_MASK)) & \ 179129198Scognet ((1 << FAULT_PERM_P) | (1 << FAULT_PERM_S))) != 0) 180129198Scognet 181129198Scognetstatic __inline void 182129198Scognetcall_trapsignal(struct thread *td, int sig, u_long code) 183129198Scognet{ 184129198Scognet 185129198Scognet trapsignal(td, sig, code); 186129198Scognet} 187129198Scognet 188129198Scognetstatic __inline int 189129198Scognetdata_abort_fixup(trapframe_t *tf, u_int fsr, u_int far, struct thread *td, struct ksig *ksig) 190129198Scognet{ 191129198Scognet#ifdef CPU_ABORT_FIXUP_REQUIRED 192129198Scognet int error; 193129198Scognet 194129198Scognet /* Call the cpu specific data abort fixup routine */ 195129198Scognet error = cpu_dataabt_fixup(tf); 196129198Scognet if (__predict_true(error != ABORT_FIXUP_FAILED)) 197129198Scognet return (error); 198129198Scognet 199129198Scognet /* 200129198Scognet * Oops, couldn't fix up the instruction 201129198Scognet */ 202129198Scognet printf("data_abort_fixup: fixup for %s mode data abort failed.\n", 203129198Scognet TRAP_USERMODE(tf) ? "user" : "kernel"); 204129198Scognet printf("pc = 0x%08x, opcode 0x%08x, insn = ", tf->tf_pc, 205129198Scognet *((u_int *)tf->tf_pc)); 206129198Scognet disassemble(tf->tf_pc); 207129198Scognet 208129198Scognet /* Die now if this happened in kernel mode */ 209129198Scognet if (!TRAP_USERMODE(tf)) 210129198Scognet dab_fatal(tf, fsr, far, td, NULL, ksig); 211129198Scognet 212129198Scognet return (error); 213129198Scognet#else 214129198Scognet return (ABORT_FIXUP_OK); 215129198Scognet#endif /* CPU_ABORT_FIXUP_REQUIRED */ 216129198Scognet} 217129198Scognet 218129198Scognetvoid 219129198Scognetdata_abort_handler(trapframe_t *tf) 220129198Scognet{ 221129198Scognet struct vm_map *map; 222129198Scognet struct pcb *pcb; 223129198Scognet struct thread *td; 224129198Scognet u_int user, far, fsr; 225129198Scognet vm_prot_t ftype; 226129198Scognet void *onfault; 227129198Scognet vm_offset_t va; 228129198Scognet u_int sticks = 0; 229129198Scognet int error = 0; 230129198Scognet struct ksig ksig; 231137275Scognet struct proc *p; 232137275Scognet 233129198Scognet 234129198Scognet /* Grab FAR/FSR before enabling interrupts */ 235129198Scognet far = cpu_faultaddress(); 236129198Scognet fsr = cpu_faultstatus(); 237135656Scognet#if 0 238135656Scognet printf("data abort: %p (from %p %p)\n", (void*)far, (void*)tf->tf_pc, 239135656Scognet (void*)tf->tf_svc_lr); 240135656Scognet#endif 241129198Scognet 242135656Scognet /* Update vmmeter statistics */ 243129198Scognet#if 0 244129198Scognet vmexp.traps++; 245129198Scognet#endif 246129198Scognet 247135656Scognet td = curthread; 248137275Scognet p = td->td_proc; 249129198Scognet 250137903Scognet atomic_add_int(&cnt.v_trap, 1); 251129198Scognet /* Data abort came from user mode? */ 252129198Scognet user = TRAP_USERMODE(tf); 253129198Scognet 254135656Scognet if (user) { 255137275Scognet sticks = td->td_sticks; td->td_frame = tf; 256135656Scognet if (td->td_ucred != td->td_proc->p_ucred) 257135656Scognet cred_update_thread(td); 258137275Scognet if (td->td_pflags & TDP_SA) 259137275Scognet thread_user_enter(td); 260135656Scognet 261135656Scognet } 262129198Scognet /* Grab the current pcb */ 263129198Scognet pcb = td->td_pcb; 264135656Scognet /* Re-enable interrupts if they were enabled previously */ 265135656Scognet if (td->td_critnest == 0 && __predict_true(tf->tf_spsr & I32_bit) == 0) 266135656Scognet enable_interrupts(I32_bit); 267135656Scognet 268129198Scognet /* Invoke the appropriate handler, if necessary */ 269129198Scognet if (__predict_false(data_aborts[fsr & FAULT_TYPE_MASK].func != NULL)) { 270129198Scognet if ((data_aborts[fsr & FAULT_TYPE_MASK].func)(tf, fsr, far, 271135656Scognet td, &ksig)) { 272129198Scognet goto do_trapsignal; 273135656Scognet } 274129198Scognet goto out; 275129198Scognet } 276129198Scognet 277129198Scognet /* 278129198Scognet * At this point, we're dealing with one of the following data aborts: 279129198Scognet * 280129198Scognet * FAULT_TRANS_S - Translation -- Section 281129198Scognet * FAULT_TRANS_P - Translation -- Page 282129198Scognet * FAULT_DOMAIN_S - Domain -- Section 283129198Scognet * FAULT_DOMAIN_P - Domain -- Page 284129198Scognet * FAULT_PERM_S - Permission -- Section 285129198Scognet * FAULT_PERM_P - Permission -- Page 286129198Scognet * 287129198Scognet * These are the main virtual memory-related faults signalled by 288129198Scognet * the MMU. 289129198Scognet */ 290129198Scognet 291129198Scognet /* fusubailout is used by [fs]uswintr to avoid page faulting */ 292129198Scognet if (__predict_false(pcb->pcb_onfault == fusubailout)) { 293129198Scognet tf->tf_r0 = EFAULT; 294129198Scognet tf->tf_pc = (register_t)(intptr_t) pcb->pcb_onfault; 295129198Scognet return; 296129198Scognet } 297129198Scognet 298129198Scognet /* 299129198Scognet * Make sure the Program Counter is sane. We could fall foul of 300129198Scognet * someone executing Thumb code, in which case the PC might not 301129198Scognet * be word-aligned. This would cause a kernel alignment fault 302129198Scognet * further down if we have to decode the current instruction. 303129198Scognet * XXX: It would be nice to be able to support Thumb at some point. 304129198Scognet */ 305129198Scognet if (__predict_false((tf->tf_pc & 3) != 0)) { 306129198Scognet if (user) { 307129198Scognet /* 308129198Scognet * Give the user an illegal instruction signal. 309129198Scognet */ 310129198Scognet /* Deliver a SIGILL to the process */ 311129198Scognet ksig.signb = SIGILL; 312129198Scognet ksig.code = 0; 313129198Scognet goto do_trapsignal; 314129198Scognet } 315129198Scognet 316129198Scognet /* 317129198Scognet * The kernel never executes Thumb code. 318129198Scognet */ 319129198Scognet printf("\ndata_abort_fault: Misaligned Kernel-mode " 320129198Scognet "Program Counter\n"); 321129198Scognet dab_fatal(tf, fsr, far, td, &ksig); 322129198Scognet } 323129198Scognet 324129198Scognet /* See if the cpu state needs to be fixed up */ 325129198Scognet switch (data_abort_fixup(tf, fsr, far, td, &ksig)) { 326129198Scognet case ABORT_FIXUP_RETURN: 327129198Scognet return; 328129198Scognet case ABORT_FIXUP_FAILED: 329129198Scognet /* Deliver a SIGILL to the process */ 330129198Scognet ksig.signb = SIGILL; 331129198Scognet ksig.code = 0; 332129198Scognet goto do_trapsignal; 333129198Scognet default: 334129198Scognet break; 335129198Scognet } 336129198Scognet 337129198Scognet va = trunc_page((vm_offset_t)far); 338129198Scognet 339129198Scognet /* 340129198Scognet * It is only a kernel address space fault iff: 341129198Scognet * 1. user == 0 and 342129198Scognet * 2. pcb_onfault not set or 343129198Scognet * 3. pcb_onfault set and not LDRT/LDRBT/STRT/STRBT instruction. 344129198Scognet */ 345129198Scognet if (user == 0 && (va >= VM_MIN_KERNEL_ADDRESS || 346129198Scognet (va < VM_MIN_ADDRESS && vector_page == ARM_VECTORS_LOW)) && 347129198Scognet __predict_true((pcb->pcb_onfault == NULL || 348129198Scognet (ReadWord(tf->tf_pc) & 0x05200000) != 0x04200000))) { 349129198Scognet map = kernel_map; 350129198Scognet 351129198Scognet /* Was the fault due to the FPE/IPKDB ? */ 352129198Scognet if (__predict_false((tf->tf_spsr & PSR_MODE)==PSR_UND32_MODE)) { 353129198Scognet 354129198Scognet /* 355129198Scognet * Force exit via userret() 356129198Scognet * This is necessary as the FPE is an extension to 357129198Scognet * userland that actually runs in a priveledged mode 358129198Scognet * but uses USR mode permissions for its accesses. 359129198Scognet */ 360129198Scognet user = 1; 361129198Scognet ksig.signb = SIGSEGV; 362129198Scognet ksig.code = 0; 363129198Scognet goto do_trapsignal; 364129198Scognet } 365129198Scognet } else { 366129198Scognet map = &td->td_proc->p_vmspace->vm_map; 367129198Scognet } 368129198Scognet 369129198Scognet /* 370129198Scognet * We need to know whether the page should be mapped 371129198Scognet * as R or R/W. The MMU does not give us the info as 372129198Scognet * to whether the fault was caused by a read or a write. 373129198Scognet * 374129198Scognet * However, we know that a permission fault can only be 375129198Scognet * the result of a write to a read-only location, so 376129198Scognet * we can deal with those quickly. 377129198Scognet * 378129198Scognet * Otherwise we need to disassemble the instruction 379129198Scognet * responsible to determine if it was a write. 380129198Scognet */ 381129198Scognet if (IS_PERMISSION_FAULT(fsr)) { 382129198Scognet ftype = VM_PROT_WRITE; 383129198Scognet } else { 384129198Scognet u_int insn = ReadWord(tf->tf_pc); 385129198Scognet 386129198Scognet if (((insn & 0x0c100000) == 0x04000000) || /* STR/STRB */ 387129198Scognet ((insn & 0x0e1000b0) == 0x000000b0) || /* STRH/STRD */ 388129198Scognet ((insn & 0x0a100000) == 0x08000000)) /* STM/CDT */ 389129198Scognet { 390129198Scognet ftype = VM_PROT_WRITE; 391129198Scognet } 392129198Scognet else 393129198Scognet if ((insn & 0x0fb00ff0) == 0x01000090) /* SWP */ 394129198Scognet ftype = VM_PROT_READ | VM_PROT_WRITE; 395129198Scognet else 396129198Scognet ftype = VM_PROT_READ; 397129198Scognet } 398129198Scognet 399129198Scognet /* 400129198Scognet * See if the fault is as a result of ref/mod emulation, 401129198Scognet * or domain mismatch. 402129198Scognet */ 403129198Scognet#ifdef DEBUG 404129198Scognet last_fault_code = fsr; 405129198Scognet#endif 406135656Scognet if (pmap_fault_fixup(user ? vmspace_pmap(td->td_proc->p_vmspace) : 407135656Scognet kernel_pmap, va, ftype, user)) { 408129198Scognet goto out; 409129198Scognet } 410129198Scognet 411129198Scognet onfault = pcb->pcb_onfault; 412129198Scognet pcb->pcb_onfault = NULL; 413137275Scognet if (map != kernel_map) { 414137275Scognet PROC_LOCK(p); 415137275Scognet p->p_lock++; 416137275Scognet PROC_UNLOCK(p); 417137275Scognet } 418129198Scognet error = vm_fault(map, va, ftype, (ftype & VM_PROT_WRITE) ? 419129198Scognet VM_FAULT_DIRTY : VM_FAULT_NORMAL); 420129198Scognet pcb->pcb_onfault = onfault; 421129198Scognet if (__predict_true(error == 0)) { 422129198Scognet goto out; 423129198Scognet } 424129198Scognet 425137275Scognet if (map != kernel_map) { 426137275Scognet PROC_LOCK(p); 427137275Scognet p->p_lock++; 428137275Scognet PROC_UNLOCK(p); 429137275Scognet } 430129198Scognet if (user == 0) { 431129198Scognet if (pcb->pcb_onfault) { 432129198Scognet tf->tf_r0 = error; 433129198Scognet tf->tf_pc = (register_t)(intptr_t) pcb->pcb_onfault; 434129198Scognet return; 435129198Scognet } 436129198Scognet 437129198Scognet printf("\nvm_fault(%p, %x, %x, 0) -> %x\n", map, va, ftype, 438129198Scognet error); 439129198Scognet dab_fatal(tf, fsr, far, td, &ksig); 440129198Scognet } 441129198Scognet 442129198Scognet 443129198Scognet if (error == ENOMEM) { 444129198Scognet printf("VM: pid %d (%s), uid %d killed: " 445129198Scognet "out of swap\n", td->td_proc->p_pid, td->td_proc->p_comm, 446129198Scognet (td->td_proc->p_ucred) ? 447129198Scognet td->td_proc->p_ucred->cr_uid : -1); 448129198Scognet ksig.signb = SIGKILL; 449129198Scognet } else { 450129198Scognet ksig.signb = SIGSEGV; 451129198Scognet } 452129198Scognet ksig.code = 0; 453129198Scognetdo_trapsignal: 454129198Scognet call_trapsignal(td, ksig.signb, ksig.code); 455129198Scognetout: 456129198Scognet /* If returning to user mode, make sure to invoke userret() */ 457129198Scognet if (user) 458129198Scognet userret(td, tf, sticks); 459129198Scognet} 460129198Scognet 461129198Scognet/* 462129198Scognet * dab_fatal() handles the following data aborts: 463129198Scognet * 464129198Scognet * FAULT_WRTBUF_0 - Vector Exception 465129198Scognet * FAULT_WRTBUF_1 - Terminal Exception 466129198Scognet * 467129198Scognet * We should never see these on a properly functioning system. 468129198Scognet * 469129198Scognet * This function is also called by the other handlers if they 470129198Scognet * detect a fatal problem. 471129198Scognet * 472129198Scognet * Note: If 'l' is NULL, we assume we're dealing with a prefetch abort. 473129198Scognet */ 474129198Scognetstatic int 475129198Scognetdab_fatal(trapframe_t *tf, u_int fsr, u_int far, struct thread *td, struct ksig *ksig) 476129198Scognet{ 477129198Scognet const char *mode; 478129198Scognet 479129198Scognet mode = TRAP_USERMODE(tf) ? "user" : "kernel"; 480129198Scognet 481129198Scognet if (td != NULL) { 482129198Scognet printf("Fatal %s mode data abort: '%s'\n", mode, 483129198Scognet data_aborts[fsr & FAULT_TYPE_MASK].desc); 484129198Scognet printf("trapframe: %p\nFSR=%08x, FAR=", tf, fsr); 485129198Scognet if ((fsr & FAULT_IMPRECISE) == 0) 486129198Scognet printf("%08x, ", far); 487129198Scognet else 488129198Scognet printf("Invalid, "); 489129198Scognet printf("spsr=%08x\n", tf->tf_spsr); 490129198Scognet } else { 491129198Scognet printf("Fatal %s mode prefetch abort at 0x%08x\n", 492129198Scognet mode, tf->tf_pc); 493129198Scognet printf("trapframe: %p, spsr=%08x\n", tf, tf->tf_spsr); 494129198Scognet } 495129198Scognet 496129198Scognet printf("r0 =%08x, r1 =%08x, r2 =%08x, r3 =%08x\n", 497129198Scognet tf->tf_r0, tf->tf_r1, tf->tf_r2, tf->tf_r3); 498129198Scognet printf("r4 =%08x, r5 =%08x, r6 =%08x, r7 =%08x\n", 499129198Scognet tf->tf_r4, tf->tf_r5, tf->tf_r6, tf->tf_r7); 500129198Scognet printf("r8 =%08x, r9 =%08x, r10=%08x, r11=%08x\n", 501129198Scognet tf->tf_r8, tf->tf_r9, tf->tf_r10, tf->tf_r11); 502129198Scognet printf("r12=%08x, ", tf->tf_r12); 503129198Scognet 504129198Scognet if (TRAP_USERMODE(tf)) 505129198Scognet printf("usp=%08x, ulr=%08x", 506129198Scognet tf->tf_usr_sp, tf->tf_usr_lr); 507129198Scognet else 508129198Scognet printf("ssp=%08x, slr=%08x", 509129198Scognet tf->tf_svc_sp, tf->tf_svc_lr); 510129198Scognet printf(", pc =%08x\n\n", tf->tf_pc); 511129198Scognet 512129198Scognet#if defined(DDB) || defined(KGDB) 513129198Scognet kdb_trap(T_FAULT, tf); 514129198Scognet#endif 515129198Scognet panic("Fatal abort"); 516129198Scognet /*NOTREACHED*/ 517129198Scognet} 518129198Scognet 519129198Scognet/* 520129198Scognet * dab_align() handles the following data aborts: 521129198Scognet * 522129198Scognet * FAULT_ALIGN_0 - Alignment fault 523129198Scognet * FAULT_ALIGN_0 - Alignment fault 524129198Scognet * 525129198Scognet * These faults are fatal if they happen in kernel mode. Otherwise, we 526129198Scognet * deliver a bus error to the process. 527129198Scognet */ 528129198Scognetstatic int 529129198Scognetdab_align(trapframe_t *tf, u_int fsr, u_int far, struct thread *td, struct ksig *ksig) 530129198Scognet{ 531129198Scognet 532129198Scognet /* Alignment faults are always fatal if they occur in kernel mode */ 533137275Scognet if (!TRAP_USERMODE(tf)) { 534137275Scognet if (!td || !td->td_pcb->pcb_onfault) 535137275Scognet dab_fatal(tf, fsr, far, td, ksig); 536137275Scognet tf->tf_r0 = EFAULT; 537137275Scognet tf->tf_pc = (int)td->td_pcb->pcb_onfault; 538137275Scognet return (0); 539137275Scognet } 540129198Scognet 541129198Scognet /* pcb_onfault *must* be NULL at this point */ 542129198Scognet 543129198Scognet /* See if the cpu state needs to be fixed up */ 544129198Scognet (void) data_abort_fixup(tf, fsr, far, td, ksig); 545129198Scognet 546129198Scognet /* Deliver a bus error signal to the process */ 547129198Scognet ksig->code = 0; 548129198Scognet ksig->signb = SIGBUS; 549129198Scognet td->td_frame = tf; 550129198Scognet 551129198Scognet return (1); 552129198Scognet} 553129198Scognet 554129198Scognet/* 555129198Scognet * dab_buserr() handles the following data aborts: 556129198Scognet * 557129198Scognet * FAULT_BUSERR_0 - External Abort on Linefetch -- Section 558129198Scognet * FAULT_BUSERR_1 - External Abort on Linefetch -- Page 559129198Scognet * FAULT_BUSERR_2 - External Abort on Non-linefetch -- Section 560129198Scognet * FAULT_BUSERR_3 - External Abort on Non-linefetch -- Page 561129198Scognet * FAULT_BUSTRNL1 - External abort on Translation -- Level 1 562129198Scognet * FAULT_BUSTRNL2 - External abort on Translation -- Level 2 563129198Scognet * 564129198Scognet * If pcb_onfault is set, flag the fault and return to the handler. 565129198Scognet * If the fault occurred in user mode, give the process a SIGBUS. 566129198Scognet * 567129198Scognet * Note: On XScale, FAULT_BUSERR_0, FAULT_BUSERR_1, and FAULT_BUSERR_2 568129198Scognet * can be flagged as imprecise in the FSR. This causes a real headache 569129198Scognet * since some of the machine state is lost. In this case, tf->tf_pc 570129198Scognet * may not actually point to the offending instruction. In fact, if 571129198Scognet * we've taken a double abort fault, it generally points somewhere near 572129198Scognet * the top of "data_abort_entry" in exception.S. 573129198Scognet * 574129198Scognet * In all other cases, these data aborts are considered fatal. 575129198Scognet */ 576129198Scognetstatic int 577129198Scognetdab_buserr(trapframe_t *tf, u_int fsr, u_int far, struct thread *td, struct ksig *ksig) 578129198Scognet{ 579129198Scognet struct pcb *pcb = td->td_pcb; 580129198Scognet 581129198Scognet#ifdef __XSCALE__ 582129198Scognet if ((fsr & FAULT_IMPRECISE) != 0 && 583129198Scognet (tf->tf_spsr & PSR_MODE) == PSR_ABT32_MODE) { 584129198Scognet /* 585129198Scognet * Oops, an imprecise, double abort fault. We've lost the 586129198Scognet * r14_abt/spsr_abt values corresponding to the original 587129198Scognet * abort, and the spsr saved in the trapframe indicates 588129198Scognet * ABT mode. 589129198Scognet */ 590129198Scognet tf->tf_spsr &= ~PSR_MODE; 591129198Scognet 592129198Scognet /* 593129198Scognet * We use a simple heuristic to determine if the double abort 594129198Scognet * happened as a result of a kernel or user mode access. 595129198Scognet * If the current trapframe is at the top of the kernel stack, 596129198Scognet * the fault _must_ have come from user mode. 597129198Scognet */ 598129198Scognet if (tf != ((trapframe_t *)pcb->un_32.pcb32_sp) - 1) { 599129198Scognet /* 600129198Scognet * Kernel mode. We're either about to die a 601129198Scognet * spectacular death, or pcb_onfault will come 602129198Scognet * to our rescue. Either way, the current value 603129198Scognet * of tf->tf_pc is irrelevant. 604129198Scognet */ 605129198Scognet tf->tf_spsr |= PSR_SVC32_MODE; 606129198Scognet if (pcb->pcb_onfault == NULL) 607129198Scognet printf("\nKernel mode double abort!\n"); 608129198Scognet } else { 609129198Scognet /* 610129198Scognet * User mode. We've lost the program counter at the 611129198Scognet * time of the fault (not that it was accurate anyway; 612129198Scognet * it's not called an imprecise fault for nothing). 613129198Scognet * About all we can do is copy r14_usr to tf_pc and 614129198Scognet * hope for the best. The process is about to get a 615129198Scognet * SIGBUS, so it's probably history anyway. 616129198Scognet */ 617129198Scognet tf->tf_spsr |= PSR_USR32_MODE; 618129198Scognet tf->tf_pc = tf->tf_usr_lr; 619129198Scognet } 620129198Scognet } 621129198Scognet 622129198Scognet /* FAR is invalid for imprecise exceptions */ 623129198Scognet if ((fsr & FAULT_IMPRECISE) != 0) 624129198Scognet far = 0; 625129198Scognet#endif /* __XSCALE__ */ 626129198Scognet 627129198Scognet if (pcb->pcb_onfault) { 628129198Scognet tf->tf_r0 = EFAULT; 629129198Scognet tf->tf_pc = (register_t)(intptr_t) pcb->pcb_onfault; 630129198Scognet return (0); 631129198Scognet } 632129198Scognet 633129198Scognet /* See if the cpu state needs to be fixed up */ 634129198Scognet (void) data_abort_fixup(tf, fsr, far, td, ksig); 635129198Scognet 636129198Scognet /* 637129198Scognet * At this point, if the fault happened in kernel mode, we're toast 638129198Scognet */ 639129198Scognet if (!TRAP_USERMODE(tf)) 640129198Scognet dab_fatal(tf, fsr, far, td, ksig); 641129198Scognet 642129198Scognet /* Deliver a bus error signal to the process */ 643129198Scognet ksig->signb = SIGBUS; 644129198Scognet ksig->code = 0; 645129198Scognet td->td_frame = tf; 646129198Scognet 647129198Scognet return (1); 648129198Scognet} 649129198Scognet 650129198Scognetstatic __inline int 651129198Scognetprefetch_abort_fixup(trapframe_t *tf, struct ksig *ksig) 652129198Scognet{ 653129198Scognet#ifdef CPU_ABORT_FIXUP_REQUIRED 654129198Scognet int error; 655129198Scognet 656129198Scognet /* Call the cpu specific prefetch abort fixup routine */ 657129198Scognet error = cpu_prefetchabt_fixup(tf); 658129198Scognet if (__predict_true(error != ABORT_FIXUP_FAILED)) 659129198Scognet return (error); 660129198Scognet 661129198Scognet /* 662129198Scognet * Oops, couldn't fix up the instruction 663129198Scognet */ 664129198Scognet printf( 665129198Scognet "prefetch_abort_fixup: fixup for %s mode prefetch abort failed.\n", 666129198Scognet TRAP_USERMODE(tf) ? "user" : "kernel"); 667129198Scognet printf("pc = 0x%08x, opcode 0x%08x, insn = ", tf->tf_pc, 668129198Scognet *((u_int *)tf->tf_pc)); 669129198Scognet disassemble(tf->tf_pc); 670129198Scognet 671129198Scognet /* Die now if this happened in kernel mode */ 672129198Scognet if (!TRAP_USERMODE(tf)) 673129198Scognet dab_fatal(tf, 0, tf->tf_pc, NULL, ksig); 674129198Scognet 675129198Scognet return (error); 676129198Scognet#else 677129198Scognet return (ABORT_FIXUP_OK); 678129198Scognet#endif /* CPU_ABORT_FIXUP_REQUIRED */ 679129198Scognet} 680129198Scognet 681129198Scognet/* 682129198Scognet * void prefetch_abort_handler(trapframe_t *tf) 683129198Scognet * 684129198Scognet * Abort handler called when instruction execution occurs at 685129198Scognet * a non existent or restricted (access permissions) memory page. 686129198Scognet * If the address is invalid and we were in SVC mode then panic as 687129198Scognet * the kernel should never prefetch abort. 688129198Scognet * If the address is invalid and the page is mapped then the user process 689129198Scognet * does no have read permission so send it a signal. 690129198Scognet * Otherwise fault the page in and try again. 691129198Scognet */ 692129198Scognetvoid 693129198Scognetprefetch_abort_handler(trapframe_t *tf) 694129198Scognet{ 695129198Scognet struct thread *td; 696137275Scognet struct proc * p; 697129198Scognet struct vm_map *map; 698129198Scognet vm_offset_t fault_pc, va; 699129198Scognet int error = 0; 700129198Scognet u_int sticks = 0; 701129198Scognet struct ksig ksig; 702129198Scognet 703137275Scognet 704129198Scognet#if 0 705129198Scognet /* Update vmmeter statistics */ 706129198Scognet uvmexp.traps++; 707129198Scognet#endif 708135656Scognet#if 0 709135656Scognet printf("prefetch abort handler: %p %p\n", (void*)tf->tf_pc, 710135656Scognet (void*)tf->tf_usr_lr); 711135656Scognet#endif 712135656Scognet 713135656Scognet td = curthread; 714137275Scognet p = td->td_proc; 715137903Scognet atomic_add_int(&cnt.v_trap, 1); 716135656Scognet 717135656Scognet if (TRAP_USERMODE(tf)) { 718137275Scognet td->td_frame = tf; 719135656Scognet if (td->td_ucred != td->td_proc->p_ucred) 720135656Scognet cred_update_thread(td); 721137275Scognet if (td->td_proc->p_flag & P_SA) 722137275Scognet thread_user_enter(td); 723135656Scognet } 724135656Scognet fault_pc = tf->tf_pc; 725135656Scognet if (td->td_critnest == 0 && 726135656Scognet __predict_true((tf->tf_spsr & I32_bit) == 0)) 727129198Scognet enable_interrupts(I32_bit); 728129198Scognet 729135656Scognet 730129198Scognet /* See if the cpu state needs to be fixed up */ 731129198Scognet switch (prefetch_abort_fixup(tf, &ksig)) { 732129198Scognet case ABORT_FIXUP_RETURN: 733129198Scognet return; 734129198Scognet case ABORT_FIXUP_FAILED: 735129198Scognet /* Deliver a SIGILL to the process */ 736129198Scognet ksig.signb = SIGILL; 737129198Scognet ksig.code = 0; 738129198Scognet td->td_frame = tf; 739129198Scognet goto do_trapsignal; 740129198Scognet default: 741129198Scognet break; 742129198Scognet } 743129198Scognet 744129198Scognet /* Prefetch aborts cannot happen in kernel mode */ 745129198Scognet if (__predict_false(!TRAP_USERMODE(tf))) 746129198Scognet dab_fatal(tf, 0, tf->tf_pc, NULL, &ksig); 747129198Scognet sticks = td->td_sticks; 748129198Scognet 749135656Scognet 750129198Scognet /* Ok validate the address, can only execute in USER space */ 751129198Scognet if (__predict_false(fault_pc >= VM_MAXUSER_ADDRESS || 752129198Scognet (fault_pc < VM_MIN_ADDRESS && vector_page == ARM_VECTORS_LOW))) { 753129198Scognet ksig.signb = SIGSEGV; 754129198Scognet ksig.code = 0; 755129198Scognet goto do_trapsignal; 756129198Scognet } 757129198Scognet 758129198Scognet map = &td->td_proc->p_vmspace->vm_map; 759129198Scognet va = trunc_page(fault_pc); 760129198Scognet 761129198Scognet /* 762129198Scognet * See if the pmap can handle this fault on its own... 763129198Scognet */ 764129198Scognet#ifdef DEBUG 765129198Scognet last_fault_code = -1; 766129198Scognet#endif 767129198Scognet if (pmap_fault_fixup(map->pmap, va, VM_PROT_READ, 1)) 768129198Scognet goto out; 769129198Scognet 770137275Scognet if (map != kernel_map) { 771137275Scognet PROC_LOCK(p); 772137275Scognet p->p_lock++; 773137275Scognet PROC_UNLOCK(p); 774137275Scognet } 775137275Scognet 776135656Scognet error = vm_fault(map, va, VM_PROT_READ | VM_PROT_EXECUTE, 777129198Scognet VM_FAULT_NORMAL); 778137275Scognet if (map != kernel_map) { 779137275Scognet PROC_LOCK(p); 780137275Scognet p->p_lock--; 781137275Scognet PROC_UNLOCK(p); 782137275Scognet } 783137275Scognet 784129198Scognet if (__predict_true(error == 0)) 785129198Scognet goto out; 786129198Scognet 787129198Scognet if (error == ENOMEM) { 788129198Scognet printf("VM: pid %d (%s), uid %d killed: " 789129198Scognet "out of swap\n", td->td_proc->p_pid, td->td_proc->p_comm, 790129198Scognet (td->td_proc->p_ucred) ? 791129198Scognet td->td_proc->p_ucred->cr_uid : -1); 792129198Scognet ksig.signb = SIGKILL; 793129198Scognet } else { 794129198Scognet ksig.signb = SIGSEGV; 795129198Scognet } 796129198Scognet ksig.code = 0; 797129198Scognet 798129198Scognetdo_trapsignal: 799129198Scognet call_trapsignal(td, ksig.signb, ksig.code); 800129198Scognet 801129198Scognetout: 802129198Scognet userret(td, tf, sticks); 803135656Scognet 804129198Scognet} 805129198Scognet 806129198Scognetextern int badaddr_read_1(const uint8_t *, uint8_t *); 807129198Scognetextern int badaddr_read_2(const uint16_t *, uint16_t *); 808129198Scognetextern int badaddr_read_4(const uint32_t *, uint32_t *); 809129198Scognet/* 810129198Scognet * Tentatively read an 8, 16, or 32-bit value from 'addr'. 811129198Scognet * If the read succeeds, the value is written to 'rptr' and zero is returned. 812129198Scognet * Else, return EFAULT. 813129198Scognet */ 814129198Scognetint 815129198Scognetbadaddr_read(void *addr, size_t size, void *rptr) 816129198Scognet{ 817129198Scognet union { 818129198Scognet uint8_t v1; 819129198Scognet uint16_t v2; 820129198Scognet uint32_t v4; 821129198Scognet } u; 822129198Scognet int rv; 823129198Scognet 824129198Scognet cpu_drain_writebuf(); 825129198Scognet 826129198Scognet /* Read from the test address. */ 827129198Scognet switch (size) { 828129198Scognet case sizeof(uint8_t): 829129198Scognet rv = badaddr_read_1(addr, &u.v1); 830129198Scognet if (rv == 0 && rptr) 831129198Scognet *(uint8_t *) rptr = u.v1; 832129198Scognet break; 833129198Scognet 834129198Scognet case sizeof(uint16_t): 835129198Scognet rv = badaddr_read_2(addr, &u.v2); 836129198Scognet if (rv == 0 && rptr) 837129198Scognet *(uint16_t *) rptr = u.v2; 838129198Scognet break; 839129198Scognet 840129198Scognet case sizeof(uint32_t): 841129198Scognet rv = badaddr_read_4(addr, &u.v4); 842129198Scognet if (rv == 0 && rptr) 843129198Scognet *(uint32_t *) rptr = u.v4; 844129198Scognet break; 845129198Scognet 846129198Scognet default: 847129198Scognet panic("badaddr: invalid size (%lu)", (u_long) size); 848129198Scognet } 849129198Scognet 850129198Scognet /* Return EFAULT if the address was invalid, else zero */ 851129198Scognet return (rv); 852129198Scognet} 853129198Scognet 854129198Scognet#define MAXARGS 8 855129198Scognetstatic void 856129198Scognetsyscall(struct thread *td, trapframe_t *frame, u_int32_t insn) 857129198Scognet{ 858129198Scognet struct proc *p = td->td_proc; 859129198Scognet int code, error; 860129198Scognet u_int nap, nargs; 861129198Scognet register_t *ap, *args, copyargs[MAXARGS]; 862129198Scognet struct sysent *callp; 863129198Scognet int locked = 0; 864135656Scognet u_int sticks = 0; 865129198Scognet 866137903Scognet atomic_add_int(&cnt.v_syscall, 1); 867135656Scognet sticks = td->td_sticks; 868135656Scognet if (td->td_ucred != td->td_proc->p_ucred) 869135656Scognet cred_update_thread(td); 870129198Scognet switch (insn & SWI_OS_MASK) { 871129198Scognet case 0: /* XXX: we need our own one. */ 872129198Scognet nap = 4; 873129198Scognet break; 874129198Scognet default: 875129198Scognet trapsignal(td, SIGILL, 0); 876129198Scognet userret(td, frame, td->td_sticks); 877129198Scognet return; 878129198Scognet } 879129198Scognet code = insn & 0x000fffff; 880135656Scognet sticks = td->td_sticks; 881129198Scognet ap = &frame->tf_r0; 882129198Scognet if (code == SYS_syscall) { 883129198Scognet code = *ap++; 884129198Scognet 885129198Scognet nap--; 886129198Scognet } else if (code == SYS___syscall) { 887129198Scognet code = *ap++; 888129198Scognet nap -= 2; 889129198Scognet ap++; 890129198Scognet } 891129198Scognet if (p->p_sysent->sv_mask) 892129198Scognet code &= p->p_sysent->sv_mask; 893129198Scognet if (code >= p->p_sysent->sv_size) 894129198Scognet callp = &p->p_sysent->sv_table[0]; 895129198Scognet else 896129198Scognet callp = &p->p_sysent->sv_table[code]; 897129198Scognet nargs = callp->sy_narg & SYF_ARGMASK; 898137275Scognet memcpy(copyargs, ap, nap * sizeof(register_t)); 899137275Scognet if (nargs > nap) { 900129198Scognet error = copyin((void *)frame->tf_usr_sp, copyargs + nap, 901129198Scognet (nargs - nap) * sizeof(register_t)); 902129198Scognet if (error) 903129198Scognet goto bad; 904129198Scognet } 905137275Scognet args = copyargs; 906129198Scognet error = 0; 907135656Scognet#ifdef KTRACE 908135656Scognet if (KTRPOINT(td, KTR_SYSCALL)) 909135656Scognet ktrsyscall(code, nargs, args); 910135656Scognet#endif 911135656Scognet 912129198Scognet if ((callp->sy_narg & SYF_MPSAFE) == 0) 913129198Scognet mtx_lock(&Giant); 914129198Scognet locked = 1; 915129198Scognet if (error == 0) { 916129198Scognet td->td_retval[0] = 0; 917129198Scognet td->td_retval[1] = 0; 918129198Scognet error = (*callp->sy_call)(td, args); 919129198Scognet } 920129198Scognet switch (error) { 921129198Scognet case 0: 922129198Scognet frame->tf_r0 = td->td_retval[0]; 923129198Scognet frame->tf_r1 = td->td_retval[1]; 924129198Scognet 925129198Scognet frame->tf_spsr &= ~PSR_C_bit; /* carry bit */ 926129198Scognet break; 927129198Scognet 928129198Scognet case ERESTART: 929129198Scognet /* 930129198Scognet * Reconstruct the pc to point at the swi. 931129198Scognet */ 932129198Scognet frame->tf_pc -= INSN_SIZE; 933129198Scognet break; 934129198Scognet case EJUSTRETURN: 935129198Scognet /* nothing to do */ 936129198Scognet break; 937129198Scognet default: 938129198Scognetbad: 939129198Scognet frame->tf_r0 = error; 940129198Scognet frame->tf_spsr |= PSR_C_bit; /* carry bit */ 941129198Scognet break; 942129198Scognet } 943129198Scognet if (locked && (callp->sy_narg & SYF_MPSAFE) == 0) 944129198Scognet mtx_unlock(&Giant); 945129198Scognet 946129198Scognet 947135656Scognet userret(td, frame, sticks); 948135656Scognet#ifdef KTRACE 949135656Scognet if (KTRPOINT(td, KTR_SYSRET)) 950135656Scognet ktrsysret(code, error, td->td_retval[0]); 951135656Scognet#endif 952129198Scognet mtx_assert(&sched_lock, MA_NOTOWNED); 953129198Scognet mtx_assert(&Giant, MA_NOTOWNED); 954129198Scognet} 955129198Scognet 956129198Scognetvoid 957129198Scognetswi_handler(trapframe_t *frame) 958129198Scognet{ 959129198Scognet struct thread *td = curthread; 960129198Scognet uint32_t insn; 961129198Scognet 962137275Scognet td->td_frame = frame; 963135656Scognet 964137275Scognet if (td->td_proc->p_flag & P_SA) 965137275Scognet thread_user_enter(td); 966129198Scognet /* 967129198Scognet * Make sure the program counter is correctly aligned so we 968129198Scognet * don't take an alignment fault trying to read the opcode. 969129198Scognet */ 970129198Scognet if (__predict_false(((frame->tf_pc - INSN_SIZE) & 3) != 0)) { 971129198Scognet trapsignal(td, SIGILL, 0); 972129198Scognet userret(td, frame, td->td_sticks); 973129198Scognet return; 974129198Scognet } 975129198Scognet insn = *(u_int32_t *)(frame->tf_pc - INSN_SIZE); 976137275Scognet /* 977137275Scognet * Enable interrupts if they were enabled before the exception. 978137275Scognet * Since all syscalls *should* come from user mode it will always 979137275Scognet * be safe to enable them, but check anyway. 980137275Scognet */ 981137275Scognet if (td->td_critnest == 0 && !(frame->tf_spsr & I32_bit)) 982137275Scognet enable_interrupts(I32_bit); 983137275Scognet 984129198Scognet syscall(td, frame, insn); 985129198Scognet} 986129198Scognet 987