undefined.c revision 157616
153451Speter/*	$NetBSD: undefined.c,v 1.22 2003/11/29 22:21:29 bjh21 Exp $	*/
253475Sobrien
353451Speter/*-
453451Speter * Copyright (c) 2001 Ben Harris.
553451Speter * Copyright (c) 1995 Mark Brinicombe.
653475Sobrien * Copyright (c) 1995 Brini.
753451Speter * All rights reserved.
853451Speter *
953451Speter * This code is derived from software written for Brini by Mark Brinicombe
1053451Speter *
1153451Speter * Redistribution and use in source and binary forms, with or without
1253451Speter * modification, are permitted provided that the following conditions
1353451Speter * are met:
1453451Speter * 1. Redistributions of source code must retain the above copyright
1553451Speter *    notice, this list of conditions and the following disclaimer.
1653475Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1753475Sobrien *    notice, this list of conditions and the following disclaimer in the
1853451Speter *    documentation and/or other materials provided with the distribution.
1953475Sobrien * 3. All advertising materials mentioning features or use of this software
2053451Speter *    must display the following acknowledgement:
2153451Speter *	This product includes software developed by Brini.
2253451Speter * 4. The name of the company nor the name of the author may be used to
2353475Sobrien *    endorse or promote products derived from this software without specific
2453475Sobrien *    prior written permission.
2553451Speter *
2653451Speter * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
2753451Speter * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
28131557Stjr * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2953451Speter * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
3053451Speter * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
3153451Speter * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
3253475Sobrien * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3353451Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3453451Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3553451Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3653451Speter * SUCH DAMAGE.
3753451Speter *
38131557Stjr * RiscBSD kernel project
3953451Speter *
4053451Speter * undefined.c
4153451Speter *
4253451Speter * Fault handler
43131557Stjr *
4453451Speter * Created      : 06/01/95
4553451Speter */
4653451Speter
4753475Sobrien
4853451Speter#include "opt_ddb.h"
4953451Speter
5053451Speter#include <sys/cdefs.h>
5153451Speter__FBSDID("$FreeBSD: head/sys/arm/arm/undefined.c 157616 2006-04-09 20:16:47Z cognet $");
5253451Speter
5353451Speter#include <sys/param.h>
5453451Speter#include <sys/malloc.h>
55131557Stjr#include <sys/queue.h>
5653451Speter#include <sys/signal.h>
5753451Speter#include <sys/systm.h>
5853475Sobrien#include <sys/proc.h>
5953451Speter#include <sys/syslog.h>
60#include <sys/vmmeter.h>
61#include <sys/types.h>
62#include <sys/lock.h>
63#include <sys/mutex.h>
64#include <sys/signalvar.h>
65#include <sys/ptrace.h>
66#ifdef KDB
67#include <sys/kdb.h>
68#endif
69#ifdef FAST_FPE
70#include <sys/acct.h>
71#endif
72
73#include <vm/vm.h>
74#include <vm/vm_extern.h>
75
76#include <machine/asm.h>
77#include <machine/cpu.h>
78#include <machine/frame.h>
79#include <machine/undefined.h>
80#include <machine/trap.h>
81
82#include <machine/disassem.h>
83
84#ifdef DDB
85#include <ddb/db_output.h>
86#include <machine/db_machdep.h>
87#endif
88
89#ifdef acorn26
90#include <machine/machdep.h>
91#endif
92
93static int gdb_trapper(u_int, u_int, struct trapframe *, int);
94#ifdef FAST_FPE
95extern int want_resched;
96#endif
97
98LIST_HEAD(, undefined_handler) undefined_handlers[MAX_COPROCS];
99
100
101void *
102install_coproc_handler(int coproc, undef_handler_t handler)
103{
104	struct undefined_handler *uh;
105
106	KASSERT(coproc >= 0 && coproc < MAX_COPROCS, ("bad coproc"));
107	KASSERT(handler != NULL, ("handler is NULL")); /* Used to be legal. */
108
109	/* XXX: M_TEMP??? */
110	MALLOC(uh, struct undefined_handler *, sizeof(*uh), M_TEMP, M_WAITOK);
111	uh->uh_handler = handler;
112	install_coproc_handler_static(coproc, uh);
113	return uh;
114}
115
116void
117install_coproc_handler_static(int coproc, struct undefined_handler *uh)
118{
119
120	LIST_INSERT_HEAD(&undefined_handlers[coproc], uh, uh_link);
121}
122
123void
124remove_coproc_handler(void *cookie)
125{
126	struct undefined_handler *uh = cookie;
127
128	LIST_REMOVE(uh, uh_link);
129	FREE(uh, M_TEMP);
130}
131
132
133static int
134gdb_trapper(u_int addr, u_int insn, struct trapframe *frame, int code)
135{
136	struct thread *td;
137	ksiginfo_t ksi;
138
139	td = (curthread == NULL) ? &thread0 : curthread;
140
141	if (insn == GDB_BREAKPOINT || insn == GDB5_BREAKPOINT) {
142		if (code == FAULT_USER) {
143			ksiginfo_init_trap(&ksi);
144			ksi.ksi_signo = SIGTRAP;
145			ksi.ksi_code = TRAP_BRKPT;
146			ksi.ksi_addr = (u_int32_t *)addr;
147			trapsignal(td, &ksi);
148			return 0;
149		}
150#if 0
151#ifdef KGDB
152		return !kgdb_trap(T_BREAKPOINT, frame);
153#endif
154#endif
155	}
156	return 1;
157}
158
159static struct undefined_handler gdb_uh;
160
161void
162undefined_init()
163{
164	int loop;
165
166	/* Not actually necessary -- the initialiser is just NULL */
167	for (loop = 0; loop < MAX_COPROCS; ++loop)
168		LIST_INIT(&undefined_handlers[loop]);
169
170	/* Install handler for GDB breakpoints */
171	gdb_uh.uh_handler = gdb_trapper;
172	install_coproc_handler_static(0, &gdb_uh);
173}
174
175
176void
177undefinedinstruction(trapframe_t *frame)
178{
179	struct thread *td;
180	u_int fault_pc;
181	int fault_instruction;
182	int fault_code;
183	int coprocessor;
184	struct undefined_handler *uh;
185#ifdef VERBOSE_ARM32
186	int s;
187#endif
188	ksiginfo_t ksi;
189
190	/* Enable interrupts if they were enabled before the exception. */
191	if (!(frame->tf_spsr & I32_bit))
192		enable_interrupts(I32_bit|F32_bit);
193
194	frame->tf_pc -= INSN_SIZE;
195	PCPU_LAZY_INC(cnt.v_trap);
196
197	fault_pc = frame->tf_pc;
198
199	/*
200	 * Get the current thread/proc structure or thread0/proc0 if there is
201	 * none.
202	 */
203	td = curthread == NULL ? &thread0 : curthread;
204
205	/*
206	 * Make sure the program counter is correctly aligned so we
207	 * don't take an alignment fault trying to read the opcode.
208	 */
209	if (__predict_false((fault_pc & 3) != 0)) {
210		ksiginfo_init_trap(&ksi);
211		ksi.ksi_signo = SIGILL;
212		ksi.ksi_code = ILL_ILLADR;
213		ksi.ksi_addr = (u_int32_t *)(intptr_t) fault_pc;
214		trapsignal(td, &ksi);
215		userret(td, frame);
216		return;
217	}
218
219	/*
220	 * Should use fuword() here .. but in the interests of squeezing every
221	 * bit of speed we will just use ReadWord(). We know the instruction
222	 * can be read as was just executed so this will never fail unless the
223	 * kernel is screwed up in which case it does not really matter does
224	 * it ?
225	 */
226
227	fault_instruction = *(u_int32_t *)fault_pc;
228
229	/* Update vmmeter statistics */
230#if 0
231	uvmexp.traps++;
232#endif
233	/* Check for coprocessor instruction */
234
235	/*
236	 * According to the datasheets you only need to look at bit 27 of the
237	 * instruction to tell the difference between and undefined
238	 * instruction and a coprocessor instruction following an undefined
239	 * instruction trap.
240	 */
241
242	if ((fault_instruction & (1 << 27)) != 0)
243		coprocessor = (fault_instruction >> 8) & 0x0f;
244	else
245		coprocessor = 0;
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#ifdef FAST_FPE
294	/* Optimised exit code */
295	{
296
297		/*
298		 * Check for reschedule request, at the moment there is only
299		 * 1 ast so this code should always be run
300		 */
301
302		if (want_resched) {
303			/*
304			 * We are being preempted.
305			 */
306			preempt(0);
307		}
308
309		/* Invoke MI userret code */
310		mi_userret(td);
311
312#if 0
313		l->l_priority = l->l_usrpri;
314
315		curcpu()->ci_schedstate.spc_curpriority = l->l_priority;
316#endif
317	}
318
319#else
320	userret(td, frame);
321#endif
322}
323