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