xref: /netbsd/sys/arch/amiga/amiga/trap.c (revision bf9ec67e)
1 /*	$NetBSD: trap.c,v 1.88 2002/02/14 07:08:03 chs Exp $	*/
2 
3 /*
4  * Copyright (c) 1988 University of Utah.
5  * Copyright (c) 1982, 1986, 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 Systems Programming Group of the University of Utah Computer
10  * Science Department.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. All advertising materials mentioning features or use of this software
21  *    must display the following acknowledgement:
22  *	This product includes software developed by the University of
23  *	California, Berkeley and its contributors.
24  * 4. Neither the name of the University nor the names of its contributors
25  *    may be used to endorse or promote products derived from this software
26  *    without specific prior written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38  * SUCH DAMAGE.
39  *
40  * from: Utah $Hdr: trap.c 1.32 91/04/06$
41  *
42  *	@(#)trap.c	7.15 (Berkeley) 8/2/91
43  */
44 
45 #include "opt_ddb.h"
46 #include "opt_execfmt.h"
47 #include "opt_compat_sunos.h"
48 
49 #include <sys/cdefs.h>
50 __KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.88 2002/02/14 07:08:03 chs Exp $");
51 
52 #include <sys/param.h>
53 #include <sys/systm.h>
54 #include <sys/proc.h>
55 #include <sys/acct.h>
56 #include <sys/kernel.h>
57 #include <sys/signalvar.h>
58 #include <sys/resourcevar.h>
59 #include <sys/syslog.h>
60 #include <sys/syscall.h>
61 
62 #include <sys/user.h>
63 
64 #include <uvm/uvm_extern.h>
65 
66 #include <machine/psl.h>
67 #include <machine/trap.h>
68 #include <machine/cpu.h>
69 #include <machine/reg.h>
70 #include <machine/mtpr.h>
71 #include <machine/pte.h>
72 
73 #include <m68k/fpe/fpu_emulate.h>
74 #include <m68k/cacheops.h>
75 
76 #ifdef COMPAT_SUNOS
77 #include <compat/sunos/sunos_syscall.h>
78 extern struct emul emul_sunos;
79 #endif
80 
81 /*
82  * XXX Hack until I can figure out what to do about this code's removal
83  * from m68k/include/frame.h
84  */
85 
86 /* 68040 fault frame */
87 #define SSW_CP		0x8000		/* Continuation - Floating-Point Post*/
88 #define SSW_CU		0x4000		/* Continuation - Unimpl. FP */
89 #define SSW_CT		0x2000		/* Continuation - Trace */
90 #define SSW_CM		0x1000		/* Continuation - MOVEM */
91 #define SSW_MA		0x0800		/* Misaligned access */
92 #define SSW_ATC		0x0400		/* ATC fault */
93 #define SSW_LK		0x0200		/* Locked transfer */
94 #define SSW_RW040	0x0100		/* Read/Write */
95 #define SSW_SZMASK	0x0060		/* Transfer size */
96 #define SSW_TTMASK	0x0018		/* Transfer type */
97 #define SSW_TMMASK	0x0007		/* Transfer modifier */
98 
99 #define WBS_TMMASK	0x0007
100 #define WBS_TTMASK	0x0018
101 #define WBS_SZMASK	0x0060
102 #define WBS_VALID	0x0080
103 
104 #define WBS_SIZE_BYTE	0x0020
105 #define WBS_SIZE_WORD	0x0040
106 #define WBS_SIZE_LONG	0x0000
107 #define WBS_SIZE_LINE	0x0060
108 
109 #define WBS_TT_NORMAL	0x0000
110 #define WBS_TT_MOVE16	0x0008
111 #define WBS_TT_ALTFC	0x0010
112 #define WBS_TT_ACK	0x0018
113 
114 #define WBS_TM_PUSH	0x0000
115 #define WBS_TM_UDATA	0x0001
116 #define WBS_TM_UCODE	0x0002
117 #define WBS_TM_MMUTD	0x0003
118 #define WBS_TM_MMUTC	0x0004
119 #define WBS_TM_SDATA	0x0005
120 #define WBS_TM_SCODE	0x0006
121 #define WBS_TM_RESV	0x0007
122 
123 #define	MMUSR_PA_MASK	0xfffff000
124 #define MMUSR_B		0x00000800
125 #define MMUSR_G		0x00000400
126 #define MMUSR_U1	0x00000200
127 #define MMUSR_U0	0x00000100
128 #define MMUSR_S		0x00000080
129 #define MMUSR_CM	0x00000060
130 #define MMUSR_M		0x00000010
131 #define MMUSR_0		0x00000008
132 #define MMUSR_W		0x00000004
133 #define MMUSR_T		0x00000002
134 #define MMUSR_R		0x00000001
135 
136 #define FSLW_STRING	"\020\1SEE\3BPE\4TTR\5WE\6RE\7TWE\010WP\011SP" \
137 			"\012PF\013IL\014PTB\015PTA\016SBE\017PBE"
138 /*
139  * XXX End hack
140  */
141 
142 int	astpending;
143 
144 char	*trap_type[] = {
145 	"Bus error",
146 	"Address error",
147 	"Illegal instruction",
148 	"Zero divide",
149 	"CHK instruction",
150 	"TRAPV instruction",
151 	"Privilege violation",
152 	"Trace trap",
153 	"MMU fault",
154 	"SSIR trap",
155 	"Format error",
156 	"68881 exception",
157 	"Coprocessor violation",
158 	"Async system trap"
159 };
160 int	trap_types = sizeof trap_type / sizeof trap_type[0];
161 
162 /*
163  * Size of various exception stack frames (minus the standard 8 bytes)
164  */
165 short	exframesize[] = {
166 	FMT0SIZE,	/* type 0 - normal (68020/030/040/060) */
167 	FMT1SIZE,	/* type 1 - throwaway (68020/030/040) */
168 	FMT2SIZE,	/* type 2 - normal 6-word (68020/030/040/060) */
169 	FMT3SIZE,	/* type 3 - FP post-instruction (68040/060) */
170 	FMT4SIZE,	/* type 4 - access error/fp disabled (68060) */
171 	-1, -1,		/* type 5-6 - undefined */
172 	FMT7SIZE,	/* type 7 - access error (68040) */
173 	58,		/* type 8 - bus fault (68010) */
174 	FMT9SIZE,	/* type 9 - coprocessor mid-instruction (68020/030) */
175 	FMTASIZE,	/* type A - short bus fault (68020/030) */
176 	FMTBSIZE,	/* type B - long bus fault (68020/030) */
177 	-1, -1, -1, -1	/* type C-F - undefined */
178 };
179 
180 #ifdef DEBUG
181 int mmudebug = 0;
182 #endif
183 
184 extern struct pcb *curpcb;
185 extern char fubail[], subail[];
186 int _write_back(u_int, u_int, u_int, u_int, struct vm_map *);
187 static void userret(struct proc *, int, u_quad_t);
188 void panictrap(int, u_int, u_int, struct frame *);
189 void trapcpfault(struct proc *, struct frame *);
190 void trapmmufault(int, u_int, u_int, struct frame *, struct proc *,
191 			u_quad_t);
192 void trap(int, u_int, u_int, struct frame);
193 #ifdef DDB
194 #include <m68k/db_machdep.h>
195 int kdb_trap(int, db_regs_t *);
196 #endif
197 void _wb_fault(void);
198 
199 
200 static void
201 userret(p, pc, oticks)
202 	struct proc *p;
203 	int pc;
204 	u_quad_t oticks;
205 {
206 	int sig;
207 
208 	while ((sig = CURSIG(p)) != 0)
209 		postsig(sig);
210 
211 	p->p_priority = p->p_usrpri;
212 
213 	if (want_resched) {
214 		/*
215 		 * We are being preempted.
216 		 */
217 		preempt(NULL);
218 		while ((sig = CURSIG(p)) != 0)
219 			postsig(sig);
220 	}
221 	/*
222 	 * If profiling, charge recent system time.
223 	 */
224 	if (p->p_flag & P_PROFIL) {
225 		extern int psratio;
226 
227 		addupc_task(p, pc, (int)(p->p_sticks - oticks) * psratio);
228 	}
229 	curcpu()->ci_schedstate.spc_curpriority = p->p_priority;
230 }
231 
232 /*
233  * Used by the common m68k syscall() and child_return() functions.
234  * XXX: Temporary until all m68k ports share common trap()/userret() code.
235  */
236 void machine_userret(struct proc *, struct frame *, u_quad_t);
237 
238 void
239 machine_userret(p, f, t)
240 	struct proc *p;
241 	struct frame *f;
242 	u_quad_t t;
243 {
244 
245 	userret(p, f->f_pc, t);
246 }
247 
248 void
249 panictrap(type, code, v, fp)
250 	int type;
251 	u_int code, v;
252 	struct frame *fp;
253 {
254 	static int panicing = 0;
255 	if (panicing++ == 0) {
256 		printf("trap type %d, code = %x, v = %x\n", type, code, v);
257 		regdump((struct trapframe *)fp, 128);
258 	}
259 	type &= ~T_USER;
260 #ifdef DEBUG
261 	DCIS(); 		/* XXX? push cache */
262 #endif
263 	if ((u_int)type < trap_types)
264 		panic(trap_type[type]);
265 	panic("trap");
266 	/*NOTREACHED*/
267 }
268 
269 /*
270  * return to fault handler
271  */
272 void
273 trapcpfault(p, fp)
274 	struct proc *p;
275 	struct frame *fp;
276 {
277 	/*
278 	 * We have arranged to catch this fault in one of the
279 	 * copy to/from user space routines, set PC to return to
280 	 * indicated location and set flag informing buserror code
281 	 * that it may need to clean up stack frame.
282 	 */
283 	fp->f_stackadj = exframesize[fp->f_format];
284 	fp->f_format = fp->f_vector = 0;
285 	fp->f_pc = (int) p->p_addr->u_pcb.pcb_onfault;
286 }
287 
288 int donomore = 0;
289 
290 void
291 trapmmufault(type, code, v, fp, p, sticks)
292 	int type;
293 	u_int code, v;
294 	struct frame *fp;
295 	struct proc *p;
296 	u_quad_t sticks;
297 {
298 #if defined(DEBUG) && defined(M68060)
299 	static u_int oldcode=0, oldv=0;
300 	static struct proc *oldp=0;
301 #endif
302 	extern struct vm_map *kernel_map;
303 	struct vmspace *vm = NULL;
304 	vm_prot_t ftype;
305 	vaddr_t va;
306 	struct vm_map *map;
307 	u_int nss;
308 	int rv;
309 
310 	/*
311 	 * It is only a kernel address space fault iff:
312 	 * 	1. (type & T_USER) == 0  and
313 	 * 	2. pcb_onfault not set or
314 	 *	3. pcb_onfault set but supervisor space data fault
315 	 * The last can occur during an exec() copyin where the
316 	 * argument space is lazy-allocated.
317 	 */
318 #ifdef DEBUG
319 	/*
320 	 * Print out some data about the fault
321 	 */
322 #ifdef DEBUG_PAGE0
323 	if (v < NBPG)					/* XXX PAGE0 */
324 		mmudebug |= 0x100;			/* XXX PAGE0 */
325 #endif
326 	if (mmudebug && mmutype == MMU_68040) {
327 #ifdef M68060
328 		if (machineid & AMIGA_68060) {
329 			if (--donomore == 0 || mmudebug & 1) {
330 				char bits[64];
331 				printf ("68060 access error: pc %x, code %s,"
332 				     " ea %x\n", fp->f_pc,
333 				     bitmask_snprintf(code, FSLW_STRING,
334 				     bits, sizeof(bits)), v);
335 			}
336 			if (p == oldp && v == oldv && code == oldcode)
337 				panic("Identical fault backtoback!");
338 			if (donomore == 0)
339 				panic("Tired of faulting.");
340 			oldp = p;
341 			oldv = v;
342 			oldcode = code;
343 		} else
344 #endif
345 		printf("68040 access error: pc %x, code %x,"
346 		    " ea %x, fa %x\n", fp->f_pc, code, fp->f_fmt7.f_ea, v);
347 		if (curpcb)
348 			printf(" curpcb %p\n", curpcb);
349 
350 
351 #ifdef DDB						/* XXX PAGE0 */
352 		if (v < NBPG)				/* XXX PAGE0 */
353 			Debugger();			/* XXX PAGE0 */
354 #endif							/* XXX PAGE0 */
355 	}
356 #ifdef DEBUG_PAGE0
357 	mmudebug &= ~0x100;				/* XXX PAGE0 */
358 #endif
359 #endif
360 
361 	if (p)
362 		vm = p->p_vmspace;
363 
364 	if (type == T_MMUFLT &&
365 	    (!p || !p->p_addr || p->p_addr->u_pcb.pcb_onfault == 0 || (
366 #ifdef M68060
367 	     machineid & AMIGA_68060 ? code & FSLW_TM_SV :
368 #endif
369 	     mmutype == MMU_68040 ? (code & SSW_TMMASK) == FC_SUPERD :
370 	     (code & (SSW_DF|FC_SUPERD)) == (SSW_DF|FC_SUPERD))))
371 		map = kernel_map;
372 	else
373 		map = &vm->vm_map;
374 
375 	if (
376 #ifdef M68060
377 	    machineid & AMIGA_68060 ? code & FSLW_RW_W :
378 #endif
379 	    mmutype == MMU_68040 ? (code & SSW_RW040) == 0 :
380 	    (code & (SSW_DF|SSW_RW)) == SSW_DF)
381 							/* what about RMW? */
382 		ftype = VM_PROT_WRITE;
383 	else
384 		ftype = VM_PROT_READ;
385 	va = trunc_page((vaddr_t)v);
386 #ifdef DEBUG
387 	if (map == kernel_map && va == 0) {
388 		printf("trap: bad kernel access at %x pc %x\n", v, fp->f_pc);
389 		panictrap(type, code, v, fp);
390 	}
391 #endif
392 #ifndef no_386bsd_code
393 	/*
394 	 * XXX: rude hack to make stack limits "work"
395 	 */
396 	nss = 0;
397 	if (map != kernel_map && (caddr_t)va >= vm->vm_maxsaddr) {
398 		nss = btoc(USRSTACK - (unsigned)va);
399 		if (nss > btoc(p->p_rlimit[RLIMIT_STACK].rlim_cur)) {
400 			nss = 0;
401 		}
402 	}
403 #endif
404 
405 #ifdef DEBUG
406 	if (mmudebug)
407 		printf("vm_fault(%p,%lx,%d,0)\n", map, va, ftype);
408 #endif
409 
410 	rv = uvm_fault(map, va, 0, ftype);
411 
412 #ifdef DEBUG
413 	if (mmudebug)
414 		printf("vmfault %s %lx returned %d\n",
415 		    map == kernel_map ? "kernel" : "user", va, rv);
416 #endif
417 #ifdef M68060
418 	if ((machineid & AMIGA_68060) == 0 && mmutype == MMU_68040) {
419 #else
420 	if (mmutype == MMU_68040) {
421 #endif
422 		if (rv != 0) {
423 			goto nogo;
424 		}
425 
426 		/*
427 		 * The 68040 doesn't re-run instructions that cause
428 		 * write page faults (unless due to a move16 isntruction).
429 		 * So once the page is repaired, we have to write the
430 		 * value of WB2D out to memory ourselves.  Because
431 		 * the writeback could possibly span two pages in
432 		 * memory, so we need to check both "ends" of the
433 		 * address to see if they are in the same page or not.
434 		 * If not, then we need to make sure the second page
435 		 * is valid, and bring it into memory if it's not.
436 		 *
437 		 * This whole process needs to be repeated for WB3 as well.
438 		 * <sigh>
439 		 */
440 
441 		/* Check WB1 */
442 		if (fp->f_fmt7.f_wb1s & WBS_VALID) {
443 			printf ("trap: wb1 was valid, not handled yet\n");
444 			panictrap(type, code, v, fp);
445 		}
446 
447 		/*
448 		 * Check WB2
449 		 * skip if it's for a move16 instruction
450 		 */
451 		if(fp->f_fmt7.f_wb2s & WBS_VALID &&
452 		   ((fp->f_fmt7.f_wb2s & WBS_TTMASK)==WBS_TT_MOVE16) == 0) {
453 			if (_write_back(2, fp->f_fmt7.f_wb2s,
454 			    fp->f_fmt7.f_wb2d, fp->f_fmt7.f_wb2a, map) != 0)
455 				goto nogo;
456 			if ((fp->f_fmt7.f_wb2s & WBS_TMMASK)
457 			    != (code & SSW_TMMASK))
458 				panictrap(type, code, v, fp);
459 		}
460 
461 		/* Check WB3 */
462 		if(fp->f_fmt7.f_wb3s & WBS_VALID) {
463 			struct vm_map *wb3_map;
464 
465 			if ((fp->f_fmt7.f_wb3s & WBS_TMMASK) == WBS_TM_SDATA)
466 				wb3_map = kernel_map;
467 			else
468 				wb3_map = &vm->vm_map;
469 			if (_write_back(3, fp->f_fmt7.f_wb3s,
470 			    fp->f_fmt7.f_wb3d, fp->f_fmt7.f_wb3a, wb3_map) != 0)
471 				goto nogo;
472 		}
473 	}
474 
475 #ifdef no_386bsd_code
476 	/*
477 	 * If this was a stack access we keep track of the maximum
478 	 * accessed stack size.  Also, if vm_fault gets a protection
479 	 * failure it is due to accessing the stack region outside
480 	 * the current limit and we need to reflect that as an access
481 	 * error.
482 	 */
483 	if (map != kernel_map && (caddr_t)va >= vm->vm_maxsaddr) {
484 		if (rv == 0) {
485 			nss = btoc(USRSTACK-(unsigned)va);
486 			if (nss > vm->vm_ssize)
487 				vm->vm_ssize = nss;
488 		} else if (rv == EACCES)
489 			rv = EFAULT;
490 	}
491 
492 	if (rv == 0) {
493 		if (type == T_MMUFLT)
494 			return;
495 		userret(p, fp->f_pc, sticks);
496 		return;
497 	}
498 #else /* use hacky 386bsd_code */
499 	if (rv == 0) {
500 		/*
501 		 * XXX: continuation of rude stack hack
502 		 */
503 		if (nss > vm->vm_ssize)
504 			vm->vm_ssize = nss;
505 		if (type == T_MMUFLT)
506 			return;
507 		userret(p, fp->f_pc, sticks);
508 		return;
509 	}
510 nogo:
511 #endif
512 	if (type == T_MMUFLT) {
513 		if (p->p_addr->u_pcb.pcb_onfault) {
514 			trapcpfault(p, fp);
515 			return;
516 		}
517 		printf("uvm_fault(%p, 0x%lx, 0, 0x%x) -> 0x%x\n",
518 		    map, va, ftype, rv);
519 		printf("  type %x, code [mmu,,ssw]: %x\n",
520 		       type, code);
521 		panictrap(type, code, v, fp);
522 	}
523 	if (rv == ENOMEM) {
524 		printf("UVM: pid %d (%s), uid %d killed: out of swap\n",
525 		       p->p_pid, p->p_comm,
526 		       p->p_cred && p->p_ucred ? p->p_ucred->cr_uid : -1);
527 		trapsignal(p, SIGKILL, v);
528 	} else {
529 		trapsignal(p, SIGSEGV, v);
530 	}
531 	if ((type & T_USER) == 0)
532 		return;
533 	userret(p, fp->f_pc, sticks);
534 }
535 /*
536  * Trap is called from locore to handle most types of processor traps,
537  * including events such as simulated software interrupts/AST's.
538  * System calls are broken out for efficiency.
539  */
540 /*ARGSUSED*/
541 void
542 trap(type, code, v, frame)
543 	int type;
544 	u_int code, v;
545 	struct frame frame;
546 {
547 	struct proc *p;
548 	u_int ucode;
549 	u_quad_t sticks = 0;
550 	int i;
551 
552 	p = curproc;
553 	ucode = 0;
554 	uvmexp.traps++;
555 
556 	if (USERMODE(frame.f_sr)) {
557 		type |= T_USER;
558 		sticks = p->p_sticks;
559 		p->p_md.md_regs = frame.f_regs;
560 	}
561 
562 #ifdef DDB
563 	if (type == T_TRACE || type == T_BREAKPOINT) {
564 		if (kdb_trap(type, (db_regs_t *)&frame))
565 			return;
566 	}
567 #endif
568 #ifdef DEBUG
569 	if (mmudebug & 2)
570 	printf("trap: t %x c %x v %x pad %x adj %x sr %x pc %x fmt %x vc %x\n",
571 	    type, code, v, frame.f_pad, frame.f_stackadj, frame.f_sr,
572 	    frame.f_pc, frame.f_format, frame.f_vector);
573 #endif
574 	switch (type) {
575 	default:
576 		panictrap(type, code, v, &frame);
577 	/*
578 	 * Kernel Bus error
579 	 */
580 	case T_BUSERR:
581 		if (!p || !p->p_addr || !p->p_addr->u_pcb.pcb_onfault)
582 			panictrap(type, code, v, &frame);
583 		trapcpfault(p, &frame);
584 		return;
585 	/*
586 	 * User Bus/Addr error.
587 	 */
588 	case T_BUSERR|T_USER:
589 	case T_ADDRERR|T_USER:
590 		i = SIGBUS;
591 		break;
592 	/*
593 	 * User illegal/privleged inst fault
594 	 */
595 	case T_ILLINST|T_USER:
596 	case T_PRIVINST|T_USER:
597 		ucode = frame.f_format;	/* XXX was ILL_PRIVIN_FAULT */
598 		i = SIGILL;
599 		break;
600 	/*
601 	 * divde by zero, CHK/TRAPV inst
602 	 */
603 	case T_ZERODIV|T_USER:
604 	case T_CHKINST|T_USER:
605 	case T_TRAPVINST|T_USER:
606 		ucode = frame.f_format;
607 		i = SIGFPE;
608 		break;
609 
610 	case T_FPEMULI|T_USER:
611 	case T_FPEMULD|T_USER:
612 #ifdef FPU_EMULATE
613 		i = fpu_emulate(&frame, &p->p_addr->u_pcb.pcb_fpregs);
614 		/* XXX - Deal with tracing? (frame.f_sr & PSL_T) */
615 #else
616 		printf("pid %d killed: no floating point support\n", p->p_pid);
617 		i = SIGILL;
618 #endif
619 		break;
620 
621 #ifdef FPCOPROC
622 	/*
623 	 * User coprocessor violation
624 	 */
625 	case T_COPERR|T_USER:
626 		ucode = 0;
627 		i = SIGFPE;	/* XXX What is a proper response here? */
628 		break;
629 	/*
630 	 * 6888x exceptions
631 	 */
632 	case T_FPERR|T_USER:
633 		/*
634 		 * We pass along the 68881 status register which locore
635 		 * stashed in code for us.  Note that there is a
636 		 * possibility that the bit pattern of this register
637 		 * will conflict with one of the FPE_* codes defined
638 		 * in signal.h.  Fortunately for us, the only such
639 		 * codes we use are all in the range 1-7 and the low
640 		 * 3 bits of the status register are defined as 0 so
641 		 * there is no clash.
642 		 */
643 		ucode = code;
644 		i = SIGFPE;
645 		break;
646 	/*
647 	 * Kernel coprocessor violation
648 	 */
649 	case T_COPERR:
650 		/*FALLTHROUGH*/
651 #endif
652 	/*
653 	 * Kernel format error
654 	 */
655 	case T_FMTERR:
656 		/*
657 		 * The user has most likely trashed the RTE or FP state info
658 		 * in the stack frame of a signal handler.
659 		 */
660 		type |= T_USER;
661 #ifdef DEBUG
662 		printf("pid %d: kernel %s exception\n", p->p_pid,
663 		    type==T_COPERR ? "coprocessor" : "format");
664 #endif
665 		SIGACTION(p, SIGILL).sa_handler = SIG_DFL;
666 		sigdelset(&p->p_sigctx.ps_sigignore, SIGILL);
667 		sigdelset(&p->p_sigctx.ps_sigcatch, SIGILL);
668 		sigdelset(&p->p_sigctx.ps_sigmask, SIGILL);
669 		i = SIGILL;
670 		ucode = frame.f_format;	/* XXX was ILL_RESAD_FAULT */
671 		break;
672 	/*
673 	 * Trace traps.
674 	 *
675 	 * M68k NetBSD uses trap #2,
676 	 * SUN 3.x uses trap #15,
677 	 * KGDB uses trap #15 (for kernel breakpoints; handled elsewhere).
678 	 *
679 	 * Amiga traps get mapped by locore.s into T_TRACE.
680 	 * SUN 3.x traps get passed through as T_TRAP15 and are not really
681 	 * supported yet.
682 	 */
683 	case T_TRACE:
684 	case T_TRAP15:
685 		frame.f_sr &= ~PSL_T;
686 		i = SIGTRAP;
687 		break;
688 	case T_TRACE|T_USER:
689 	case T_TRAP15|T_USER:
690 #ifdef COMPAT_SUNOS
691 		/*
692 		 * SunOS uses Trap #2 for a "CPU cache flush".
693 		 * Just flush the on-chip caches and return.
694 		 */
695 		if (p->p_emul == &emul_sunos) {
696 			ICIA();
697 			DCIU();
698 			return;
699 		}
700 #endif
701 		frame.f_sr &= ~PSL_T;
702 		i = SIGTRAP;
703 		break;
704 	/*
705 	 * Kernel AST (should not happen)
706 	 */
707 	case T_ASTFLT:
708 		panictrap(type, code, v, &frame);
709 	/*
710 	 * User AST
711 	 */
712 	case T_ASTFLT|T_USER:
713 		astpending = 0;
714 		spl0();
715 		if (p->p_flag & P_OWEUPC) {
716 			p->p_flag &= ~P_OWEUPC;
717 			ADDUPROF(p);
718 		}
719 		userret(p, frame.f_pc, sticks);
720 		return;
721 	/*
722 	 * Kernel/User page fault
723 	 */
724 	case T_MMUFLT:
725 		if (p && p->p_addr &&
726 		    (p->p_addr->u_pcb.pcb_onfault == (caddr_t)fubail ||
727 		    p->p_addr->u_pcb.pcb_onfault == (caddr_t)subail)) {
728 			trapcpfault(p, &frame);
729 			return;
730 		}
731 		/*FALLTHROUGH*/
732 	case T_MMUFLT|T_USER:	/* page fault */
733 		trapmmufault(type, code, v, &frame, p, sticks);
734 		return;
735 	}
736 
737 #ifdef DEBUG
738 	if (i != SIGTRAP)
739 		printf("trapsignal(%d, %d, %d, %x, %x)\n", p->p_pid, i,
740 		    ucode, v, frame.f_pc);
741 #endif
742 	if (i)
743 		trapsignal(p, i, ucode);
744 	if ((type & T_USER) == 0)
745 		return;
746 	userret(p, frame.f_pc, sticks);
747 }
748 
749 /*
750  * Process a pending write back
751  */
752 int
753 _write_back (wb, wb_sts, wb_data, wb_addr, wb_map)
754 	u_int wb;	/* writeback type: 1, 2, or 3 */
755 	u_int wb_sts;	/* writeback status information */
756 	u_int wb_data;	/* data to writeback */
757 	u_int wb_addr;	/* address to writeback to */
758 	struct vm_map *wb_map;
759 {
760 	u_int wb_extra_page = 0;
761 	u_int wb_rc, mmusr;
762 
763 #ifdef DEBUG
764 	if (mmudebug)
765 		printf("wb%d valid: %x %x %x\n",wb,wb_sts,wb_addr,wb_data);
766 #endif
767 
768 	/* See if we're going to span two pages (for word or long transfers) */
769 
770 	if((wb_sts & WBS_SZMASK) == WBS_SIZE_WORD)
771 		if(trunc_page((vaddr_t)wb_addr) !=
772 		    trunc_page((vaddr_t)wb_addr+1))
773 			wb_extra_page = 1;
774 
775 	if((wb_sts & WBS_SZMASK) == WBS_SIZE_LONG)
776 		if(trunc_page((vaddr_t)wb_addr) !=
777 		    trunc_page((vaddr_t)wb_addr+3))
778 			wb_extra_page = 3;
779 
780 	/*
781 	 * if it's writeback 3, we need to check the first page
782 	 */
783 	if (wb == 3) {
784 		mmusr = probeva(wb_addr, wb_sts & WBS_TMMASK);
785 #ifdef DEBUG
786 	if (mmudebug)
787 		printf("wb3: probeva(%x,%x) = %x\n",
788 		    wb_addr + wb_extra_page, wb_sts & WBS_TMMASK, mmusr);
789 #endif
790 
791 		if((mmusr & (MMUSR_R | MMUSR_W)) != MMUSR_R) {
792 #ifdef DEBUG
793 			if (mmudebug)
794 				printf("wb3: need to bring in first page\n");
795 #endif
796 			wb_rc = uvm_fault(wb_map,
797 			    trunc_page((vm_offset_t)wb_addr),
798 			    0, VM_PROT_READ | VM_PROT_WRITE);
799 
800 			if (wb_rc != 0)
801 				return (wb_rc);
802 #ifdef DEBUG
803 			if (mmudebug)
804 				printf("wb3: first page brought in.\n");
805 #endif
806 		}
807 	}
808 
809 	/*
810 	 * now check to see if a second page is required
811 	 */
812 	if(wb_extra_page) {
813 
814 		mmusr = probeva(wb_addr+wb_extra_page, wb_sts & WBS_TMMASK);
815 #ifdef DEBUG
816 		if (mmudebug)
817 			printf("wb%d: probeva %x %x = %x\n",
818 			    wb, wb_addr + wb_extra_page,
819 			    wb_sts & WBS_TMMASK,mmusr);
820 #endif
821 
822 		if((mmusr & (MMUSR_R | MMUSR_W)) != MMUSR_R) {
823 #ifdef DEBUG
824 			if (mmudebug)
825 				printf("wb%d: page boundary crossed."
826 				    "  Bringing in extra page.\n",wb);
827 #endif
828 
829 			wb_rc = uvm_fault(wb_map,
830 			    trunc_page((vm_offset_t)wb_addr + wb_extra_page),
831 			    0, VM_PROT_READ | VM_PROT_WRITE);
832 
833 			if (wb_rc != 0)
834 				return (wb_rc);
835 		}
836 #ifdef DEBUG
837 		if (mmudebug)
838 			printf("wb%d: extra page brought in okay.\n", wb);
839 #endif
840 	}
841 
842 	/* Actually do the write now */
843 
844 	if ((wb_sts & WBS_TMMASK) == FC_USERD &&
845 	    !curpcb->pcb_onfault) {
846 	    	curpcb->pcb_onfault = (caddr_t) _wb_fault;
847 	}
848 
849 	switch(wb_sts & WBS_SZMASK) {
850 
851 	case WBS_SIZE_BYTE :
852 		asm volatile ("movec %0,%%dfc ; movesb %1,%2@":: "d" (wb_sts & WBS_TMMASK),
853 								 "d" (wb_data),
854 								 "a" (wb_addr));
855 		break;
856 
857 	case WBS_SIZE_WORD :
858 		asm volatile ("movec %0,%%dfc ; movesw %1,%2@":: "d" (wb_sts & WBS_TMMASK),
859 								 "d" (wb_data),
860 								 "a" (wb_addr));
861 		break;
862 
863 	case WBS_SIZE_LONG :
864 		asm volatile ("movec %0,%%dfc ; movesl %1,%2@":: "d" (wb_sts & WBS_TMMASK),
865 								 "d" (wb_data),
866 								 "a" (wb_addr));
867 		break;
868 
869 	}
870 	if (curpcb->pcb_onfault == (caddr_t) _wb_fault)
871 		curpcb->pcb_onfault = NULL;
872 	if ((wb_sts & WBS_TMMASK) != FC_USERD)
873 		asm volatile ("movec %0,%%dfc\n" : : "d" (FC_USERD));
874 	return 0;
875 }
876 
877 /*
878  * fault handler for write back
879  */
880 void
881 _wb_fault()
882 {
883 #ifdef DEBUG
884 	printf ("trap: writeback fault\n");
885 #endif
886 	return;
887 }
888