1 /* $OpenBSD: undefined.c,v 1.8 2016/06/10 06:32:36 jsg 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 static int gdb_trapper(u_int, u_int, struct trapframe *, int); 69 70 LIST_HEAD(, undefined_handler) undefined_handlers[MAX_COPROCS]; 71 72 73 void * 74 install_coproc_handler(int coproc, undef_handler_t handler) 75 { 76 struct undefined_handler *uh; 77 78 KASSERT(coproc >= 0 && coproc < MAX_COPROCS); 79 KASSERT(handler != NULL); /* Used to be legal. */ 80 81 /* XXX: M_TEMP??? */ 82 uh = (struct undefined_handler *)malloc(sizeof(*uh), M_TEMP, M_WAITOK); 83 uh->uh_handler = handler; 84 install_coproc_handler_static(coproc, uh); 85 return uh; 86 } 87 88 void 89 install_coproc_handler_static(int coproc, struct undefined_handler *uh) 90 { 91 92 LIST_INSERT_HEAD(&undefined_handlers[coproc], uh, uh_link); 93 } 94 95 void 96 remove_coproc_handler(void *cookie) 97 { 98 struct undefined_handler *uh = cookie; 99 100 LIST_REMOVE(uh, uh_link); 101 free(uh, M_TEMP, 0); 102 } 103 104 105 static int 106 gdb_trapper(u_int addr, u_int insn, struct trapframe *frame, int code) 107 { 108 union sigval sv; 109 struct proc *p; 110 p = (curproc == NULL) ? &proc0 : curproc; 111 112 if (insn == GDB_BREAKPOINT || insn == GDB5_BREAKPOINT) { 113 if (code == FAULT_USER) { 114 sv.sival_int = addr; 115 trapsignal(p, SIGTRAP, 0, TRAP_BRKPT, sv); 116 return 0; 117 } 118 #ifdef KGDB 119 return !kgdb_trap(T_BREAKPOINT, frame); 120 #endif 121 } 122 return 1; 123 } 124 125 static struct undefined_handler gdb_uh; 126 127 void 128 undefined_init() 129 { 130 int loop; 131 132 /* Not actually necessary -- the initialiser is just NULL */ 133 for (loop = 0; loop < MAX_COPROCS; ++loop) 134 LIST_INIT(&undefined_handlers[loop]); 135 136 /* Install handler for GDB breakpoints */ 137 gdb_uh.uh_handler = gdb_trapper; 138 install_coproc_handler_static(0, &gdb_uh); 139 } 140 141 142 void 143 undefinedinstruction(trapframe_t *frame) 144 { 145 struct proc *p; 146 u_int fault_pc; 147 int fault_instruction; 148 int fault_code; 149 int coprocessor; 150 struct undefined_handler *uh; 151 #ifdef VERBOSE_ARM32 152 int s; 153 #endif 154 union sigval sv; 155 156 /* Enable interrupts if they were enabled before the exception. */ 157 if (!(frame->tf_spsr & PSR_I)) 158 enable_interrupts(PSR_I); 159 160 frame->tf_pc -= INSN_SIZE; 161 fault_pc = frame->tf_pc; 162 163 /* Get the current proc structure or proc0 if there is none. */ 164 p = (curproc == NULL) ? &proc0 : curproc; 165 166 /* 167 * Make sure the program counter is correctly aligned so we 168 * don't take an alignment fault trying to read the opcode. 169 */ 170 if (__predict_false((fault_pc & 3) != 0)) { 171 /* Give the user an illegal instruction signal. */ 172 sv.sival_int = (u_int32_t) fault_pc; 173 trapsignal(p, SIGILL, 0, ILL_ILLOPC, sv); 174 userret(p); 175 return; 176 } 177 178 /* 179 * Should use copyin() here .. but in the interests of squeezing every 180 * bit of speed we will just read it directly. We know the instruction 181 * can be read as was just executed so this will never fail unless the 182 * kernel is screwed up in which case it does not really matter does 183 * it? 184 */ 185 186 fault_instruction = *(u_int32_t *)fault_pc; 187 188 /* Update vmmeter statistics */ 189 uvmexp.traps++; 190 191 /* Check for coprocessor instruction */ 192 193 /* 194 * According to the datasheets you only need to look at bit 27 of the 195 * instruction to tell the difference between an undefined 196 * instruction and a coprocessor instruction following an undefined 197 * instruction trap. 198 */ 199 200 if ((fault_instruction & (1 << 27)) != 0) 201 coprocessor = (fault_instruction >> 8) & 0x0f; 202 else 203 coprocessor = 0; 204 205 if ((frame->tf_spsr & PSR_MODE) == PSR_USR32_MODE) { 206 /* 207 * Modify the fault_code to reflect the USR/SVC state at 208 * time of fault. 209 */ 210 fault_code = FAULT_USER; 211 p->p_addr->u_pcb.pcb_tf = frame; 212 } else 213 fault_code = 0; 214 215 /* OK this is were we do something about the instruction. */ 216 LIST_FOREACH(uh, &undefined_handlers[coprocessor], uh_link) 217 if (uh->uh_handler(fault_pc, fault_instruction, frame, 218 fault_code) == 0) 219 break; 220 221 if (uh == NULL) { 222 /* Fault has not been handled */ 223 224 #ifdef VERBOSE_ARM32 225 s = spltty(); 226 227 if ((fault_instruction & 0x0f000010) == 0x0e000000) { 228 printf("CDP\n"); 229 disassemble(fault_pc); 230 } else if ((fault_instruction & 0x0e000000) == 0x0c000000) { 231 printf("LDC/STC\n"); 232 disassemble(fault_pc); 233 } else if ((fault_instruction & 0x0f000010) == 0x0e000010) { 234 printf("MRC/MCR\n"); 235 disassemble(fault_pc); 236 } else if ((fault_instruction & ~INSN_COND_MASK) 237 != (KERNEL_BREAKPOINT & ~INSN_COND_MASK)) { 238 printf("Undefined instruction\n"); 239 disassemble(fault_pc); 240 } 241 242 splx(s); 243 #endif 244 245 if ((fault_code & FAULT_USER) == 0) { 246 printf("Undefined instruction in kernel\n"); 247 #ifdef DDB 248 Debugger(); 249 #endif 250 } 251 252 sv.sival_int = frame->tf_pc; 253 trapsignal(p, SIGILL, 0, ILL_ILLOPC, sv); 254 } 255 256 if ((fault_code & FAULT_USER) == 0) 257 return; 258 259 userret(p); 260 } 261