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: stable/11/sys/arm/arm/undefined.c 331722 2018-03-29 02:50:57Z eadler $"); 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/lock.h> 62129198Scognet#include <sys/mutex.h> 63138525Scognet#include <sys/signalvar.h> 64140001Scognet#include <sys/ptrace.h> 65331017Skevans#include <sys/vmmeter.h> 66137940Scognet#ifdef KDB 67137940Scognet#include <sys/kdb.h> 68137940Scognet#endif 69129198Scognet 70129198Scognet#include <vm/vm.h> 71129198Scognet#include <vm/vm_extern.h> 72129198Scognet 73271398Sandrew#include <machine/armreg.h> 74129198Scognet#include <machine/asm.h> 75129198Scognet#include <machine/cpu.h> 76129198Scognet#include <machine/frame.h> 77129198Scognet#include <machine/undefined.h> 78129198Scognet#include <machine/trap.h> 79129198Scognet 80129198Scognet#include <machine/disassem.h> 81129198Scognet 82129198Scognet#ifdef DDB 83129198Scognet#include <ddb/db_output.h> 84129198Scognet#endif 85129198Scognet 86196484Scognet#ifdef KDB 87196484Scognet#include <machine/db_machdep.h> 88129198Scognet#endif 89129198Scognet 90282779Sandrew#define ARM_COPROC_INSN(insn) (((insn) & (1 << 27)) != 0) 91282779Sandrew#define ARM_VFP_INSN(insn) ((((insn) & 0xfe000000) == 0xf2000000) || \ 92282779Sandrew (((insn) & 0xff100000) == 0xf4000000)) 93282779Sandrew#define ARM_COPROC(insn) (((insn) >> 8) & 0xf) 94282779Sandrew 95282779Sandrew#define THUMB_32BIT_INSN(insn) ((insn) >= 0xe800) 96282779Sandrew#define THUMB_COPROC_INSN(insn) (((insn) & (3 << 26)) == (3 << 26)) 97282779Sandrew#define THUMB_COPROC_UNDEFINED(insn) (((insn) & 0x3e << 20) == 0) 98282779Sandrew#define THUMB_VFP_INSN(insn) (((insn) & (3 << 24)) == (3 << 24)) 99282779Sandrew#define THUMB_COPROC(insn) (((insn) >> 8) & 0xf) 100282779Sandrew 101282779Sandrew#define COPROC_VFP 10 102282779Sandrew 103129198Scognetstatic int gdb_trapper(u_int, u_int, struct trapframe *, int); 104129198Scognet 105129198ScognetLIST_HEAD(, undefined_handler) undefined_handlers[MAX_COPROCS]; 106129198Scognet 107129198Scognet 108129198Scognetvoid * 109129198Scognetinstall_coproc_handler(int coproc, undef_handler_t handler) 110129198Scognet{ 111129198Scognet struct undefined_handler *uh; 112129198Scognet 113129198Scognet KASSERT(coproc >= 0 && coproc < MAX_COPROCS, ("bad coproc")); 114129198Scognet KASSERT(handler != NULL, ("handler is NULL")); /* Used to be legal. */ 115129198Scognet 116129198Scognet /* XXX: M_TEMP??? */ 117184205Sdes uh = malloc(sizeof(*uh), M_TEMP, M_WAITOK); 118129198Scognet uh->uh_handler = handler; 119129198Scognet install_coproc_handler_static(coproc, uh); 120129198Scognet return uh; 121129198Scognet} 122129198Scognet 123129198Scognetvoid 124129198Scognetinstall_coproc_handler_static(int coproc, struct undefined_handler *uh) 125129198Scognet{ 126129198Scognet 127129198Scognet LIST_INSERT_HEAD(&undefined_handlers[coproc], uh, uh_link); 128129198Scognet} 129129198Scognet 130129198Scognetvoid 131129198Scognetremove_coproc_handler(void *cookie) 132129198Scognet{ 133129198Scognet struct undefined_handler *uh = cookie; 134129198Scognet 135129198Scognet LIST_REMOVE(uh, uh_link); 136184205Sdes free(uh, M_TEMP); 137129198Scognet} 138129198Scognet 139129198Scognet 140129198Scognetstatic int 141129198Scognetgdb_trapper(u_int addr, u_int insn, struct trapframe *frame, int code) 142129198Scognet{ 143129198Scognet struct thread *td; 144151316Sdavidxu ksiginfo_t ksi; 145151316Sdavidxu 146129198Scognet td = (curthread == NULL) ? &thread0 : curthread; 147129198Scognet 148129198Scognet if (insn == GDB_BREAKPOINT || insn == GDB5_BREAKPOINT) { 149129198Scognet if (code == FAULT_USER) { 150151316Sdavidxu ksiginfo_init_trap(&ksi); 151151316Sdavidxu ksi.ksi_signo = SIGTRAP; 152151316Sdavidxu ksi.ksi_code = TRAP_BRKPT; 153151316Sdavidxu ksi.ksi_addr = (u_int32_t *)addr; 154151316Sdavidxu trapsignal(td, &ksi); 155129198Scognet return 0; 156129198Scognet } 157140001Scognet#if 0 158129198Scognet#ifdef KGDB 159129198Scognet return !kgdb_trap(T_BREAKPOINT, frame); 160129198Scognet#endif 161140001Scognet#endif 162129198Scognet } 163129198Scognet return 1; 164129198Scognet} 165129198Scognet 166129198Scognetstatic struct undefined_handler gdb_uh; 167129198Scognet 168129198Scognetvoid 169314506Sianundefined_init(void) 170129198Scognet{ 171129198Scognet int loop; 172129198Scognet 173129198Scognet /* Not actually necessary -- the initialiser is just NULL */ 174129198Scognet for (loop = 0; loop < MAX_COPROCS; ++loop) 175129198Scognet LIST_INIT(&undefined_handlers[loop]); 176129198Scognet 177129198Scognet /* Install handler for GDB breakpoints */ 178129198Scognet gdb_uh.uh_handler = gdb_trapper; 179129198Scognet install_coproc_handler_static(0, &gdb_uh); 180129198Scognet} 181129198Scognet 182129198Scognet 183129198Scognetvoid 184257217Sianundefinedinstruction(struct trapframe *frame) 185129198Scognet{ 186129198Scognet struct thread *td; 187129198Scognet u_int fault_pc; 188129198Scognet int fault_instruction; 189129198Scognet int fault_code; 190129198Scognet int coprocessor; 191129198Scognet struct undefined_handler *uh; 192282779Sandrew int error; 193129198Scognet#ifdef VERBOSE_ARM32 194129198Scognet int s; 195129198Scognet#endif 196151316Sdavidxu ksiginfo_t ksi; 197129198Scognet 198129198Scognet /* Enable interrupts if they were enabled before the exception. */ 199271398Sandrew if (__predict_true(frame->tf_spsr & PSR_I) == 0) 200271398Sandrew enable_interrupts(PSR_I); 201271398Sandrew if (__predict_true(frame->tf_spsr & PSR_F) == 0) 202271398Sandrew enable_interrupts(PSR_F); 203129198Scognet 204170291Sattilio PCPU_INC(cnt.v_trap); 205129198Scognet 206129198Scognet fault_pc = frame->tf_pc; 207129198Scognet 208236991Simp /* 209236991Simp * Get the current thread/proc structure or thread0/proc0 if there is 210129198Scognet * none. 211129198Scognet */ 212129198Scognet td = curthread == NULL ? &thread0 : curthread; 213129198Scognet 214282779Sandrew coprocessor = 0; 215282779Sandrew if ((frame->tf_spsr & PSR_T) == 0) { 216282779Sandrew /* 217282779Sandrew * Make sure the program counter is correctly aligned so we 218282779Sandrew * don't take an alignment fault trying to read the opcode. 219282779Sandrew */ 220282779Sandrew if (__predict_false((fault_pc & 3) != 0)) { 221282779Sandrew ksiginfo_init_trap(&ksi); 222282779Sandrew ksi.ksi_signo = SIGILL; 223282779Sandrew ksi.ksi_code = ILL_ILLADR; 224282779Sandrew ksi.ksi_addr = (u_int32_t *)(intptr_t) fault_pc; 225282779Sandrew trapsignal(td, &ksi); 226282779Sandrew userret(td, frame); 227282779Sandrew return; 228282779Sandrew } 229282779Sandrew 230282779Sandrew /* 231282779Sandrew * Should use fuword() here .. but in the interests of 232282779Sandrew * squeezing every bit of speed we will just use ReadWord(). 233282779Sandrew * We know the instruction can be read as was just executed 234282779Sandrew * so this will never fail unless the kernel is screwed up 235282779Sandrew * in which case it does not really matter does it ? 236282779Sandrew */ 237282779Sandrew 238282779Sandrew fault_instruction = *(u_int32_t *)fault_pc; 239282779Sandrew 240282779Sandrew /* Check for coprocessor instruction */ 241282779Sandrew 242282779Sandrew /* 243282779Sandrew * According to the datasheets you only need to look at bit 244282779Sandrew * 27 of the instruction to tell the difference between and 245282779Sandrew * undefined instruction and a coprocessor instruction 246282779Sandrew * following an undefined instruction trap. 247282779Sandrew */ 248282779Sandrew 249282779Sandrew if (ARM_COPROC_INSN(fault_instruction)) 250282779Sandrew coprocessor = ARM_COPROC(fault_instruction); 251282779Sandrew else { /* check for special instructions */ 252282779Sandrew if (ARM_VFP_INSN(fault_instruction)) 253282779Sandrew coprocessor = COPROC_VFP; /* vfp / simd */ 254282779Sandrew } 255282779Sandrew } else { 256282779Sandrew#if __ARM_ARCH >= 7 257282779Sandrew fault_instruction = *(uint16_t *)fault_pc; 258282779Sandrew if (THUMB_32BIT_INSN(fault_instruction)) { 259282779Sandrew fault_instruction <<= 16; 260282779Sandrew fault_instruction |= *(uint16_t *)(fault_pc + 2); 261282779Sandrew 262282779Sandrew /* 263282779Sandrew * Is it a Coprocessor, Advanced SIMD, or 264282779Sandrew * Floating-point instruction. 265282779Sandrew */ 266282779Sandrew if (THUMB_COPROC_INSN(fault_instruction)) { 267282779Sandrew if (THUMB_COPROC_UNDEFINED(fault_instruction)) { 268282779Sandrew /* undefined insn */ 269282779Sandrew } else if (THUMB_VFP_INSN(fault_instruction)) 270282779Sandrew coprocessor = COPROC_VFP; 271282779Sandrew else 272282779Sandrew coprocessor = 273282779Sandrew THUMB_COPROC(fault_instruction); 274282779Sandrew } 275282779Sandrew } 276282779Sandrew#else 277282779Sandrew /* 278282779Sandrew * No support for Thumb-2 on this cpu 279282779Sandrew */ 280151316Sdavidxu ksiginfo_init_trap(&ksi); 281151316Sdavidxu ksi.ksi_signo = SIGILL; 282151316Sdavidxu ksi.ksi_code = ILL_ILLADR; 283151316Sdavidxu ksi.ksi_addr = (u_int32_t *)(intptr_t) fault_pc; 284151316Sdavidxu trapsignal(td, &ksi); 285156166Scognet userret(td, frame); 286129198Scognet return; 287129198Scognet#endif 288239268Sgonzo } 289129198Scognet 290129198Scognet if ((frame->tf_spsr & PSR_MODE) == PSR_USR32_MODE) { 291129198Scognet /* 292129198Scognet * Modify the fault_code to reflect the USR/SVC state at 293129198Scognet * time of fault. 294129198Scognet */ 295129198Scognet fault_code = FAULT_USER; 296129198Scognet td->td_frame = frame; 297129198Scognet } else 298129198Scognet fault_code = 0; 299129198Scognet 300129198Scognet /* OK this is were we do something about the instruction. */ 301129198Scognet LIST_FOREACH(uh, &undefined_handlers[coprocessor], uh_link) 302129198Scognet if (uh->uh_handler(fault_pc, fault_instruction, frame, 303129198Scognet fault_code) == 0) 304129198Scognet break; 305129198Scognet 306282779Sandrew if (fault_code & FAULT_USER) { 307282779Sandrew /* TODO: No support for ptrace from Thumb-2 */ 308282779Sandrew if ((frame->tf_spsr & PSR_T) == 0 && 309282779Sandrew fault_instruction == PTRACE_BREAKPOINT) { 310282779Sandrew PROC_LOCK(td->td_proc); 311282779Sandrew _PHOLD(td->td_proc); 312282779Sandrew error = ptrace_clear_single_step(td); 313282779Sandrew _PRELE(td->td_proc); 314282779Sandrew PROC_UNLOCK(td->td_proc); 315282779Sandrew if (error != 0) { 316282779Sandrew ksiginfo_init_trap(&ksi); 317282779Sandrew ksi.ksi_signo = SIGILL; 318282779Sandrew ksi.ksi_code = ILL_ILLOPC; 319282779Sandrew ksi.ksi_addr = (u_int32_t *)(intptr_t) fault_pc; 320282779Sandrew trapsignal(td, &ksi); 321282779Sandrew } 322282779Sandrew return; 323282779Sandrew } 324140001Scognet } 325140001Scognet 326137940Scognet if (uh == NULL && (fault_code & FAULT_USER)) { 327129198Scognet /* Fault has not been handled */ 328151316Sdavidxu ksiginfo_init_trap(&ksi); 329151316Sdavidxu ksi.ksi_signo = SIGILL; 330151316Sdavidxu ksi.ksi_code = ILL_ILLOPC; 331151316Sdavidxu ksi.ksi_addr = (u_int32_t *)(intptr_t) fault_pc; 332151316Sdavidxu trapsignal(td, &ksi); 333129198Scognet } 334129198Scognet 335137940Scognet if ((fault_code & FAULT_USER) == 0) { 336137940Scognet if (fault_instruction == KERNEL_BREAKPOINT) { 337137940Scognet#ifdef KDB 338155241Simp kdb_trap(T_BREAKPOINT, 0, frame); 339137940Scognet#else 340155241Simp printf("No debugger in kernel.\n"); 341137940Scognet#endif 342155241Simp return; 343279667Sandrew } 344279667Sandrew else 345137940Scognet panic("Undefined instruction in kernel.\n"); 346140001Scognet } 347129198Scognet 348156166Scognet userret(td, frame); 349129198Scognet} 350