1 /* $OpenBSD: undefined.c,v 1.16 2021/05/16 03:39:27 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 58 #include <uvm/uvm_extern.h> 59 60 #include <machine/cpu.h> 61 #include <machine/frame.h> 62 #include <arm/undefined.h> 63 #include <arm/vfp.h> 64 #include <machine/trap.h> 65 66 67 static int gdb_trapper(u_int, u_int, struct trapframe *, int, uint32_t); 68 69 LIST_HEAD(, undefined_handler) undefined_handlers[MAX_COPROCS]; 70 71 72 void * 73 install_coproc_handler(int coproc, undef_handler_t handler) 74 { 75 struct undefined_handler *uh; 76 77 KASSERT(coproc >= 0 && coproc < MAX_COPROCS); 78 KASSERT(handler != NULL); /* Used to be legal. */ 79 80 /* XXX: M_TEMP??? */ 81 uh = (struct undefined_handler *)malloc(sizeof(*uh), M_TEMP, M_WAITOK); 82 uh->uh_handler = handler; 83 install_coproc_handler_static(coproc, uh); 84 return uh; 85 } 86 87 void 88 install_coproc_handler_static(int coproc, struct undefined_handler *uh) 89 { 90 91 LIST_INSERT_HEAD(&undefined_handlers[coproc], uh, uh_link); 92 } 93 94 void 95 remove_coproc_handler(void *cookie) 96 { 97 struct undefined_handler *uh = cookie; 98 99 LIST_REMOVE(uh, uh_link); 100 free(uh, M_TEMP, 0); 101 } 102 103 104 static int 105 gdb_trapper(u_int addr, u_int insn, struct trapframe *frame, int code, uint32_t fpexc) 106 { 107 union sigval sv; 108 struct proc *p; 109 p = (curproc == NULL) ? &proc0 : curproc; 110 111 if (insn == GDB_BREAKPOINT || insn == GDB5_BREAKPOINT) { 112 if (code == FAULT_USER) { 113 sv.sival_int = addr; 114 trapsignal(p, SIGTRAP, 0, TRAP_BRKPT, sv); 115 return 0; 116 } 117 } 118 return 1; 119 } 120 121 static struct undefined_handler gdb_uh; 122 123 void 124 undefined_init(void) 125 { 126 int loop; 127 128 /* Not actually necessary -- the initialiser is just NULL */ 129 for (loop = 0; loop < MAX_COPROCS; ++loop) 130 LIST_INIT(&undefined_handlers[loop]); 131 132 /* Install handler for GDB breakpoints */ 133 gdb_uh.uh_handler = gdb_trapper; 134 install_coproc_handler_static(0, &gdb_uh); 135 } 136 137 138 void 139 undefinedinstruction(trapframe_t *frame) 140 { 141 struct proc *p; 142 u_int fault_pc; 143 int fault_instruction; 144 int fault_code; 145 int coprocessor; 146 struct undefined_handler *uh; 147 uint32_t fpexc; 148 #ifdef VERBOSE_ARM32 149 int s; 150 #endif 151 union sigval sv; 152 153 /* Before enabling interrupts, save FPU state */ 154 fpexc = vfp_save(); 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 coprocessor = 0; 201 if ((fault_instruction & (1 << 27)) != 0) 202 coprocessor = (fault_instruction >> 8) & 0x0f; 203 else { /* check for special instructions */ 204 if (((fault_instruction & 0xfe000000) == 0xf2000000) || 205 ((fault_instruction & 0xff100000) == 0xf4000000)) 206 coprocessor = 10; /* vfp / simd */ 207 } 208 209 if ((frame->tf_spsr & PSR_MODE) == PSR_USR32_MODE) { 210 /* 211 * Modify the fault_code to reflect the USR/SVC state at 212 * time of fault. 213 */ 214 fault_code = FAULT_USER; 215 p->p_addr->u_pcb.pcb_tf = frame; 216 } else 217 fault_code = 0; 218 219 /* OK this is were we do something about the instruction. */ 220 LIST_FOREACH(uh, &undefined_handlers[coprocessor], uh_link) 221 if (uh->uh_handler(fault_pc, fault_instruction, frame, 222 fault_code, fpexc) == 0) 223 break; 224 225 if (uh == NULL) { 226 /* Fault has not been handled */ 227 228 #ifdef VERBOSE_ARM32 229 s = spltty(); 230 231 if ((fault_instruction & 0x0f000010) == 0x0e000000) { 232 printf("CDP\n"); 233 disassemble(fault_pc); 234 } else if ((fault_instruction & 0x0e000000) == 0x0c000000) { 235 printf("LDC/STC\n"); 236 disassemble(fault_pc); 237 } else if ((fault_instruction & 0x0f000010) == 0x0e000010) { 238 printf("MRC/MCR\n"); 239 disassemble(fault_pc); 240 } else if ((fault_instruction & ~INSN_COND_MASK) 241 != (KERNEL_BREAKPOINT & ~INSN_COND_MASK)) { 242 printf("Undefined instruction\n"); 243 disassemble(fault_pc); 244 } 245 246 splx(s); 247 #endif 248 249 if ((fault_code & FAULT_USER) == 0) { 250 printf("Undefined instruction in kernel\n"); 251 #ifdef DDB 252 db_enter(); 253 #endif 254 } 255 256 sv.sival_int = frame->tf_pc; 257 trapsignal(p, SIGILL, 0, ILL_ILLOPC, sv); 258 } 259 260 if ((fault_code & FAULT_USER) == 0) 261 return; 262 263 userret(p); 264 } 265