xref: /netbsd/sys/arch/luna68k/luna68k/trap.c (revision bf9ec67e)
1 /* $NetBSD: trap.c,v 1.19 2002/02/14 07:08:08 chs Exp $ */
2 
3 /*
4  * Copyright (c) 1988 University of Utah.
5  * Copyright (c) 1982, 1986, 1990, 1993
6  *	The Regents of the University of California.  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.37 92/12/20$
41  *
42  *	@(#)trap.c	8.5 (Berkeley) 1/4/94
43  */
44 
45 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
46 
47 __KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.19 2002/02/14 07:08:08 chs Exp $");
48 
49 #include "opt_ddb.h"
50 #include "opt_kgdb.h"
51 #include "opt_execfmt.h"
52 #include "opt_compat_hpux.h"
53 
54 #include <sys/param.h>
55 #include <sys/systm.h>
56 #include <sys/proc.h>
57 #include <sys/acct.h>
58 #include <sys/kernel.h>
59 #include <sys/signalvar.h>
60 #include <sys/resourcevar.h>
61 #include <sys/syscall.h>
62 #include <sys/syslog.h>
63 #include <sys/user.h>
64 
65 #include <machine/psl.h>
66 #include <machine/trap.h>
67 #include <machine/cpu.h>
68 #include <machine/reg.h>
69 #include <machine/db_machdep.h>
70 
71 #include <uvm/uvm_extern.h>
72 
73 #include <dev/cons.h>
74 
75 int   writeback __P((struct frame *fp, int docachepush));
76 void  trap __P((int type, u_int code, u_int v, struct frame frame));
77 
78 #if defined(M68040)
79 #ifdef DEBUG
80 static void dumpssw __P((u_short));
81 static void dumpwb __P((int, u_short, u_int, u_int));
82 #endif
83 #endif
84 
85 static inline void userret __P((struct proc *p, struct frame *fp,
86 	    u_quad_t oticks, u_int faultaddr, int fromtrap));
87 
88 int	astpending;
89 
90 char	*trap_type[] = {
91 	"Bus error",
92 	"Address error",
93 	"Illegal instruction",
94 	"Zero divide",
95 	"CHK instruction",
96 	"TRAPV instruction",
97 	"Privilege violation",
98 	"Trace trap",
99 	"MMU fault",
100 	"SSIR trap",
101 	"Format error",
102 	"68881 exception",
103 	"Coprocessor violation",
104 	"Async system trap"
105 };
106 int	trap_types = sizeof trap_type / sizeof trap_type[0];
107 
108 /*
109  * Size of various exception stack frames (minus the standard 8 bytes)
110  */
111 short	exframesize[] = {
112 	FMT0SIZE,	/* type 0 - normal (68020/030/040) */
113 	FMT1SIZE,	/* type 1 - throwaway (68020/030/040) */
114 	FMT2SIZE,	/* type 2 - normal 6-word (68020/030/040) */
115 	FMT3SIZE,	/* type 3 - FP post-instruction (68040) */
116 	-1, -1, -1,	/* type 4-6 - undefined */
117 	FMT7SIZE,	/* type 7 - access error (68040) */
118 	58,		/* type 8 - bus fault (68010) */
119 	FMT9SIZE,	/* type 9 - coprocessor mid-instruction (68020/030) */
120 	FMTASIZE,	/* type A - short bus fault (68020/030) */
121 	FMTBSIZE,	/* type B - long bus fault (68020/030) */
122 	-1, -1, -1, -1	/* type C-F - undefined */
123 };
124 
125 #ifdef M68040
126 #define KDFAULT(c)    (mmutype == MMU_68040 ? \
127 			    ((c) & SSW4_TMMASK) == SSW4_TMKD : \
128 			    ((c) & (SSW_DF|FC_SUPERD)) == (SSW_DF|FC_SUPERD))
129 #define WRFAULT(c)    (mmutype == MMU_68040 ? \
130 			    ((c) & SSW4_RW) == 0 : \
131 			    ((c) & (SSW_DF|SSW_RW)) == SSW_DF)
132 #else
133 #define KDFAULT(c)	(((c) & (SSW_DF|SSW_FCMASK)) == (SSW_DF|FC_SUPERD))
134 #define WRFAULT(c)	(((c) & (SSW_DF|SSW_RW)) == SSW_DF)
135 #endif
136 
137 #ifdef DEBUG
138 int mmudebug = 0;
139 int mmupid = -1;
140 #define MDB_FOLLOW	1
141 #define MDB_WBFOLLOW	2
142 #define MDB_WBFAILED	4
143 #define MDB_ISPID(p)	((p) == mmupid)
144 #endif
145 
146 /*
147  * trap and syscall both need the following work done before returning
148  * to user mode.
149  */
150 static inline void
151 userret(p, fp, oticks, faultaddr, fromtrap)
152 	struct proc *p;
153 	struct frame *fp;
154 	u_quad_t oticks;
155 	u_int faultaddr;
156 	int fromtrap;
157 {
158 	int sig;
159 #ifdef M68040
160 	int beenhere = 0;
161 
162 again:
163 #endif
164 	/* take pending signals */
165 	while ((sig = CURSIG(p)) != 0)
166 		postsig(sig);
167 	p->p_priority = p->p_usrpri;
168 	if (want_resched) {
169 		/*
170 		 * We are being preempted.
171 		 */
172 		preempt(NULL);
173 		while ((sig = CURSIG(p)) != 0)
174 			postsig(sig);
175 	}
176 
177 	/*
178 	 * If profiling, charge system time to the trapped pc.
179 	 */
180 	if (p->p_flag & P_PROFIL) {
181 		extern int psratio;
182 
183 		addupc_task(p, fp->f_pc,
184 			    (int)(p->p_sticks - oticks) * psratio);
185 	}
186 #ifdef M68040
187 	/*
188 	 * Deal with user mode writebacks (from trap, or from sigreturn).
189 	 * If any writeback fails, go back and attempt signal delivery.
190 	 * unless we have already been here and attempted the writeback
191 	 * (e.g. bad address with user ignoring SIGSEGV).  In that case
192 	 * we just return to the user without sucessfully completing
193 	 * the writebacks.  Maybe we should just drop the sucker?
194 	 */
195 	if (cputype == CPU_68040 && fp->f_format == FMT7) {
196 		if (beenhere) {
197 #ifdef DEBUG
198 			if (mmudebug & MDB_WBFAILED)
199 				printf(fromtrap ?
200 		"pid %d(%s): writeback aborted, pc=%x, fa=%x\n" :
201 		"pid %d(%s): writeback aborted in sigreturn, pc=%x\n",
202 				    p->p_pid, p->p_comm, fp->f_pc, faultaddr);
203 #endif
204 		} else if ((sig = writeback(fp, fromtrap))) {
205 			beenhere = 1;
206 			oticks = p->p_sticks;
207 			trapsignal(p, sig, faultaddr);
208 			goto again;
209 		}
210 	}
211 #endif
212 	curcpu()->ci_schedstate.spc_curpriority = p->p_priority;
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 proc *, struct frame *, u_quad_t);
220 
221 void
222 machine_userret(p, f, t)
223 	struct proc *p;
224 	struct frame *f;
225 	u_quad_t t;
226 {
227 
228 	userret(p, f, t, 0, 0);
229 }
230 
231 /*
232  * Trap is called from locore to handle most types of processor traps,
233  * including events such as simulated software interrupts/AST's.
234  * System calls are broken out for efficiency.
235  */
236 /*ARGSUSED*/
237 void
238 trap(type, code, v, frame)
239 	int type;
240 	unsigned code;
241 	unsigned v;
242 	struct frame frame;
243 {
244 	extern char fubail[], subail[];
245 	struct proc *p;
246 	int i, s;
247 	u_int ucode;
248 	u_quad_t sticks = 0 /* XXX initializer works around compiler bug */;
249 
250 	uvmexp.traps++;
251 	p = curproc;
252 	ucode = 0;
253 
254 	/* I have verified that this DOES happen! -gwr */
255 	if (p == NULL)
256 		p = &proc0;
257 #ifdef DIAGNOSTIC
258 	if (p->p_addr == NULL)
259 		panic("trap: no pcb");
260 #endif
261 
262 	if (USERMODE(frame.f_sr)) {
263 		type |= T_USER;
264 		sticks = p->p_sticks;
265 		p->p_md.md_regs = frame.f_regs;
266 	}
267 	switch (type) {
268 
269 	default:
270 	dopanic:
271 		printf("trap type %d, code = 0x%x, v = 0x%x\n", type, code, v);
272 		printf("%s program counter = 0x%x\n",
273 		    (type & T_USER) ? "user" : "kernel", frame.f_pc);
274 		/*
275 		 * Let the kernel debugger see the trap frame that
276 		 * caused us to panic.  This is a convenience so
277 		 * one can see registers at the point of failure.
278 		 */
279 		s = splhigh();
280 #ifdef KGDB
281 		/* If connected, step or cont returns 1 */
282 		if (kgdb_trap(type, &frame))
283 			goto kgdb_cont;
284 #endif
285 #ifdef DDB
286 		(void)kdb_trap(type, (db_regs_t *)&frame);
287 #endif
288 #ifdef KGDB
289 	kgdb_cont:
290 #endif
291 		splx(s);
292 		if (panicstr) {
293 			printf("trap during panic!\n");
294 #ifdef DEBUG
295 			/* XXX should be a machine-dependent hook */
296 			printf("(press a key)\n"); (void)cngetc();
297 #endif
298 		}
299 		regdump((struct trapframe *)&frame, 128);
300 		type &= ~T_USER;
301 		if ((u_int)type < trap_types)
302 			panic(trap_type[type]);
303 		panic("trap");
304 
305 	case T_BUSERR:		/* kernel bus error */
306 		if (p->p_addr->u_pcb.pcb_onfault == 0)
307 			goto dopanic;
308 		/* FALLTHROUGH */
309 
310 	copyfault:
311 		/*
312 		 * If we have arranged to catch this fault in any of the
313 		 * copy to/from user space routines, set PC to return to
314 		 * indicated location and set flag informing buserror code
315 		 * that it may need to clean up stack frame.
316 		 */
317 		frame.f_stackadj = exframesize[frame.f_format];
318 		frame.f_format = frame.f_vector = 0;
319 		frame.f_pc = (int) p->p_addr->u_pcb.pcb_onfault;
320 		return;
321 
322 	case T_BUSERR|T_USER:	/* bus error */
323 	case T_ADDRERR|T_USER:	/* address error */
324 		ucode = v;
325 		i = SIGBUS;
326 		break;
327 
328 	case T_COPERR:		/* kernel coprocessor violation */
329 	case T_FMTERR|T_USER:	/* do all RTE errors come in as T_USER? */
330 	case T_FMTERR:		/* ...just in case... */
331 	/*
332 	 * The user has most likely trashed the RTE or FP state info
333 	 * in the stack frame of a signal handler.
334 	 */
335 		printf("pid %d: kernel %s exception\n", p->p_pid,
336 		       type==T_COPERR ? "coprocessor" : "format");
337 		type |= T_USER;
338 		SIGACTION(p, SIGILL).sa_handler = SIG_DFL;
339 		sigdelset(&p->p_sigctx.ps_sigignore, SIGILL);
340 		sigdelset(&p->p_sigctx.ps_sigcatch, SIGILL);
341 		sigdelset(&p->p_sigctx.ps_sigmask, SIGILL);
342 		i = SIGILL;
343 		ucode = frame.f_format;	/* XXX was ILL_RESAD_FAULT */
344 		break;
345 
346 	case T_COPERR|T_USER:	/* user coprocessor violation */
347 	/* What is a proper response here? */
348 		ucode = 0;
349 		i = SIGFPE;
350 		break;
351 
352 	case T_FPERR|T_USER:	/* 68881 exceptions */
353 	/*
354 	 * We pass along the 68881 status register which locore stashed
355 	 * in code for us.  Note that there is a possibility that the
356 	 * bit pattern of this register will conflict with one of the
357 	 * FPE_* codes defined in signal.h.  Fortunately for us, the
358 	 * only such codes we use are all in the range 1-7 and the low
359 	 * 3 bits of the status register are defined as 0 so there is
360 	 * no clash.
361 	 */
362 		ucode = code;
363 		i = SIGFPE;
364 		break;
365 
366 #ifdef M68040
367 	case T_FPEMULI|T_USER:	/* unimplemented FP instuction */
368 	case T_FPEMULD|T_USER:	/* unimplemented FP data type */
369 		/* XXX need to FSAVE */
370 		printf("pid %d(%s): unimplemented FP %s at %x (EA %x)\n",
371 		       p->p_pid, p->p_comm,
372 		       frame.f_format == 2 ? "instruction" : "data type",
373 		       frame.f_pc, frame.f_fmt2.f_iaddr);
374 		/* XXX need to FRESTORE */
375 		i = SIGFPE;
376 		break;
377 #endif
378 
379 	case T_ILLINST|T_USER:	/* illegal instruction fault */
380 #ifdef COMPAT_HPUX
381 		if (p->p_emul == &emul_hpux) {
382 			ucode = HPUX_ILL_ILLINST_TRAP;
383 			i = SIGILL;
384 			break;
385 		}
386 		/* fall through */
387 #endif
388 	case T_PRIVINST|T_USER:	/* privileged instruction fault */
389 #ifdef COMPAT_HPUX
390 		if (p->p_emul == &emul_hpux)
391 			ucode = HPUX_ILL_PRIV_TRAP;
392 		else
393 #endif
394 		ucode = frame.f_format;	/* XXX was ILL_PRIVIN_FAULT */
395 		i = SIGILL;
396 		break;
397 
398 	case T_ZERODIV|T_USER:	/* Divide by zero */
399 		ucode = frame.f_format;	/* XXX was FPE_INTDIV_TRAP */
400 		i = SIGFPE;
401 		break;
402 
403 	case T_CHKINST|T_USER:	/* CHK instruction trap */
404 		ucode = frame.f_format;	/* XXX was FPE_SUBRNG_TRAP */
405 		i = SIGFPE;
406 		break;
407 
408 	case T_TRAPVINST|T_USER:	/* TRAPV instruction trap */
409 		ucode = frame.f_format;	/* XXX was FPE_INTOVF_TRAP */
410 		i = SIGFPE;
411 		break;
412 
413 	/*
414 	 * XXX: Trace traps are a nightmare.
415 	 *
416 	 *	HP-UX uses trap #1 for breakpoints,
417 	 *	NetBSD/m68k uses trap #2,
418 	 *	SUN 3.x uses trap #15,
419 	 *	DDB and KGDB uses trap #15 (for kernel breakpoints;
420 	 *	handled elsewhere).
421 	 *
422 	 * NetBSD and HP-UX traps both get mapped by locore.s into T_TRACE.
423 	 * SUN 3.x traps get passed through as T_TRAP15 and are not really
424 	 * supported yet.
425 	 *
426 	 * XXX: We should never get kernel-mode T_TRAP15
427 	 * XXX: because locore.s now gives them special treatment.
428 	 */
429 	case T_TRAP15:		/* kernel breakpoint */
430 #ifdef DEBUG
431 		printf("unexpected kernel trace trap, type = %d\n", type);
432 		printf("program counter = 0x%x\n", frame.f_pc);
433 #endif
434 		frame.f_sr &= ~PSL_T;
435 		return;
436 
437 	case T_TRACE|T_USER:	/* user trace trap */
438 		/* FALLTHROUGH */
439 	case T_TRACE:
440 	case T_TRAP15|T_USER:
441 		frame.f_sr &= ~PSL_T;
442 		i = SIGTRAP;
443 		break;
444 
445 	case T_ASTFLT:		/* system async trap, cannot happen */
446 		goto dopanic;
447 
448 	case T_ASTFLT|T_USER:	/* user async trap */
449 		astpending = 0;
450 		/*
451 		 * We check for software interrupts first.  This is because
452 		 * they are at a higher level than ASTs, and on a VAX would
453 		 * interrupt the AST.  We assume that if we are processing
454 		 * an AST that we must be at IPL0 so we don't bother to
455 		 * check.  Note that we ensure that we are at least at SIR
456 		 * IPL while processing the SIR.
457 		 */
458 		spl1();
459 		/* fall into... */
460 
461 	case T_SSIR:		/* software interrupt */
462 	case T_SSIR|T_USER:
463 		if (ssir & SIR_NET) {
464 			void netintr __P((void));
465 			siroff(SIR_NET);
466 			uvmexp.softs++;
467 			netintr();
468 		}
469 		if (ssir & SIR_CLOCK) {
470 			siroff(SIR_CLOCK);
471 			uvmexp.softs++;
472 			softclock(NULL);
473 		}
474 		/*
475 		 * If this was not an AST trap, we are all done.
476 		 */
477 		if (type != (T_ASTFLT|T_USER)) {
478 			uvmexp.traps--;
479 			return;
480 		}
481 		spl0();
482 		if (p->p_flag & P_OWEUPC) {
483 			p->p_flag &= ~P_OWEUPC;
484 			ADDUPROF(p);
485 		}
486 		goto out;
487 
488 	case T_MMUFLT:		/* kernel mode page fault */
489 		/*
490 		 * If we were doing profiling ticks or other user mode
491 		 * stuff from interrupt code, Just Say No.
492 		 */
493 		if (p->p_addr->u_pcb.pcb_onfault == fubail ||
494 		    p->p_addr->u_pcb.pcb_onfault == subail)
495 			goto copyfault;
496 		/* fall into ... */
497 
498 	case T_MMUFLT|T_USER:	/* page fault */
499 	    {
500 		vaddr_t va;
501 		struct vmspace *vm = p->p_vmspace;
502 		struct vm_map *map;
503 		int rv;
504 		vm_prot_t ftype;
505 		extern struct vm_map *kernel_map;
506 
507 #ifdef DEBUG
508 		if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid))
509 		printf("trap: T_MMUFLT pid=%d, code=%x, v=%x, pc=%x, sr=%x\n",
510 		       p->p_pid, code, v, frame.f_pc, frame.f_sr);
511 #endif
512 		/*
513 		 * It is only a kernel address space fault iff:
514 		 * 	1. (type & T_USER) == 0  and
515 		 * 	2. pcb_onfault not set or
516 		 *	3. pcb_onfault set but supervisor space data fault
517 		 * The last can occur during an exec() copyin where the
518 		 * argument space is lazy-allocated.
519 		 */
520 		if ((type & T_USER) == 0 &&
521 		    ((p->p_addr->u_pcb.pcb_onfault == 0) || KDFAULT(code)))
522 			map = kernel_map;
523 		else
524 			map = vm ? &vm->vm_map : kernel_map;
525 
526 		if (WRFAULT(code))
527 			ftype = VM_PROT_WRITE;
528 		else
529 			ftype = VM_PROT_READ;
530 
531 		va = trunc_page((vaddr_t)v);
532 
533 		if (map == kernel_map && va == 0) {
534 			printf("trap: bad kernel %s access at 0x%x\n",
535 			    (ftype & VM_PROT_WRITE) ? "read/write" :
536 			    "read", v);
537 			goto dopanic;
538 		}
539 
540 		rv = uvm_fault(map, va, 0, ftype);
541 #ifdef DEBUG
542 		if (rv && MDB_ISPID(p->p_pid))
543 			printf("uvm_fault(%p, 0x%lx, 0, 0x%x) -> 0x%x\n",
544 			    map, va, ftype, rv);
545 #endif
546 		/*
547 		 * If this was a stack access we keep track of the maximum
548 		 * accessed stack size.  Also, if vm_fault gets a protection
549 		 * failure it is due to accessing the stack region outside
550 		 * the current limit and we need to reflect that as an access
551 		 * error.
552 		 */
553 		if ((vm != NULL && (caddr_t)va >= vm->vm_maxsaddr)
554 		    && map != kernel_map) {
555 			if (rv == 0) {
556 				unsigned nss;
557 
558 				nss = btoc(USRSTACK-(unsigned)va);
559 				if (nss > vm->vm_ssize)
560 					vm->vm_ssize = nss;
561 			} else if (rv == EACCES)
562 				rv = EFAULT;
563 		}
564 		if (rv == 0) {
565 			if (type == T_MMUFLT) {
566 #ifdef M68040
567 				if (cputype == CPU_68040)
568 					(void) writeback(&frame, 1);
569 #endif
570 				return;
571 			}
572 			goto out;
573 		}
574 		if (type == T_MMUFLT) {
575 			if (p->p_addr->u_pcb.pcb_onfault)
576 				goto copyfault;
577 			printf("uvm_fault(%p, 0x%lx, 0, 0x%x) -> 0x%x\n",
578 			    map, va, ftype, rv);
579 			printf("  type %x, code [mmu,,ssw]: %x\n",
580 			       type, code);
581 			goto dopanic;
582 		}
583 		ucode = v;
584 		if (rv == ENOMEM) {
585 			printf("UVM: pid %d (%s), uid %d killed: out of swap\n",
586 			    p->p_pid, p->p_comm,
587 			    p->p_cred && p->p_ucred ?
588 			    p->p_ucred->cr_uid : -1);
589 			i = SIGKILL;
590 		} else {
591 			i = SIGSEGV;
592 		}
593 		break;
594 	    }
595 	}
596 	trapsignal(p, i, ucode);
597 	if ((type & T_USER) == 0)
598 		return;
599 out:
600 	userret(p, &frame, sticks, v, 1);
601 }
602 
603 #ifdef M68040
604 #include <m68k/cacheops_40.h>
605 #ifdef DEBUG
606 struct writebackstats {
607 	int calls;
608 	int cpushes;
609 	int move16s;
610 	int wb1s, wb2s, wb3s;
611 	int wbsize[4];
612 } wbstats;
613 
614 char *f7sz[] = { "longword", "byte", "word", "line" };
615 char *f7tt[] = { "normal", "MOVE16", "AFC", "ACK" };
616 char *f7tm[] = { "d-push", "u-data", "u-code", "M-data",
617 		 "M-code", "k-data", "k-code", "RES" };
618 char wberrstr[] =
619     "WARNING: pid %d(%s) writeback [%s] failed, pc=%x fa=%x wba=%x wbd=%x\n";
620 #endif
621 
622 int
623 writeback(fp, docachepush)
624 	struct frame *fp;
625 	int docachepush;
626 {
627 	struct fmt7 *f = &fp->f_fmt7;
628 	struct proc *p = curproc;
629 	int err = 0;
630 	u_int fa;
631 	caddr_t oonfault = p->p_addr->u_pcb.pcb_onfault;
632 	paddr_t pa;
633 
634 #ifdef DEBUG
635 	if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid)) {
636 		printf(" pid=%d, fa=%x,", p->p_pid, f->f_fa);
637 		dumpssw(f->f_ssw);
638 	}
639 	wbstats.calls++;
640 #endif
641 	/*
642 	 * Deal with special cases first.
643 	 */
644 	if ((f->f_ssw & SSW4_TMMASK) == SSW4_TMDCP) {
645 		/*
646 		 * Dcache push fault.
647 		 * Line-align the address and write out the push data to
648 		 * the indicated physical address.
649 		 */
650 #ifdef DEBUG
651 		if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid)) {
652 			printf(" pushing %s to PA %x, data %x",
653 			       f7sz[(f->f_ssw & SSW4_SZMASK) >> 5],
654 			       f->f_fa, f->f_pd0);
655 			if ((f->f_ssw & SSW4_SZMASK) == SSW4_SZLN)
656 				printf("/%x/%x/%x",
657 				       f->f_pd1, f->f_pd2, f->f_pd3);
658 			printf("\n");
659 		}
660 		if (f->f_wb1s & SSW4_WBSV)
661 			panic("writeback: cache push with WB1S valid");
662 		wbstats.cpushes++;
663 #endif
664 		/*
665 		 * XXX there are security problems if we attempt to do a
666 		 * cache push after a signal handler has been called.
667 		 */
668 		if (docachepush) {
669 			pmap_enter(pmap_kernel(), (vaddr_t)vmmap,
670 			    trunc_page(f->f_fa), VM_PROT_WRITE,
671 			    VM_PROT_WRITE|PMAP_WIRED);
672 			pmap_update(pmap_kernel());
673 			fa = (u_int)&vmmap[(f->f_fa & PGOFSET) & ~0xF];
674 			bcopy((caddr_t)&f->f_pd0, (caddr_t)fa, 16);
675 			(void) pmap_extract(pmap_kernel(), (vaddr_t)fa, &pa);
676 			DCFL_40(pa);
677 			pmap_remove(pmap_kernel(), (vaddr_t)vmmap,
678 				    (vaddr_t)&vmmap[NBPG]);
679 			pmap_update(pmap_kernel());
680 		} else
681 			printf("WARNING: pid %d(%s) uid %d: CPUSH not done\n",
682 			       p->p_pid, p->p_comm, p->p_ucred->cr_uid);
683 	} else if ((f->f_ssw & (SSW4_RW|SSW4_TTMASK)) == SSW4_TTM16) {
684 		/*
685 		 * MOVE16 fault.
686 		 * Line-align the address and write out the push data to
687 		 * the indicated virtual address.
688 		 */
689 #ifdef DEBUG
690 		if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid))
691 			printf(" MOVE16 to VA %x(%x), data %x/%x/%x/%x\n",
692 			       f->f_fa, f->f_fa & ~0xF, f->f_pd0, f->f_pd1,
693 			       f->f_pd2, f->f_pd3);
694 		if (f->f_wb1s & SSW4_WBSV)
695 			panic("writeback: MOVE16 with WB1S valid");
696 		wbstats.move16s++;
697 #endif
698 		if (KDFAULT(f->f_wb1s))
699 			bcopy((caddr_t)&f->f_pd0, (caddr_t)(f->f_fa & ~0xF), 16);
700 		else
701 			err = suline((caddr_t)(f->f_fa & ~0xF), (caddr_t)&f->f_pd0);
702 		if (err) {
703 			fa = f->f_fa & ~0xF;
704 #ifdef DEBUG
705 			if (mmudebug & MDB_WBFAILED)
706 				printf(wberrstr, p->p_pid, p->p_comm,
707 				       "MOVE16", fp->f_pc, f->f_fa,
708 				       f->f_fa & ~0xF, f->f_pd0);
709 #endif
710 		}
711 	} else if (f->f_wb1s & SSW4_WBSV) {
712 		/*
713 		 * Writeback #1.
714 		 * Position the "memory-aligned" data and write it out.
715 		 */
716 		u_int wb1d = f->f_wb1d;
717 		int off;
718 
719 #ifdef DEBUG
720 		if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid))
721 			dumpwb(1, f->f_wb1s, f->f_wb1a, f->f_wb1d);
722 		wbstats.wb1s++;
723 		wbstats.wbsize[(f->f_wb2s&SSW4_SZMASK)>>5]++;
724 #endif
725 		off = (f->f_wb1a & 3) * 8;
726 		switch (f->f_wb1s & SSW4_SZMASK) {
727 		case SSW4_SZLW:
728 			if (off)
729 				wb1d = (wb1d >> (32 - off)) | (wb1d << off);
730 			if (KDFAULT(f->f_wb1s))
731 				*(long *)f->f_wb1a = wb1d;
732 			else
733 				err = suword((caddr_t)f->f_wb1a, wb1d);
734 			break;
735 		case SSW4_SZB:
736 			off = 24 - off;
737 			if (off)
738 				wb1d >>= off;
739 			if (KDFAULT(f->f_wb1s))
740 				*(char *)f->f_wb1a = wb1d;
741 			else
742 				err = subyte((caddr_t)f->f_wb1a, wb1d);
743 			break;
744 		case SSW4_SZW:
745 			off = (off + 16) % 32;
746 			if (off)
747 				wb1d = (wb1d >> (32 - off)) | (wb1d << off);
748 			if (KDFAULT(f->f_wb1s))
749 				*(short *)f->f_wb1a = wb1d;
750 			else
751 				err = susword((caddr_t)f->f_wb1a, wb1d);
752 			break;
753 		}
754 		if (err) {
755 			fa = f->f_wb1a;
756 #ifdef DEBUG
757 			if (mmudebug & MDB_WBFAILED)
758 				printf(wberrstr, p->p_pid, p->p_comm,
759 				       "#1", fp->f_pc, f->f_fa,
760 				       f->f_wb1a, f->f_wb1d);
761 #endif
762 		}
763 	}
764 	/*
765 	 * Deal with the "normal" writebacks.
766 	 *
767 	 * XXX writeback2 is known to reflect a LINE size writeback after
768 	 * a MOVE16 was already dealt with above.  Ignore it.
769 	 */
770 	if (err == 0 && (f->f_wb2s & SSW4_WBSV) &&
771 	    (f->f_wb2s & SSW4_SZMASK) != SSW4_SZLN) {
772 #ifdef DEBUG
773 		if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid))
774 			dumpwb(2, f->f_wb2s, f->f_wb2a, f->f_wb2d);
775 		wbstats.wb2s++;
776 		wbstats.wbsize[(f->f_wb2s&SSW4_SZMASK)>>5]++;
777 #endif
778 		switch (f->f_wb2s & SSW4_SZMASK) {
779 		case SSW4_SZLW:
780 			if (KDFAULT(f->f_wb2s))
781 				*(long *)f->f_wb2a = f->f_wb2d;
782 			else
783 				err = suword((caddr_t)f->f_wb2a, f->f_wb2d);
784 			break;
785 		case SSW4_SZB:
786 			if (KDFAULT(f->f_wb2s))
787 				*(char *)f->f_wb2a = f->f_wb2d;
788 			else
789 				err = subyte((caddr_t)f->f_wb2a, f->f_wb2d);
790 			break;
791 		case SSW4_SZW:
792 			if (KDFAULT(f->f_wb2s))
793 				*(short *)f->f_wb2a = f->f_wb2d;
794 			else
795 				err = susword((caddr_t)f->f_wb2a, f->f_wb2d);
796 			break;
797 		}
798 		if (err) {
799 			fa = f->f_wb2a;
800 #ifdef DEBUG
801 			if (mmudebug & MDB_WBFAILED) {
802 				printf(wberrstr, p->p_pid, p->p_comm,
803 				       "#2", fp->f_pc, f->f_fa,
804 				       f->f_wb2a, f->f_wb2d);
805 				dumpssw(f->f_ssw);
806 				dumpwb(2, f->f_wb2s, f->f_wb2a, f->f_wb2d);
807 			}
808 #endif
809 		}
810 	}
811 	if (err == 0 && (f->f_wb3s & SSW4_WBSV)) {
812 #ifdef DEBUG
813 		if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid))
814 			dumpwb(3, f->f_wb3s, f->f_wb3a, f->f_wb3d);
815 		wbstats.wb3s++;
816 		wbstats.wbsize[(f->f_wb3s&SSW4_SZMASK)>>5]++;
817 #endif
818 		switch (f->f_wb3s & SSW4_SZMASK) {
819 		case SSW4_SZLW:
820 			if (KDFAULT(f->f_wb3s))
821 				*(long *)f->f_wb3a = f->f_wb3d;
822 			else
823 				err = suword((caddr_t)f->f_wb3a, f->f_wb3d);
824 			break;
825 		case SSW4_SZB:
826 			if (KDFAULT(f->f_wb3s))
827 				*(char *)f->f_wb3a = f->f_wb3d;
828 			else
829 				err = subyte((caddr_t)f->f_wb3a, f->f_wb3d);
830 			break;
831 		case SSW4_SZW:
832 			if (KDFAULT(f->f_wb3s))
833 				*(short *)f->f_wb3a = f->f_wb3d;
834 			else
835 				err = susword((caddr_t)f->f_wb3a, f->f_wb3d);
836 			break;
837 #ifdef DEBUG
838 		case SSW4_SZLN:
839 			panic("writeback: wb3s indicates LINE write");
840 #endif
841 		}
842 		if (err) {
843 			fa = f->f_wb3a;
844 #ifdef DEBUG
845 			if (mmudebug & MDB_WBFAILED)
846 				printf(wberrstr, p->p_pid, p->p_comm,
847 				       "#3", fp->f_pc, f->f_fa,
848 				       f->f_wb3a, f->f_wb3d);
849 #endif
850 		}
851 	}
852 	p->p_addr->u_pcb.pcb_onfault = oonfault;
853 	if (err)
854 		err = SIGSEGV;
855 	return (err);
856 }
857 
858 #ifdef DEBUG
859 static void
860 dumpssw(ssw)
861 	u_short ssw;
862 {
863 	printf(" SSW: %x: ", ssw);
864 	if (ssw & SSW4_CP)
865 		printf("CP,");
866 	if (ssw & SSW4_CU)
867 		printf("CU,");
868 	if (ssw & SSW4_CT)
869 		printf("CT,");
870 	if (ssw & SSW4_CM)
871 		printf("CM,");
872 	if (ssw & SSW4_MA)
873 		printf("MA,");
874 	if (ssw & SSW4_ATC)
875 		printf("ATC,");
876 	if (ssw & SSW4_LK)
877 		printf("LK,");
878 	if (ssw & SSW4_RW)
879 		printf("RW,");
880 	printf(" SZ=%s, TT=%s, TM=%s\n",
881 	       f7sz[(ssw & SSW4_SZMASK) >> 5],
882 	       f7tt[(ssw & SSW4_TTMASK) >> 3],
883 	       f7tm[ssw & SSW4_TMMASK]);
884 }
885 
886 static void
887 dumpwb(num, s, a, d)
888 	int num;
889 	u_short s;
890 	u_int a, d;
891 {
892 	struct proc *p = curproc;
893 	paddr_t pa;
894 
895 	printf(" writeback #%d: VA %x, data %x, SZ=%s, TT=%s, TM=%s\n",
896 	       num, a, d, f7sz[(s & SSW4_SZMASK) >> 5],
897 	       f7tt[(s & SSW4_TTMASK) >> 3], f7tm[s & SSW4_TMMASK]);
898 	printf("               PA ");
899 	if (pmap_extract(p->p_vmspace->vm_map.pmap, (vaddr_t)a, &pa) == FALSE)
900 		printf("<invalid address>");
901 	else
902 		printf("%lx, current value %lx", pa, fuword((caddr_t)a));
903 	printf("\n");
904 }
905 #endif
906 #endif
907