xref: /trueos/sys/arm/arm/undefined.c (revision f3fa4bdf8b98edb697d801e65b8b2bd542f15787)
1 /*	$NetBSD: undefined.c,v 1.22 2003/11/29 22:21:29 bjh21 Exp $	*/
2 
3 /*-
4  * Copyright (c) 2001 Ben Harris.
5  * Copyright (c) 1995 Mark Brinicombe.
6  * Copyright (c) 1995 Brini.
7  * All rights reserved.
8  *
9  * This code is derived from software written for Brini by Mark Brinicombe
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *	This product includes software developed by Brini.
22  * 4. The name of the company nor the name of the author may be used to
23  *    endorse or promote products derived from this software without specific
24  *    prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
27  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
28  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
29  * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
30  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
31  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
32  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  *
38  * RiscBSD kernel project
39  *
40  * undefined.c
41  *
42  * Fault handler
43  *
44  * Created      : 06/01/95
45  */
46 
47 
48 #include "opt_ddb.h"
49 
50 #include <sys/cdefs.h>
51 __FBSDID("$FreeBSD$");
52 
53 #include <sys/param.h>
54 #include <sys/malloc.h>
55 #include <sys/queue.h>
56 #include <sys/signal.h>
57 #include <sys/systm.h>
58 #include <sys/proc.h>
59 #include <sys/syslog.h>
60 #include <sys/vmmeter.h>
61 #include <sys/lock.h>
62 #include <sys/mutex.h>
63 #include <sys/signalvar.h>
64 #include <sys/ptrace.h>
65 #ifdef KDB
66 #include <sys/kdb.h>
67 #endif
68 
69 #include <vm/vm.h>
70 #include <vm/vm_extern.h>
71 
72 #include <machine/armreg.h>
73 #include <machine/asm.h>
74 #include <machine/cpu.h>
75 #include <machine/frame.h>
76 #include <machine/undefined.h>
77 #include <machine/trap.h>
78 
79 #include <machine/disassem.h>
80 
81 #ifdef DDB
82 #include <ddb/db_output.h>
83 #endif
84 
85 #ifdef KDB
86 #include <machine/db_machdep.h>
87 #endif
88 
89 static int gdb_trapper(u_int, u_int, struct trapframe *, int);
90 
91 LIST_HEAD(, undefined_handler) undefined_handlers[MAX_COPROCS];
92 
93 
94 void *
install_coproc_handler(int coproc,undef_handler_t handler)95 install_coproc_handler(int coproc, undef_handler_t handler)
96 {
97 	struct undefined_handler *uh;
98 
99 	KASSERT(coproc >= 0 && coproc < MAX_COPROCS, ("bad coproc"));
100 	KASSERT(handler != NULL, ("handler is NULL")); /* Used to be legal. */
101 
102 	/* XXX: M_TEMP??? */
103 	uh = malloc(sizeof(*uh), M_TEMP, M_WAITOK);
104 	uh->uh_handler = handler;
105 	install_coproc_handler_static(coproc, uh);
106 	return uh;
107 }
108 
109 void
install_coproc_handler_static(int coproc,struct undefined_handler * uh)110 install_coproc_handler_static(int coproc, struct undefined_handler *uh)
111 {
112 
113 	LIST_INSERT_HEAD(&undefined_handlers[coproc], uh, uh_link);
114 }
115 
116 void
remove_coproc_handler(void * cookie)117 remove_coproc_handler(void *cookie)
118 {
119 	struct undefined_handler *uh = cookie;
120 
121 	LIST_REMOVE(uh, uh_link);
122 	free(uh, M_TEMP);
123 }
124 
125 
126 static int
gdb_trapper(u_int addr,u_int insn,struct trapframe * frame,int code)127 gdb_trapper(u_int addr, u_int insn, struct trapframe *frame, int code)
128 {
129 	struct thread *td;
130 	ksiginfo_t ksi;
131 
132 	td = (curthread == NULL) ? &thread0 : curthread;
133 
134 	if (insn == GDB_BREAKPOINT || insn == GDB5_BREAKPOINT) {
135 		if (code == FAULT_USER) {
136 			ksiginfo_init_trap(&ksi);
137 			ksi.ksi_signo = SIGTRAP;
138 			ksi.ksi_code = TRAP_BRKPT;
139 			ksi.ksi_addr = (u_int32_t *)addr;
140 			trapsignal(td, &ksi);
141 			return 0;
142 		}
143 #if 0
144 #ifdef KGDB
145 		return !kgdb_trap(T_BREAKPOINT, frame);
146 #endif
147 #endif
148 	}
149 	return 1;
150 }
151 
152 static struct undefined_handler gdb_uh;
153 
154 void
undefined_init()155 undefined_init()
156 {
157 	int loop;
158 
159 	/* Not actually necessary -- the initialiser is just NULL */
160 	for (loop = 0; loop < MAX_COPROCS; ++loop)
161 		LIST_INIT(&undefined_handlers[loop]);
162 
163 	/* Install handler for GDB breakpoints */
164 	gdb_uh.uh_handler = gdb_trapper;
165 	install_coproc_handler_static(0, &gdb_uh);
166 }
167 
168 
169 void
undefinedinstruction(struct trapframe * frame)170 undefinedinstruction(struct trapframe *frame)
171 {
172 	struct thread *td;
173 	u_int fault_pc;
174 	int fault_instruction;
175 	int fault_code;
176 	int coprocessor;
177 	struct undefined_handler *uh;
178 #ifdef VERBOSE_ARM32
179 	int s;
180 #endif
181 	ksiginfo_t ksi;
182 
183 	/* Enable interrupts if they were enabled before the exception. */
184 	if (__predict_true(frame->tf_spsr & PSR_I) == 0)
185 		enable_interrupts(PSR_I);
186 	if (__predict_true(frame->tf_spsr & PSR_F) == 0)
187 		enable_interrupts(PSR_F);
188 
189 	PCPU_INC(cnt.v_trap);
190 
191 	fault_pc = frame->tf_pc;
192 
193 	/*
194 	 * Get the current thread/proc structure or thread0/proc0 if there is
195 	 * none.
196 	 */
197 	td = curthread == NULL ? &thread0 : curthread;
198 
199 	/*
200 	 * Make sure the program counter is correctly aligned so we
201 	 * don't take an alignment fault trying to read the opcode.
202 	 */
203 	if (__predict_false((fault_pc & 3) != 0)) {
204 		ksiginfo_init_trap(&ksi);
205 		ksi.ksi_signo = SIGILL;
206 		ksi.ksi_code = ILL_ILLADR;
207 		ksi.ksi_addr = (u_int32_t *)(intptr_t) fault_pc;
208 		trapsignal(td, &ksi);
209 		userret(td, frame);
210 		return;
211 	}
212 
213 	/*
214 	 * Should use fuword() here .. but in the interests of squeezing every
215 	 * bit of speed we will just use ReadWord(). We know the instruction
216 	 * can be read as was just executed so this will never fail unless the
217 	 * kernel is screwed up in which case it does not really matter does
218 	 * it ?
219 	 */
220 
221 	fault_instruction = *(u_int32_t *)fault_pc;
222 
223 	/* Update vmmeter statistics */
224 #if 0
225 	uvmexp.traps++;
226 #endif
227 	/* Check for coprocessor instruction */
228 
229 	/*
230 	 * According to the datasheets you only need to look at bit 27 of the
231 	 * instruction to tell the difference between and undefined
232 	 * instruction and a coprocessor instruction following an undefined
233 	 * instruction trap.
234 	 */
235 
236 	coprocessor = 0;
237 	if ((fault_instruction & (1 << 27)) != 0)
238 		coprocessor = (fault_instruction >> 8) & 0x0f;
239 #ifdef VFP
240 	else {          /* check for special instructions */
241 		if (((fault_instruction & 0xfe000000) == 0xf2000000) ||
242 		    ((fault_instruction & 0xff100000) == 0xf4000000))
243 			coprocessor = 10;       /* vfp / simd */
244 	}
245 #endif	/* VFP */
246 
247 	if ((frame->tf_spsr & PSR_MODE) == PSR_USR32_MODE) {
248 		/*
249 		 * Modify the fault_code to reflect the USR/SVC state at
250 		 * time of fault.
251 		 */
252 		fault_code = FAULT_USER;
253 		td->td_frame = frame;
254 	} else
255 		fault_code = 0;
256 
257 	/* OK this is were we do something about the instruction. */
258 	LIST_FOREACH(uh, &undefined_handlers[coprocessor], uh_link)
259 	    if (uh->uh_handler(fault_pc, fault_instruction, frame,
260 			       fault_code) == 0)
261 		    break;
262 
263 	if (fault_code & FAULT_USER && fault_instruction == PTRACE_BREAKPOINT) {
264 		PROC_LOCK(td->td_proc);
265 		_PHOLD(td->td_proc);
266 		ptrace_clear_single_step(td);
267 		_PRELE(td->td_proc);
268 		PROC_UNLOCK(td->td_proc);
269 		return;
270 	}
271 
272 	if (uh == NULL && (fault_code & FAULT_USER)) {
273 		/* Fault has not been handled */
274 		ksiginfo_init_trap(&ksi);
275 		ksi.ksi_signo = SIGILL;
276 		ksi.ksi_code = ILL_ILLOPC;
277 		ksi.ksi_addr = (u_int32_t *)(intptr_t) fault_pc;
278 		trapsignal(td, &ksi);
279 	}
280 
281 	if ((fault_code & FAULT_USER) == 0) {
282 		if (fault_instruction == KERNEL_BREAKPOINT) {
283 #ifdef KDB
284 			kdb_trap(T_BREAKPOINT, 0, frame);
285 #else
286 			printf("No debugger in kernel.\n");
287 #endif
288 			return;
289 		} else
290 			panic("Undefined instruction in kernel.\n");
291 	}
292 
293 	userret(td, frame);
294 }
295