exception.c revision 1.44
1/*	$NetBSD: exception.c,v 1.44 2008/01/08 01:25:13 uwe Exp $	*/
2
3/*-
4 * Copyright (c) 2002 The NetBSD Foundation, Inc. All rights reserved.
5 * Copyright (c) 1990 The Regents of the University of California.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * the University of Utah, and William Jolitz.
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. Neither the name of the University nor the names of its contributors
20 *    may be used to endorse or promote products derived from this software
21 *    without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 *	@(#)trap.c	7.4 (Berkeley) 5/13/91
36 */
37
38/*-
39 * Copyright (c) 1995 Charles M. Hannum.  All rights reserved.
40 *
41 * This code is derived from software contributed to Berkeley by
42 * the University of Utah, and William Jolitz.
43 *
44 * Redistribution and use in source and binary forms, with or without
45 * modification, are permitted provided that the following conditions
46 * are met:
47 * 1. Redistributions of source code must retain the above copyright
48 *    notice, this list of conditions and the following disclaimer.
49 * 2. Redistributions in binary form must reproduce the above copyright
50 *    notice, this list of conditions and the following disclaimer in the
51 *    documentation and/or other materials provided with the distribution.
52 * 3. All advertising materials mentioning features or use of this software
53 *    must display the following acknowledgement:
54 *	This product includes software developed by the University of
55 *	California, Berkeley and its contributors.
56 * 4. Neither the name of the University nor the names of its contributors
57 *    may be used to endorse or promote products derived from this software
58 *    without specific prior written permission.
59 *
60 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
61 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
62 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
63 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
64 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
65 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
66 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
67 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
68 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
69 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
70 * SUCH DAMAGE.
71 *
72 *	@(#)trap.c	7.4 (Berkeley) 5/13/91
73 */
74
75/*
76 * SH3 Trap and System call handling
77 *
78 * T.Horiuchi 1998.06.8
79 */
80
81#include <sys/cdefs.h>
82__KERNEL_RCSID(0, "$NetBSD: exception.c,v 1.44 2008/01/08 01:25:13 uwe Exp $");
83
84#include "opt_ddb.h"
85#include "opt_kgdb.h"
86
87#include <sys/param.h>
88#include <sys/systm.h>
89#include <sys/kernel.h>
90#include <sys/user.h>
91#include <sys/proc.h>
92#include <sys/signal.h>
93
94#ifdef DDB
95#include <sh3/db_machdep.h>
96#endif
97#ifdef KGDB
98#include <sys/kgdb.h>
99#endif
100
101#include <uvm/uvm_extern.h>
102
103#include <sh3/cpu.h>
104#include <sh3/mmu.h>
105#include <sh3/exception.h>
106#include <sh3/userret.h>
107
108const char * const exp_type[] = {
109	"--",					/* 0x000 (reset vector) */
110	"--",					/* 0x020 (reset vector) */
111	"TLB miss/invalid (load)",		/* 0x040 EXPEVT_TLB_MISS_LD */
112	"TLB miss/invalid (store)",		/* 0x060 EXPEVT_TLB_MISS_ST */
113	"initial page write",			/* 0x080 EXPEVT_TLB_MOD */
114	"TLB protection violation (load)",	/* 0x0a0 EXPEVT_TLB_PROT_LD */
115	"TLB protection violation (store)",	/* 0x0c0 EXPEVT_TLB_PROT_ST */
116	"address error (load)",			/* 0x0e0 EXPEVT_ADDR_ERR_LD */
117	"address error (store)",		/* 0x100 EXPEVT_ADDR_ERR_ST */
118	"FPU",					/* 0x120 EXPEVT_FPU */
119	"--",					/* 0x140 (reset vector) */
120	"unconditional trap (TRAPA)",		/* 0x160 EXPEVT_TRAPA */
121	"reserved instruction code exception",	/* 0x180 EXPEVT_RES_INST */
122	"illegal slot instruction exception",	/* 0x1a0 EXPEVT_SLOT_INST */
123	"--",					/* 0x1c0 (external interrupt) */
124	"user break point trap",		/* 0x1e0 EXPEVT_BREAK */
125};
126const int exp_types = sizeof exp_type / sizeof exp_type[0];
127
128void general_exception(struct lwp *, struct trapframe *, uint32_t);
129void tlb_exception(struct lwp *, struct trapframe *, uint32_t);
130void ast(struct lwp *, struct trapframe *);
131
132/*
133 * void general_exception(struct lwp *l, struct trapframe *tf):
134 *	l  ... curlwp when exception occur.
135 *	tf ... full user context.
136 *	va ... fault va for user mode EXPEVT_ADDR_ERR_{LD,ST}
137 */
138void
139general_exception(struct lwp *l, struct trapframe *tf, uint32_t va)
140{
141	int expevt = tf->tf_expevt;
142	bool usermode = !KERNELMODE(tf->tf_ssr);
143	ksiginfo_t ksi;
144
145	uvmexp.traps++;
146
147	splx(tf->tf_ssr & PSL_IMASK);
148
149	if (l == NULL)
150 		goto do_panic;
151
152	if (usermode) {
153		KDASSERT(l->l_md.md_regs == tf); /* check exception depth */
154		expevt |= EXP_USER;
155		LWP_CACHE_CREDS(l, l->l_proc);
156	}
157
158	switch (expevt) {
159	case EXPEVT_TRAPA | EXP_USER:
160		/* Check for debugger break */
161		if (_reg_read_4(SH_(TRA)) == (_SH_TRA_BREAK << 2)) {
162			tf->tf_spc -= 2; /* back to the breakpoint address */
163			KSI_INIT_TRAP(&ksi);
164			ksi.ksi_signo = SIGTRAP;
165			ksi.ksi_code = TRAP_BRKPT;
166			ksi.ksi_addr = (void *)tf->tf_spc;
167			goto trapsignal;
168		} else {
169			/* XXX: we shouldn't treat *any* TRAPA as a syscall */
170			(*l->l_proc->p_md.md_syscall)(l, tf);
171			return;
172		}
173		break;
174
175	case EXPEVT_ADDR_ERR_LD: /* FALLTHROUGH */
176	case EXPEVT_ADDR_ERR_ST:
177		KDASSERT(l->l_md.md_pcb->pcb_onfault != NULL);
178		tf->tf_spc = (int)l->l_md.md_pcb->pcb_onfault;
179		if (tf->tf_spc == 0)
180			goto do_panic;
181		break;
182
183	case EXPEVT_ADDR_ERR_LD | EXP_USER: /* FALLTHROUGH */
184	case EXPEVT_ADDR_ERR_ST | EXP_USER:
185		KSI_INIT_TRAP(&ksi);
186		if (((int)va) < 0) {
187		    ksi.ksi_signo = SIGSEGV;
188		    ksi.ksi_code = SEGV_ACCERR;
189		} else {
190		    ksi.ksi_signo = SIGBUS;
191		    ksi.ksi_code = BUS_ADRALN;
192		}
193		ksi.ksi_addr = (void *)va;
194		goto trapsignal;
195
196	case EXPEVT_RES_INST | EXP_USER: /* FALLTHROUGH */
197	case EXPEVT_SLOT_INST | EXP_USER:
198		KSI_INIT_TRAP(&ksi);
199		ksi.ksi_signo = SIGILL;
200		ksi.ksi_code = ILL_ILLOPC; /* XXX: could be ILL_PRVOPC */
201		ksi.ksi_addr = (void *)tf->tf_spc;
202		goto trapsignal;
203
204	case EXPEVT_BREAK | EXP_USER:
205		KSI_INIT_TRAP(&ksi);
206		ksi.ksi_signo = SIGTRAP;
207		ksi.ksi_code = TRAP_TRACE;
208		ksi.ksi_addr = (void *)tf->tf_spc;
209		goto trapsignal;
210
211	default:
212		goto do_panic;
213	}
214
215	if (usermode)
216		userret(l);
217	return;
218
219 trapsignal:
220	ksi.ksi_trap = tf->tf_expevt;
221	KERNEL_LOCK(l, 1);
222	trapsignal(l, &ksi);
223	KERNEL_UNLOCK_LAST(l);
224	userret(l);
225	return;
226
227 do_panic:
228	if (expevt >> 5 < exp_types)
229		printf("fatal %s", exp_type[expevt >> 5]);
230	else
231		printf("EXPEVT 0x%03x", expevt);
232	printf(" in %s mode\n", expevt & EXP_USER ? "user" : "kernel");
233	printf(" spc %x ssr %x \n", tf->tf_spc, tf->tf_ssr);
234#ifdef DDB
235	if (kdb_trap(expevt, 0, tf))
236		return;
237#endif
238#ifdef KGDB
239	if (kgdb_trap(EXPEVT_BREAK, tf))
240		return;
241#endif
242
243	panic("general_exception");
244	/* NOTREACHED */
245}
246
247
248/*
249 * void tlb_exception(struct lwp *l, struct trapframe *tf, uint32_t va):
250 *	l  ... curlwp when exception occur.
251 *	tf ... full user context.
252 *	va ... fault address.
253 */
254void
255tlb_exception(struct lwp *l, struct trapframe *tf, uint32_t va)
256{
257	struct vm_map *map;
258	pmap_t pmap;
259	ksiginfo_t ksi;
260	bool usermode;
261	int err, track, ftype;
262	const char *panic_msg;
263
264#define TLB_ASSERT(assert, msg)				\
265		do {					\
266			if (!(assert)) {		\
267				panic_msg =  msg;	\
268				goto tlb_panic;		\
269			}				\
270		} while(/*CONSTCOND*/0)
271
272	splx(tf->tf_ssr & PSL_IMASK);
273
274	usermode = !KERNELMODE(tf->tf_ssr);
275	if (usermode) {
276		KDASSERT(l->l_md.md_regs == tf);
277		LWP_CACHE_CREDS(l, l->l_proc);
278	} else {
279#if 0 /* FIXME: probably wrong for yamt-idlelwp */
280		KDASSERT(l == NULL ||		/* idle */
281		    l == &lwp0 ||		/* kthread */
282		    l->l_md.md_regs != tf);	/* other */
283#endif
284	}
285
286	switch (tf->tf_expevt) {
287	case EXPEVT_TLB_MISS_LD:
288		track = PVH_REFERENCED;
289		ftype = VM_PROT_READ;
290		break;
291	case EXPEVT_TLB_MISS_ST:
292		track = PVH_REFERENCED;
293		ftype = VM_PROT_WRITE;
294		break;
295	case EXPEVT_TLB_MOD:
296		track = PVH_REFERENCED | PVH_MODIFIED;
297		ftype = VM_PROT_WRITE;
298		break;
299	case EXPEVT_TLB_PROT_LD:
300		TLB_ASSERT((int)va > 0,
301		    "kernel virtual protection fault (load)");
302		if (usermode) {
303			KSI_INIT_TRAP(&ksi);
304			ksi.ksi_signo = SIGSEGV;
305			ksi.ksi_code = SEGV_ACCERR;
306			ksi.ksi_addr = (void *)va;
307			goto user_fault;
308		} else {
309			TLB_ASSERT(l && l->l_md.md_pcb->pcb_onfault != NULL,
310			    "no copyin/out fault handler (load protection)");
311			tf->tf_spc = (int)l->l_md.md_pcb->pcb_onfault;
312		}
313		return;
314
315	case EXPEVT_TLB_PROT_ST:
316		track = 0;	/* call uvm_fault first. (COW) */
317		ftype = VM_PROT_WRITE;
318		break;
319
320	default:
321		TLB_ASSERT(0, "impossible expevt");
322	}
323
324	/* Select address space */
325	if (usermode) {
326		TLB_ASSERT(l != NULL, "no curlwp");
327		map = &l->l_proc->p_vmspace->vm_map;
328		pmap = map->pmap;
329	} else {
330		if ((int)va < 0) {
331			map = kernel_map;
332			pmap = pmap_kernel();
333		} else {
334			TLB_ASSERT(l != NULL &&
335			    l->l_md.md_pcb->pcb_onfault != NULL,
336			    "invalid user-space access from kernel mode");
337			if (va == 0) {
338				tf->tf_spc = (int)l->l_md.md_pcb->pcb_onfault;
339				return;
340			}
341			map = &l->l_proc->p_vmspace->vm_map;
342			pmap = map->pmap;
343		}
344	}
345
346	/* Lookup page table. if entry found, load it. */
347	if (track && __pmap_pte_load(pmap, va, track)) {
348		if (usermode)
349			userret(l);
350		return;
351	}
352
353	/* Page not found. call fault handler */
354	if (!usermode && pmap != pmap_kernel() &&
355	    l->l_md.md_pcb->pcb_faultbail) {
356		TLB_ASSERT(l->l_md.md_pcb->pcb_onfault != NULL,
357		    "no copyin/out fault handler (interrupt context)");
358		tf->tf_spc = (int)l->l_md.md_pcb->pcb_onfault;
359		return;
360	}
361
362	err = uvm_fault(map, va, ftype);
363
364	/* User stack extension */
365	if (map != kernel_map &&
366	    (va >= (vaddr_t)l->l_proc->p_vmspace->vm_maxsaddr) &&
367	    (va < USRSTACK)) {
368		if (err == 0) {
369			struct vmspace *vm = l->l_proc->p_vmspace;
370			uint32_t nss;
371			nss = btoc(USRSTACK - va);
372			if (nss > vm->vm_ssize)
373				vm->vm_ssize = nss;
374		} else if (err == EACCES) {
375			err = EFAULT;
376		}
377	}
378
379	/* Page in. load PTE to TLB. */
380	if (err == 0) {
381		bool loaded = __pmap_pte_load(pmap, va, track);
382		TLB_ASSERT(loaded, "page table entry not found");
383		if (usermode)
384			userret(l);
385		return;
386	}
387
388	/* Page not found. */
389	if (usermode) {
390		KSI_INIT_TRAP(&ksi);
391		if (err == ENOMEM)
392			ksi.ksi_signo = SIGKILL;
393		else {
394			ksi.ksi_signo = SIGSEGV;
395			ksi.ksi_code = SEGV_MAPERR;
396		}
397		goto user_fault;
398	} else {
399		TLB_ASSERT(l->l_md.md_pcb->pcb_onfault,
400		    "no copyin/out fault handler (page not found)");
401		tf->tf_spc = (int)l->l_md.md_pcb->pcb_onfault;
402	}
403	return;
404
405 user_fault:
406	ksi.ksi_trap = tf->tf_expevt
407	KERNEL_LOCK(l, 1);
408	trapsignal(l, &ksi);
409	KERNEL_UNLOCK_LAST(l);
410	userret(l);
411	ast(l, tf);
412	return;
413
414 tlb_panic:
415	panic("tlb_exception: %s\n"
416	      "expevt=%x va=%08x ssr=%08x spc=%08x lwp=%p onfault=%p",
417	      panic_msg, tf->tf_expevt, va, tf->tf_ssr, tf->tf_spc,
418	      l, l ? l->l_md.md_pcb->pcb_onfault : NULL);
419#undef	TLB_ASSERT
420}
421
422
423/*
424 * void ast(struct lwp *l, struct trapframe *tf):
425 *	l  ... curlwp when exception occur.
426 *	tf ... full user context.
427 *	This is called when exception return. if return from kernel to user,
428 *	handle asynchronous software traps and context switch if needed.
429 */
430void
431ast(struct lwp *l, struct trapframe *tf)
432{
433
434	if (KERNELMODE(tf->tf_ssr)) {
435		return;
436	}
437
438	KDASSERT(l != NULL);
439	KDASSERT(l->l_md.md_regs == tf);
440
441	while (l->l_md.md_astpending) {
442		uvmexp.softs++;
443		l->l_md.md_astpending = 0;
444
445		if (l->l_pflag & LP_OWEUPC) {
446			l->l_pflag &= ~LP_OWEUPC;
447			ADDUPROF(p);
448		}
449
450		if (l->l_cpu->ci_want_resched) {
451			/* We are being preempted. */
452			preempt();
453		}
454
455		userret(l);
456	}
457}
458