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