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