undefined.c revision 156166
1129198Scognet/* $NetBSD: undefined.c,v 1.22 2003/11/29 22:21:29 bjh21 Exp $ */ 2129198Scognet 3139735Simp/*- 4129198Scognet * Copyright (c) 2001 Ben Harris. 5129198Scognet * Copyright (c) 1995 Mark Brinicombe. 6129198Scognet * Copyright (c) 1995 Brini. 7129198Scognet * All rights reserved. 8129198Scognet * 9129198Scognet * This code is derived from software written for Brini by Mark Brinicombe 10129198Scognet * 11129198Scognet * Redistribution and use in source and binary forms, with or without 12129198Scognet * modification, are permitted provided that the following conditions 13129198Scognet * are met: 14129198Scognet * 1. Redistributions of source code must retain the above copyright 15129198Scognet * notice, this list of conditions and the following disclaimer. 16129198Scognet * 2. Redistributions in binary form must reproduce the above copyright 17129198Scognet * notice, this list of conditions and the following disclaimer in the 18129198Scognet * documentation and/or other materials provided with the distribution. 19129198Scognet * 3. All advertising materials mentioning features or use of this software 20129198Scognet * must display the following acknowledgement: 21129198Scognet * This product includes software developed by Brini. 22129198Scognet * 4. The name of the company nor the name of the author may be used to 23129198Scognet * endorse or promote products derived from this software without specific 24129198Scognet * prior written permission. 25129198Scognet * 26129198Scognet * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED 27129198Scognet * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 28129198Scognet * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 29129198Scognet * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 30129198Scognet * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 31129198Scognet * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 32129198Scognet * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33129198Scognet * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34129198Scognet * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35129198Scognet * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36129198Scognet * SUCH DAMAGE. 37129198Scognet * 38129198Scognet * RiscBSD kernel project 39129198Scognet * 40129198Scognet * undefined.c 41129198Scognet * 42129198Scognet * Fault handler 43129198Scognet * 44129198Scognet * Created : 06/01/95 45129198Scognet */ 46129198Scognet 47129198Scognet 48137975Scognet#include "opt_ddb.h" 49137975Scognet 50129198Scognet#include <sys/cdefs.h> 51129198Scognet__FBSDID("$FreeBSD: head/sys/arm/arm/undefined.c 156166 2006-03-01 18:33:45Z cognet $"); 52129198Scognet 53129198Scognet#include <sys/param.h> 54129198Scognet#include <sys/malloc.h> 55129198Scognet#include <sys/queue.h> 56129198Scognet#include <sys/signal.h> 57129198Scognet#include <sys/systm.h> 58129198Scognet#include <sys/proc.h> 59129198Scognet#include <sys/syslog.h> 60129198Scognet#include <sys/vmmeter.h> 61129198Scognet#include <sys/types.h> 62129198Scognet#include <sys/lock.h> 63129198Scognet#include <sys/mutex.h> 64138525Scognet#include <sys/signalvar.h> 65140001Scognet#include <sys/ptrace.h> 66137940Scognet#ifdef KDB 67137940Scognet#include <sys/kdb.h> 68137940Scognet#endif 69129198Scognet#ifdef FAST_FPE 70129198Scognet#include <sys/acct.h> 71129198Scognet#endif 72129198Scognet 73129198Scognet#include <vm/vm.h> 74129198Scognet#include <vm/vm_extern.h> 75129198Scognet 76129198Scognet#include <machine/asm.h> 77129198Scognet#include <machine/cpu.h> 78129198Scognet#include <machine/frame.h> 79129198Scognet#include <machine/undefined.h> 80129198Scognet#include <machine/trap.h> 81129198Scognet 82129198Scognet#include <machine/disassem.h> 83129198Scognet 84129198Scognet#ifdef DDB 85129198Scognet#include <ddb/db_output.h> 86129198Scognet#include <machine/db_machdep.h> 87129198Scognet#endif 88129198Scognet 89129198Scognet#ifdef acorn26 90129198Scognet#include <machine/machdep.h> 91129198Scognet#endif 92129198Scognet 93129198Scognetstatic int gdb_trapper(u_int, u_int, struct trapframe *, int); 94129198Scognet#ifdef FAST_FPE 95129198Scognetextern int want_resched; 96129198Scognet#endif 97129198Scognet 98129198ScognetLIST_HEAD(, undefined_handler) undefined_handlers[MAX_COPROCS]; 99129198Scognet 100129198Scognet 101129198Scognetvoid * 102129198Scognetinstall_coproc_handler(int coproc, undef_handler_t handler) 103129198Scognet{ 104129198Scognet struct undefined_handler *uh; 105129198Scognet 106129198Scognet KASSERT(coproc >= 0 && coproc < MAX_COPROCS, ("bad coproc")); 107129198Scognet KASSERT(handler != NULL, ("handler is NULL")); /* Used to be legal. */ 108129198Scognet 109129198Scognet /* XXX: M_TEMP??? */ 110129198Scognet MALLOC(uh, struct undefined_handler *, sizeof(*uh), M_TEMP, M_WAITOK); 111129198Scognet uh->uh_handler = handler; 112129198Scognet install_coproc_handler_static(coproc, uh); 113129198Scognet return uh; 114129198Scognet} 115129198Scognet 116129198Scognetvoid 117129198Scognetinstall_coproc_handler_static(int coproc, struct undefined_handler *uh) 118129198Scognet{ 119129198Scognet 120129198Scognet LIST_INSERT_HEAD(&undefined_handlers[coproc], uh, uh_link); 121129198Scognet} 122129198Scognet 123129198Scognetvoid 124129198Scognetremove_coproc_handler(void *cookie) 125129198Scognet{ 126129198Scognet struct undefined_handler *uh = cookie; 127129198Scognet 128129198Scognet LIST_REMOVE(uh, uh_link); 129129198Scognet FREE(uh, M_TEMP); 130129198Scognet} 131129198Scognet 132129198Scognet 133129198Scognetstatic int 134129198Scognetgdb_trapper(u_int addr, u_int insn, struct trapframe *frame, int code) 135129198Scognet{ 136129198Scognet struct thread *td; 137151316Sdavidxu ksiginfo_t ksi; 138151316Sdavidxu 139129198Scognet td = (curthread == NULL) ? &thread0 : curthread; 140129198Scognet 141129198Scognet if (insn == GDB_BREAKPOINT || insn == GDB5_BREAKPOINT) { 142129198Scognet if (code == FAULT_USER) { 143151316Sdavidxu ksiginfo_init_trap(&ksi); 144151316Sdavidxu ksi.ksi_signo = SIGTRAP; 145151316Sdavidxu ksi.ksi_code = TRAP_BRKPT; 146151316Sdavidxu ksi.ksi_addr = (u_int32_t *)addr; 147151316Sdavidxu trapsignal(td, &ksi); 148129198Scognet return 0; 149129198Scognet } 150140001Scognet#if 0 151129198Scognet#ifdef KGDB 152129198Scognet return !kgdb_trap(T_BREAKPOINT, frame); 153129198Scognet#endif 154140001Scognet#endif 155129198Scognet } 156129198Scognet return 1; 157129198Scognet} 158129198Scognet 159129198Scognetstatic struct undefined_handler gdb_uh; 160129198Scognet 161129198Scognetvoid 162129198Scognetundefined_init() 163129198Scognet{ 164129198Scognet int loop; 165129198Scognet 166129198Scognet /* Not actually necessary -- the initialiser is just NULL */ 167129198Scognet for (loop = 0; loop < MAX_COPROCS; ++loop) 168129198Scognet LIST_INIT(&undefined_handlers[loop]); 169129198Scognet 170129198Scognet /* Install handler for GDB breakpoints */ 171129198Scognet gdb_uh.uh_handler = gdb_trapper; 172129198Scognet install_coproc_handler_static(0, &gdb_uh); 173129198Scognet} 174129198Scognet 175129198Scognet 176129198Scognetvoid 177129198Scognetundefinedinstruction(trapframe_t *frame) 178129198Scognet{ 179129198Scognet struct thread *td; 180129198Scognet u_int fault_pc; 181129198Scognet int fault_instruction; 182129198Scognet int fault_code; 183129198Scognet int coprocessor; 184129198Scognet struct undefined_handler *uh; 185129198Scognet#ifdef VERBOSE_ARM32 186129198Scognet int s; 187129198Scognet#endif 188151316Sdavidxu ksiginfo_t ksi; 189129198Scognet 190129198Scognet /* Enable interrupts if they were enabled before the exception. */ 191129198Scognet if (!(frame->tf_spsr & I32_bit)) 192129198Scognet enable_interrupts(I32_bit); 193129198Scognet 194129198Scognet frame->tf_pc -= INSN_SIZE; 195144971Sjhb PCPU_LAZY_INC(cnt.v_trap); 196129198Scognet 197129198Scognet fault_pc = frame->tf_pc; 198129198Scognet 199129198Scognet /* 200129198Scognet * Get the current thread/proc structure or thread0/proc0 if there is 201129198Scognet * none. 202129198Scognet */ 203129198Scognet td = curthread == NULL ? &thread0 : curthread; 204129198Scognet 205129198Scognet /* 206129198Scognet * Make sure the program counter is correctly aligned so we 207129198Scognet * don't take an alignment fault trying to read the opcode. 208129198Scognet */ 209129198Scognet if (__predict_false((fault_pc & 3) != 0)) { 210151316Sdavidxu ksiginfo_init_trap(&ksi); 211151316Sdavidxu ksi.ksi_signo = SIGILL; 212151316Sdavidxu ksi.ksi_code = ILL_ILLADR; 213151316Sdavidxu ksi.ksi_addr = (u_int32_t *)(intptr_t) fault_pc; 214151316Sdavidxu trapsignal(td, &ksi); 215156166Scognet userret(td, frame); 216129198Scognet return; 217129198Scognet } 218129198Scognet 219129198Scognet /* 220129198Scognet * Should use fuword() here .. but in the interests of squeezing every 221129198Scognet * bit of speed we will just use ReadWord(). We know the instruction 222129198Scognet * can be read as was just executed so this will never fail unless the 223129198Scognet * kernel is screwed up in which case it does not really matter does 224129198Scognet * it ? 225129198Scognet */ 226129198Scognet 227129198Scognet fault_instruction = *(u_int32_t *)fault_pc; 228129198Scognet 229129198Scognet /* Update vmmeter statistics */ 230129198Scognet#if 0 231129198Scognet uvmexp.traps++; 232129198Scognet#endif 233129198Scognet /* Check for coprocessor instruction */ 234129198Scognet 235129198Scognet /* 236129198Scognet * According to the datasheets you only need to look at bit 27 of the 237129198Scognet * instruction to tell the difference between and undefined 238129198Scognet * instruction and a coprocessor instruction following an undefined 239129198Scognet * instruction trap. 240129198Scognet */ 241129198Scognet 242129198Scognet if ((fault_instruction & (1 << 27)) != 0) 243129198Scognet coprocessor = (fault_instruction >> 8) & 0x0f; 244129198Scognet else 245129198Scognet coprocessor = 0; 246129198Scognet 247129198Scognet if ((frame->tf_spsr & PSR_MODE) == PSR_USR32_MODE) { 248129198Scognet /* 249129198Scognet * Modify the fault_code to reflect the USR/SVC state at 250129198Scognet * time of fault. 251129198Scognet */ 252129198Scognet fault_code = FAULT_USER; 253129198Scognet td->td_frame = frame; 254129198Scognet } else 255129198Scognet fault_code = 0; 256129198Scognet 257129198Scognet /* OK this is were we do something about the instruction. */ 258129198Scognet LIST_FOREACH(uh, &undefined_handlers[coprocessor], uh_link) 259129198Scognet if (uh->uh_handler(fault_pc, fault_instruction, frame, 260129198Scognet fault_code) == 0) 261129198Scognet break; 262129198Scognet 263140001Scognet if (fault_code & FAULT_USER && fault_instruction == PTRACE_BREAKPOINT) { 264155922Sjhb PROC_LOCK(td->td_proc); 265155922Sjhb _PHOLD(td->td_proc); 266140001Scognet ptrace_clear_single_step(td); 267155922Sjhb _PRELE(td->td_proc); 268155922Sjhb PROC_UNLOCK(td->td_proc); 269140001Scognet return; 270140001Scognet } 271140001Scognet 272137940Scognet if (uh == NULL && (fault_code & FAULT_USER)) { 273129198Scognet /* Fault has not been handled */ 274151316Sdavidxu ksiginfo_init_trap(&ksi); 275151316Sdavidxu ksi.ksi_signo = SIGILL; 276151316Sdavidxu ksi.ksi_code = ILL_ILLOPC; 277151316Sdavidxu ksi.ksi_addr = (u_int32_t *)(intptr_t) fault_pc; 278151316Sdavidxu trapsignal(td, &ksi); 279129198Scognet } 280129198Scognet 281137940Scognet if ((fault_code & FAULT_USER) == 0) { 282137940Scognet if (fault_instruction == KERNEL_BREAKPOINT) { 283137940Scognet#ifdef KDB 284155241Simp kdb_trap(T_BREAKPOINT, 0, frame); 285137940Scognet#else 286155241Simp printf("No debugger in kernel.\n"); 287137940Scognet#endif 288155241Simp return; 289137975Scognet } else 290137940Scognet panic("Undefined instruction in kernel.\n"); 291140001Scognet } 292129198Scognet 293129198Scognet#ifdef FAST_FPE 294129198Scognet /* Optimised exit code */ 295129198Scognet { 296129198Scognet 297129198Scognet /* 298129198Scognet * Check for reschedule request, at the moment there is only 299129198Scognet * 1 ast so this code should always be run 300129198Scognet */ 301129198Scognet 302129198Scognet if (want_resched) { 303129198Scognet /* 304129198Scognet * We are being preempted. 305129198Scognet */ 306129198Scognet preempt(0); 307129198Scognet } 308129198Scognet 309129198Scognet /* Invoke MI userret code */ 310129198Scognet mi_userret(td); 311129198Scognet 312129198Scognet#if 0 313129198Scognet l->l_priority = l->l_usrpri; 314129198Scognet 315129198Scognet curcpu()->ci_schedstate.spc_curpriority = l->l_priority; 316129198Scognet#endif 317129198Scognet } 318129198Scognet 319129198Scognet#else 320156166Scognet userret(td, frame); 321129198Scognet#endif 322129198Scognet} 323