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