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