xref: /netbsd-src/sys/arch/amiga/amiga/trap.c (revision f0eb9f868ac05e98b02fef5affab68945a02f0f0)
1 /*	$NetBSD: trap.c,v 1.143 2024/05/04 13:45:10 mlelstv 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.143 2024/05/04 13:45:10 mlelstv 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/fcode.h>
68 #include <machine/pcb.h>
69 #include <machine/pte.h>
70 
71 #include <m68k/fpe/fpu_emulate.h>
72 #include <m68k/cacheops.h>
73 
74 #ifdef COMPAT_SUNOS
75 #include <compat/sunos/sunos_syscall.h>
76 extern struct emul emul_sunos;
77 #endif
78 
79 /*
80  * XXX Hack until I can figure out what to do about this code's removal
81  * from m68k/include/frame.h
82  */
83 
84 /* 68040 fault frame */
85 #define SSW_CP		0x8000		/* Continuation - Floating-Point Post*/
86 #define SSW_CU		0x4000		/* Continuation - Unimpl. FP */
87 #define SSW_CT		0x2000		/* Continuation - Trace */
88 #define SSW_CM		0x1000		/* Continuation - MOVEM */
89 #define SSW_MA		0x0800		/* Misaligned access */
90 #define SSW_ATC		0x0400		/* ATC fault */
91 #define SSW_LK		0x0200		/* Locked transfer */
92 #define SSW_RW040	0x0100		/* Read/Write */
93 #define SSW_SZMASK	0x0060		/* Transfer size */
94 #define SSW_TTMASK	0x0018		/* Transfer type */
95 #define SSW_TMMASK	0x0007		/* Transfer modifier */
96 
97 #define WBS_TMMASK	0x0007
98 #define WBS_TTMASK	0x0018
99 #define WBS_SZMASK	0x0060
100 #define WBS_VALID	0x0080
101 
102 #define WBS_SIZE_BYTE	0x0020
103 #define WBS_SIZE_WORD	0x0040
104 #define WBS_SIZE_LONG	0x0000
105 #define WBS_SIZE_LINE	0x0060
106 
107 #define WBS_TT_NORMAL	0x0000
108 #define WBS_TT_MOVE16	0x0008
109 #define WBS_TT_ALTFC	0x0010
110 #define WBS_TT_ACK	0x0018
111 
112 #define WBS_TM_PUSH	0x0000
113 #define WBS_TM_UDATA	0x0001
114 #define WBS_TM_UCODE	0x0002
115 #define WBS_TM_MMUTD	0x0003
116 #define WBS_TM_MMUTC	0x0004
117 #define WBS_TM_SDATA	0x0005
118 #define WBS_TM_SCODE	0x0006
119 #define WBS_TM_RESV	0x0007
120 
121 #define	MMUSR_PA_MASK	0xfffff000
122 #define MMUSR_B		0x00000800
123 #define MMUSR_G		0x00000400
124 #define MMUSR_U1	0x00000200
125 #define MMUSR_U0	0x00000100
126 #define MMUSR_S		0x00000080
127 #define MMUSR_CM	0x00000060
128 #define MMUSR_M		0x00000010
129 #define MMUSR_0		0x00000008
130 #define MMUSR_W		0x00000004
131 #define MMUSR_T		0x00000002
132 #define MMUSR_R		0x00000001
133 
134 #define FSLW_STRING	"\020\1SEE\3BPE\4TTR\5WE\6RE\7TWE\010WP\011SP" \
135 			"\012PF\013IL\014PTB\015PTA\016SBE\017PBE"
136 /*
137  * XXX End hack
138  */
139 
140 volatile int astpending;
141 
142 const char *trap_type[] = {
143 	"Bus error",
144 	"Address error",
145 	"Illegal instruction",
146 	"Zero divide",
147 	"CHK instruction",
148 	"TRAPV instruction",
149 	"Privilege violation",
150 	"Trace trap",
151 	"MMU fault",
152 	"SSIR trap",
153 	"Format error",
154 	"68881 exception",
155 	"Coprocessor violation",
156 	"Async system trap"
157 };
158 int	trap_types = sizeof trap_type / sizeof trap_type[0];
159 
160 /*
161  * Size of various exception stack frames (minus the standard 8 bytes)
162  */
163 short	exframesize[] = {
164 	FMT0SIZE,	/* type 0 - normal (68020/030/040/060) */
165 	FMT1SIZE,	/* type 1 - throwaway (68020/030/040) */
166 	FMT2SIZE,	/* type 2 - normal 6-word (68020/030/040/060) */
167 	FMT3SIZE,	/* type 3 - FP post-instruction (68040/060) */
168 	FMT4SIZE,	/* type 4 - access error/fp disabled (68060) */
169 	-1, -1,		/* type 5-6 - undefined */
170 	FMT7SIZE,	/* type 7 - access error (68040) */
171 	58,		/* type 8 - bus fault (68010) */
172 	FMT9SIZE,	/* type 9 - coprocessor mid-instruction (68020/030) */
173 	FMTASIZE,	/* type A - short bus fault (68020/030) */
174 	FMTBSIZE,	/* type B - long bus fault (68020/030) */
175 	-1, -1, -1, -1	/* type C-F - undefined */
176 };
177 
178 #ifdef DEBUG
179 int mmudebug = 0;
180 #endif
181 
182 extern struct pcb *curpcb;
183 int _write_back(u_int, u_int, u_int, u_int, struct vm_map *);
184 static void userret(struct lwp *, int, u_quad_t);
185 void panictrap(int, u_int, u_int, struct frame *);
186 void trapcpfault(struct lwp *, struct frame *, int);
187 void trapmmufault(int, u_int, u_int, struct frame *, struct lwp *,
188 			u_quad_t);
189 void trap(struct frame *, int, u_int, u_int);
190 #ifdef DDB
191 #include <m68k/db_machdep.h>
192 int kdb_trap(int, db_regs_t *);
193 #endif
194 void _wb_fault(void);
195 
196 
197 static void
userret(struct lwp * l,int pc,u_quad_t oticks)198 userret(struct lwp *l, int pc, u_quad_t oticks)
199 {
200 	struct proc *p = l->l_proc;
201 
202 	/* Invoke MI userret code */
203 	mi_userret(l);
204 
205 	/*
206 	 * If profiling, charge recent system time.
207 	 */
208 	if (p->p_stflag & PST_PROFIL) {
209 		extern int psratio;
210 
211 		addupc_task(l, pc, (int)(p->p_sticks - oticks) * psratio);
212 	}
213 }
214 
215 /*
216  * Used by the common m68k syscall() and child_return() functions.
217  * XXX: Temporary until all m68k ports share common trap()/userret() code.
218  */
219 void machine_userret(struct lwp *, struct frame *, u_quad_t);
220 
221 void
machine_userret(struct lwp * l,struct frame * f,u_quad_t t)222 machine_userret(struct lwp *l, struct frame *f, u_quad_t t)
223 {
224 
225 	userret(l, f->f_pc, t);
226 }
227 
228 void
panictrap(int type,u_int code,u_int v,struct frame * fp)229 panictrap(int type, u_int code, u_int v, struct frame *fp)
230 {
231 	static int panicking = 0;
232 	if (panicking++ == 0) {
233 		printf("trap type %d, code = %x, v = %x\n", type, code, v);
234 		regdump((struct trapframe *)fp, 128);
235 	}
236 	type &= ~T_USER;
237 #ifdef DEBUG
238 	DCIS(); 		/* XXX? push cache */
239 #endif
240 	if ((u_int)type < trap_types)
241 		panic(trap_type[type]);
242 	panic("trap");
243 	/*NOTREACHED*/
244 }
245 
246 /*
247  * return to fault handler
248  */
249 void
trapcpfault(struct lwp * l,struct frame * fp,int error)250 trapcpfault(struct lwp *l, struct frame *fp, int error)
251 {
252 	struct pcb *pcb = lwp_getpcb(l);
253 
254 	/*
255 	 * We have arranged to catch this fault in one of the
256 	 * copy to/from user space routines, set PC to return to
257 	 * indicated location and set flag informing buserror code
258 	 * that it may need to clean up stack frame.
259 	 */
260 	fp->f_stackadj = exframesize[fp->f_format];
261 	fp->f_format = fp->f_vector = 0;
262 	fp->f_pc = (int)pcb->pcb_onfault;
263 	fp->f_regs[D0] = error;
264 }
265 
266 int donomore = 0;
267 
268 void
trapmmufault(int type,u_int code,u_int v,struct frame * fp,struct lwp * l,u_quad_t sticks)269 trapmmufault(int type, u_int code, u_int v, struct frame *fp, struct lwp *l, u_quad_t sticks)
270 {
271 #if defined(DEBUG) && defined(M68060)
272 	static u_int oldcode=0, oldv=0;
273 	static struct proc *oldp=0;
274 #endif
275 	extern struct vm_map *kernel_map;
276 	struct proc *p = l->l_proc;
277 	struct vmspace *vm = NULL;
278 	struct vm_map *map;
279 	struct pcb *pcb;
280 	void *onfault;
281 	vm_prot_t ftype;
282 	vaddr_t va;
283 	ksiginfo_t ksi;
284 	int rv;
285 
286 	pcb = lwp_getpcb(l);
287 	onfault = pcb->pcb_onfault;
288 
289 	KSI_INIT_TRAP(&ksi);
290 	ksi.ksi_trap = type & ~T_USER;
291 
292 	/*
293 	 * It is only a kernel address space fault iff:
294 	 * 	1. (type & T_USER) == 0  and
295 	 * 	2. pcb_onfault not set or
296 	 *	3. pcb_onfault set but supervisor space data fault
297 	 * The last can occur during an exec() copyin where the
298 	 * argument space is lazy-allocated.
299 	 */
300 #ifdef DEBUG
301 	/*
302 	 * Print out some data about the fault
303 	 */
304 #ifdef DEBUG_PAGE0
305 	if (v < PAGE_SIZE)				/* XXX PAGE0 */
306 		mmudebug |= 0x100;			/* XXX PAGE0 */
307 #endif
308 	if (mmudebug && mmutype == MMU_68040) {
309 #ifdef M68060
310 		if (machineid & AMIGA_68060) {
311 			if (--donomore == 0 || mmudebug & 1) {
312 				char bits[64];
313 				snprintb(bits, sizeof(bits), FSLW_STRING, code);
314 				printf ("68060 access error: pc %x, code %s,"
315 				     " ea %x\n", fp->f_pc, bits, v);
316 			}
317 			if (p == oldp && v == oldv && code == oldcode)
318 				panic("Identical fault backtoback!");
319 			if (donomore == 0)
320 				panic("Tired of faulting.");
321 			oldp = p;
322 			oldv = v;
323 			oldcode = code;
324 		} else
325 #endif
326 		printf("68040 access error: pc %x, code %x,"
327 		    " ea %x, fa %x\n", fp->f_pc, code, fp->f_fmt7.f_ea, v);
328 		if (curpcb)
329 			printf(" curpcb %p\n", curpcb);
330 
331 
332 #ifdef DDB						/* XXX PAGE0 */
333 		if (v < PAGE_SIZE)			/* XXX PAGE0 */
334 			Debugger();			/* XXX PAGE0 */
335 #endif							/* XXX PAGE0 */
336 	}
337 #ifdef DEBUG_PAGE0
338 	mmudebug &= ~0x100;				/* XXX PAGE0 */
339 #endif
340 #endif
341 
342 	if (p)
343 		vm = p->p_vmspace;
344 
345 	if (type == T_MMUFLT && (l == &lwp0 || onfault == 0 || (
346 #ifdef M68060
347 	     machineid & AMIGA_68060 ? code & FSLW_TM_SV :
348 #endif
349 	     mmutype == MMU_68040 ? (code & SSW_TMMASK) == FC_SUPERD :
350 	     (code & (SSW_DF|FC_SUPERD)) == (SSW_DF|FC_SUPERD))))
351 		map = kernel_map;
352 	else
353 		map = &vm->vm_map;
354 
355 	if (
356 #ifdef M68060
357 	    machineid & AMIGA_68060 ? code & FSLW_RW_W :
358 #endif
359 	    mmutype == MMU_68040 ? (code & (SSW_LK|SSW_RW040)) != SSW_RW040 :
360 	    ((code & SSW_DF) != 0 &&
361 	    ((code & SSW_RW) == 0 || (code & SSW_RM) != 0)))
362 		ftype = VM_PROT_WRITE;
363 	else
364 		ftype = VM_PROT_READ;
365 	va = trunc_page((vaddr_t)v);
366 #ifdef DEBUG
367 	if (map == kernel_map && va == 0 && onfault == 0) {
368 		printf("trap: bad kernel access at %x pc %x\n", v, fp->f_pc);
369 		panictrap(type, code, v, fp);
370 	}
371 
372 	if (mmudebug)
373 		printf("vm_fault(%p,%lx,%d)\n", map, va, ftype);
374 #endif
375 
376 	pcb->pcb_onfault = NULL;
377 	rv = uvm_fault(map, va, ftype);
378 	pcb->pcb_onfault = onfault;
379 
380 #ifdef DEBUG
381 	if (mmudebug)
382 		printf("vmfault %s %lx returned %d\n",
383 		    map == kernel_map ? "kernel" : "user", va, rv);
384 #endif
385 
386 #ifdef M68060
387 	if ((machineid & AMIGA_68060) == 0 && mmutype == MMU_68040) {
388 #else
389 	if (mmutype == MMU_68040) {
390 #endif
391 		if (rv != 0) {
392 			goto nogo;
393 		}
394 
395 		/*
396 		 * The 68040 doesn't re-run instructions that cause
397 		 * write page faults (unless due to a move16 isntruction).
398 		 * So once the page is repaired, we have to write the
399 		 * value of WB2D out to memory ourselves.  Because
400 		 * the writeback could possibly span two pages in
401 		 * memory, so we need to check both "ends" of the
402 		 * address to see if they are in the same page or not.
403 		 * If not, then we need to make sure the second page
404 		 * is valid, and bring it into memory if it's not.
405 		 *
406 		 * This whole process needs to be repeated for WB3 as well.
407 		 * <sigh>
408 		 */
409 
410 		/* Check WB1 */
411 		if (fp->f_fmt7.f_wb1s & WBS_VALID) {
412 			printf ("trap: wb1 was valid, not handled yet\n");
413 			panictrap(type, code, v, fp);
414 		}
415 
416 		/*
417 		 * Check WB2
418 		 * skip if it's for a move16 instruction
419 		 */
420 		if(fp->f_fmt7.f_wb2s & WBS_VALID &&
421 		   ((fp->f_fmt7.f_wb2s & WBS_TTMASK)==WBS_TT_MOVE16) == 0) {
422 			if (_write_back(2, fp->f_fmt7.f_wb2s,
423 			    fp->f_fmt7.f_wb2d, fp->f_fmt7.f_wb2a, map) != 0)
424 				goto nogo;
425 			if ((fp->f_fmt7.f_wb2s & WBS_TMMASK)
426 			    != (code & SSW_TMMASK))
427 				panictrap(type, code, v, fp);
428 		}
429 
430 		/* Check WB3 */
431 		if(fp->f_fmt7.f_wb3s & WBS_VALID) {
432 			struct vm_map *wb3_map;
433 
434 			if ((fp->f_fmt7.f_wb3s & WBS_TMMASK) == WBS_TM_SDATA)
435 				wb3_map = kernel_map;
436 			else
437 				wb3_map = &vm->vm_map;
438 			if (_write_back(3, fp->f_fmt7.f_wb3s,
439 			    fp->f_fmt7.f_wb3d, fp->f_fmt7.f_wb3a, wb3_map) != 0)
440 				goto nogo;
441 		}
442 	}
443 
444 	/*
445 	 * If this was a stack access we keep track of the maximum
446 	 * accessed stack size.  Also, if vm_fault gets a protection
447 	 * failure it is due to accessing the stack region outside
448 	 * the current limit and we need to reflect that as an access
449 	 * error.
450 	 */
451 	if (rv == 0) {
452 		if (map != kernel_map && (void *)va >= vm->vm_maxsaddr)
453 			uvm_grow(p, va);
454 
455 		if (type == T_MMUFLT)
456 			return;
457 		userret(l, fp->f_pc, sticks);
458 		return;
459 	}
460 nogo:
461 	if (type == T_MMUFLT) {
462 		if (onfault) {
463 			trapcpfault(l, fp, rv);
464 			return;
465 		}
466 		printf("uvm_fault(%p, 0x%lx, 0x%x) -> 0x%x\n",
467 		    map, va, ftype, rv);
468 		printf("  type %x, code [mmu,,ssw]: %x\n",
469 		       type, code);
470 		panictrap(type, code, v, fp);
471 	}
472 	ksi.ksi_addr = (void *)v;
473 	switch (rv) {
474 	case ENOMEM:
475 		printf("UVM: pid %d (%s), uid %d killed: out of swap\n",
476 		    p->p_pid, p->p_comm,
477 		    l->l_cred ? kauth_cred_geteuid(l->l_cred) : -1);
478 		ksi.ksi_signo = SIGKILL;
479 		break;
480 	case EINVAL:
481 		ksi.ksi_signo = SIGBUS;
482 		ksi.ksi_code = BUS_ADRERR;
483 		break;
484 	case EACCES:
485 		ksi.ksi_signo = SIGSEGV;
486 		ksi.ksi_code = SEGV_ACCERR;
487 		break;
488 	default:
489 		ksi.ksi_signo = SIGSEGV;
490 		ksi.ksi_code = SEGV_MAPERR;
491 		break;
492 	}
493 	trapsignal(l, &ksi);
494 	if ((type & T_USER) == 0)
495 		return;
496 	userret(l, fp->f_pc, sticks);
497 }
498 /*
499  * Trap is called from locore to handle most types of processor traps,
500  * including events such as simulated software interrupts/AST's.
501  * System calls are broken out for efficiency.
502  */
503 /*ARGSUSED*/
504 void
505 trap(struct frame *fp, int type, u_int code, u_int v)
506 {
507 	struct lwp *l;
508 	struct proc *p;
509 	struct pcb *pcb;
510 	ksiginfo_t ksi;
511 	u_quad_t sticks = 0;
512 
513 	l = curlwp;
514 	p = l->l_proc;
515 	pcb = lwp_getpcb(l);
516 
517 	curcpu()->ci_data.cpu_ntrap++;
518 
519 	KSI_INIT_TRAP(&ksi);
520 	ksi.ksi_trap = type & ~T_USER;
521 
522 	if (USERMODE(fp->f_sr)) {
523 		type |= T_USER;
524 		sticks = p->p_sticks;
525 		l->l_md.md_regs = fp->f_regs;
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