Annotation of sys/arch/arm/arm/undefined.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: undefined.c,v 1.3 2006/12/24 20:30:35 miod Exp $ */
! 2: /* $NetBSD: undefined.c,v 1.22 2003/11/29 22:21:29 bjh21 Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 2001 Ben Harris.
! 6: * Copyright (c) 1995 Mark Brinicombe.
! 7: * Copyright (c) 1995 Brini.
! 8: * All rights reserved.
! 9: *
! 10: * This code is derived from software written for Brini by Mark Brinicombe
! 11: *
! 12: * Redistribution and use in source and binary forms, with or without
! 13: * modification, are permitted provided that the following conditions
! 14: * are met:
! 15: * 1. Redistributions of source code must retain the above copyright
! 16: * notice, this list of conditions and the following disclaimer.
! 17: * 2. Redistributions in binary form must reproduce the above copyright
! 18: * notice, this list of conditions and the following disclaimer in the
! 19: * documentation and/or other materials provided with the distribution.
! 20: * 3. All advertising materials mentioning features or use of this software
! 21: * must display the following acknowledgement:
! 22: * This product includes software developed by Brini.
! 23: * 4. The name of the company nor the name of the author may be used to
! 24: * endorse or promote products derived from this software without specific
! 25: * prior written permission.
! 26: *
! 27: * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
! 28: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
! 29: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 30: * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
! 31: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
! 32: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
! 33: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 34: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 35: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 36: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 37: * SUCH DAMAGE.
! 38: *
! 39: * RiscBSD kernel project
! 40: *
! 41: * undefined.c
! 42: *
! 43: * Fault handler
! 44: *
! 45: * Created : 06/01/95
! 46: */
! 47:
! 48: #include <sys/param.h>
! 49:
! 50: #include <sys/malloc.h>
! 51: #include <sys/queue.h>
! 52: #include <sys/signal.h>
! 53: #include <sys/signalvar.h>
! 54: #include <sys/systm.h>
! 55: #include <sys/proc.h>
! 56: #include <sys/user.h>
! 57: #include <sys/syslog.h>
! 58: #include <sys/vmmeter.h>
! 59:
! 60: #include <uvm/uvm_extern.h>
! 61:
! 62: #include <machine/cpu.h>
! 63: #include <machine/frame.h>
! 64: #include <arm/undefined.h>
! 65: #include <machine/trap.h>
! 66:
! 67:
! 68: #ifdef acorn26
! 69: #include <machine/machdep.h>
! 70: #endif
! 71:
! 72: static int gdb_trapper(u_int, u_int, struct trapframe *, int);
! 73:
! 74: LIST_HEAD(, undefined_handler) undefined_handlers[MAX_COPROCS];
! 75:
! 76:
! 77: void *
! 78: install_coproc_handler(int coproc, undef_handler_t handler)
! 79: {
! 80: struct undefined_handler *uh;
! 81:
! 82: KASSERT(coproc >= 0 && coproc < MAX_COPROCS);
! 83: KASSERT(handler != NULL); /* Used to be legal. */
! 84:
! 85: /* XXX: M_TEMP??? */
! 86: MALLOC(uh, struct undefined_handler *, sizeof(*uh), M_TEMP, M_WAITOK);
! 87: uh->uh_handler = handler;
! 88: install_coproc_handler_static(coproc, uh);
! 89: return uh;
! 90: }
! 91:
! 92: void
! 93: install_coproc_handler_static(int coproc, struct undefined_handler *uh)
! 94: {
! 95:
! 96: LIST_INSERT_HEAD(&undefined_handlers[coproc], uh, uh_link);
! 97: }
! 98:
! 99: void
! 100: remove_coproc_handler(void *cookie)
! 101: {
! 102: struct undefined_handler *uh = cookie;
! 103:
! 104: LIST_REMOVE(uh, uh_link);
! 105: FREE(uh, M_TEMP);
! 106: }
! 107:
! 108:
! 109: static int
! 110: gdb_trapper(u_int addr, u_int insn, struct trapframe *frame, int code)
! 111: {
! 112: union sigval sv;
! 113: struct proc *p;
! 114: p = (curproc == NULL) ? &proc0 : curproc;
! 115:
! 116: if (insn == GDB_BREAKPOINT || insn == GDB5_BREAKPOINT) {
! 117: if (code == FAULT_USER) {
! 118: sv.sival_int = addr;
! 119: trapsignal(p, SIGTRAP, 0, TRAP_BRKPT, sv);
! 120: return 0;
! 121: }
! 122: #ifdef KGDB
! 123: return !kgdb_trap(T_BREAKPOINT, frame);
! 124: #endif
! 125: }
! 126: return 1;
! 127: }
! 128:
! 129: static struct undefined_handler gdb_uh;
! 130:
! 131: void
! 132: undefined_init()
! 133: {
! 134: int loop;
! 135:
! 136: /* Not actually necessary -- the initialiser is just NULL */
! 137: for (loop = 0; loop < MAX_COPROCS; ++loop)
! 138: LIST_INIT(&undefined_handlers[loop]);
! 139:
! 140: /* Install handler for GDB breakpoints */
! 141: gdb_uh.uh_handler = gdb_trapper;
! 142: install_coproc_handler_static(0, &gdb_uh);
! 143: }
! 144:
! 145:
! 146: void
! 147: undefinedinstruction(trapframe_t *frame)
! 148: {
! 149: struct proc *p;
! 150: u_int fault_pc;
! 151: int fault_instruction;
! 152: int fault_code;
! 153: int coprocessor;
! 154: struct undefined_handler *uh;
! 155: #ifdef VERBOSE_ARM32
! 156: int s;
! 157: #endif
! 158: union sigval sv;
! 159:
! 160: /* Enable interrupts if they were enabled before the exception. */
! 161: #ifdef acorn26
! 162: if ((frame->tf_r15 & R15_IRQ_DISABLE) == 0)
! 163: int_on();
! 164: #else
! 165: if (!(frame->tf_spsr & I32_bit))
! 166: enable_interrupts(I32_bit);
! 167: #endif
! 168:
! 169: #ifndef acorn26
! 170: frame->tf_pc -= INSN_SIZE;
! 171: #endif
! 172:
! 173: #ifdef __PROG26
! 174: fault_pc = frame->tf_r15 & R15_PC;
! 175: #else
! 176: fault_pc = frame->tf_pc;
! 177: #endif
! 178:
! 179: /* Get the current proc structure or proc0 if there is none. */
! 180: p = (curproc == NULL) ? &proc0 : curproc;
! 181:
! 182: /*
! 183: * Make sure the program counter is correctly aligned so we
! 184: * don't take an alignment fault trying to read the opcode.
! 185: */
! 186: if (__predict_false((fault_pc & 3) != 0)) {
! 187: /* Give the user an illegal instruction signal. */
! 188: sv.sival_int = (u_int32_t) fault_pc;
! 189: trapsignal(p, SIGILL, 0, ILL_ILLOPC, sv);
! 190: userret(p);
! 191: return;
! 192: }
! 193:
! 194: /*
! 195: * Should use fuword() here .. but in the interests of squeezing every
! 196: * bit of speed we will just use ReadWord(). We know the instruction
! 197: * can be read as was just executed so this will never fail unless the
! 198: * kernel is screwed up in which case it does not really matter does
! 199: * it ?
! 200: */
! 201:
! 202: fault_instruction = *(u_int32_t *)fault_pc;
! 203:
! 204: /* Update vmmeter statistics */
! 205: uvmexp.traps++;
! 206:
! 207: /* Check for coprocessor instruction */
! 208:
! 209: /*
! 210: * According to the datasheets you only need to look at bit 27 of the
! 211: * instruction to tell the difference between and undefined
! 212: * instruction and a coprocessor instruction following an undefined
! 213: * instruction trap.
! 214: */
! 215:
! 216: if ((fault_instruction & (1 << 27)) != 0)
! 217: coprocessor = (fault_instruction >> 8) & 0x0f;
! 218: else
! 219: coprocessor = 0;
! 220:
! 221: #ifdef __PROG26
! 222: if ((frame->tf_r15 & R15_MODE) == R15_MODE_USR)
! 223: #else
! 224: if ((frame->tf_spsr & PSR_MODE) == PSR_USR32_MODE)
! 225: #endif
! 226: {
! 227: /*
! 228: * Modify the fault_code to reflect the USR/SVC state at
! 229: * time of fault.
! 230: */
! 231: fault_code = FAULT_USER;
! 232: p->p_addr->u_pcb.pcb_tf = frame;
! 233: } else
! 234: fault_code = 0;
! 235:
! 236: /* OK this is were we do something about the instruction. */
! 237: LIST_FOREACH(uh, &undefined_handlers[coprocessor], uh_link)
! 238: if (uh->uh_handler(fault_pc, fault_instruction, frame,
! 239: fault_code) == 0)
! 240: break;
! 241:
! 242: if (uh == NULL) {
! 243: /* Fault has not been handled */
! 244:
! 245: #ifdef VERBOSE_ARM32
! 246: s = spltty();
! 247:
! 248: if ((fault_instruction & 0x0f000010) == 0x0e000000) {
! 249: printf("CDP\n");
! 250: disassemble(fault_pc);
! 251: } else if ((fault_instruction & 0x0e000000) == 0x0c000000) {
! 252: printf("LDC/STC\n");
! 253: disassemble(fault_pc);
! 254: } else if ((fault_instruction & 0x0f000010) == 0x0e000010) {
! 255: printf("MRC/MCR\n");
! 256: disassemble(fault_pc);
! 257: } else if ((fault_instruction & ~INSN_COND_MASK)
! 258: != (KERNEL_BREAKPOINT & ~INSN_COND_MASK)) {
! 259: printf("Undefined instruction\n");
! 260: disassemble(fault_pc);
! 261: }
! 262:
! 263: splx(s);
! 264: #endif
! 265:
! 266: if ((fault_code & FAULT_USER) == 0) {
! 267: printf("Undefined instruction in kernel\n");
! 268: #ifdef DDB
! 269: Debugger();
! 270: #endif
! 271: }
! 272:
! 273: sv.sival_int = frame->tf_pc;
! 274: trapsignal(p, SIGILL, 0, ILL_ILLOPC, sv);
! 275: }
! 276:
! 277: if ((fault_code & FAULT_USER) == 0)
! 278: return;
! 279:
! 280: userret(p);
! 281: }
CVSweb