/*	$NetBSD: trap.c,v 1.143 2024/05/04 13:45:10 mlelstv Exp $	*/

/*
 * Copyright (c) 1988 University of Utah.
 * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
 * All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by
 * the Systems Programming Group of the University of Utah Computer
 * Science Department.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * from: Utah $Hdr: trap.c 1.32 91/04/06$
 *
 *	@(#)trap.c	7.15 (Berkeley) 8/2/91
 */

#include "opt_ddb.h"
#include "opt_execfmt.h"
#include "opt_compat_sunos.h"
#include "opt_fpu_emulate.h"
#include "opt_m68k_arch.h"

#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.143 2024/05/04 13:45:10 mlelstv Exp $");

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/acct.h>
#include <sys/kernel.h>
#include <sys/signalvar.h>
#include <sys/resourcevar.h>
#include <sys/syslog.h>
#include <sys/syscall.h>
#include <sys/userret.h>
#include <sys/kauth.h>

#include <uvm/uvm_extern.h>

#include <machine/psl.h>
#include <machine/trap.h>
#include <machine/cpu.h>
#include <machine/fcode.h>
#include <machine/pcb.h>
#include <machine/pte.h>

#include <m68k/fpe/fpu_emulate.h>
#include <m68k/cacheops.h>

#ifdef COMPAT_SUNOS
#include <compat/sunos/sunos_syscall.h>
extern struct emul emul_sunos;
#endif

/*
 * XXX Hack until I can figure out what to do about this code's removal
 * from m68k/include/frame.h
 */

/* 68040 fault frame */
#define SSW_CP		0x8000		/* Continuation - Floating-Point Post*/
#define SSW_CU		0x4000		/* Continuation - Unimpl. FP */
#define SSW_CT		0x2000		/* Continuation - Trace */
#define SSW_CM		0x1000		/* Continuation - MOVEM */
#define SSW_MA		0x0800		/* Misaligned access */
#define SSW_ATC		0x0400		/* ATC fault */
#define SSW_LK		0x0200		/* Locked transfer */
#define SSW_RW040	0x0100		/* Read/Write */
#define SSW_SZMASK	0x0060		/* Transfer size */
#define SSW_TTMASK	0x0018		/* Transfer type */
#define SSW_TMMASK	0x0007		/* Transfer modifier */

#define WBS_TMMASK	0x0007
#define WBS_TTMASK	0x0018
#define WBS_SZMASK	0x0060
#define WBS_VALID	0x0080

#define WBS_SIZE_BYTE	0x0020
#define WBS_SIZE_WORD	0x0040
#define WBS_SIZE_LONG	0x0000
#define WBS_SIZE_LINE	0x0060

#define WBS_TT_NORMAL	0x0000
#define WBS_TT_MOVE16	0x0008
#define WBS_TT_ALTFC	0x0010
#define WBS_TT_ACK	0x0018

#define WBS_TM_PUSH	0x0000
#define WBS_TM_UDATA	0x0001
#define WBS_TM_UCODE	0x0002
#define WBS_TM_MMUTD	0x0003
#define WBS_TM_MMUTC	0x0004
#define WBS_TM_SDATA	0x0005
#define WBS_TM_SCODE	0x0006
#define WBS_TM_RESV	0x0007

#define	MMUSR_PA_MASK	0xfffff000
#define MMUSR_B		0x00000800
#define MMUSR_G		0x00000400
#define MMUSR_U1	0x00000200
#define MMUSR_U0	0x00000100
#define MMUSR_S		0x00000080
#define MMUSR_CM	0x00000060
#define MMUSR_M		0x00000010
#define MMUSR_0		0x00000008
#define MMUSR_W		0x00000004
#define MMUSR_T		0x00000002
#define MMUSR_R		0x00000001

#define FSLW_STRING	"\020\1SEE\3BPE\4TTR\5WE\6RE\7TWE\010WP\011SP" \
			"\012PF\013IL\014PTB\015PTA\016SBE\017PBE"
/*
 * XXX End hack
 */

volatile int astpending;

const char *trap_type[] = {
	"Bus error",
	"Address error",
	"Illegal instruction",
	"Zero divide",
	"CHK instruction",
	"TRAPV instruction",
	"Privilege violation",
	"Trace trap",
	"MMU fault",
	"SSIR trap",
	"Format error",
	"68881 exception",
	"Coprocessor violation",
	"Async system trap"
};
int	trap_types = sizeof trap_type / sizeof trap_type[0];

/*
 * Size of various exception stack frames (minus the standard 8 bytes)
 */
short	exframesize[] = {
	FMT0SIZE,	/* type 0 - normal (68020/030/040/060) */
	FMT1SIZE,	/* type 1 - throwaway (68020/030/040) */
	FMT2SIZE,	/* type 2 - normal 6-word (68020/030/040/060) */
	FMT3SIZE,	/* type 3 - FP post-instruction (68040/060) */
	FMT4SIZE,	/* type 4 - access error/fp disabled (68060) */
	-1, -1,		/* type 5-6 - undefined */
	FMT7SIZE,	/* type 7 - access error (68040) */
	58,		/* type 8 - bus fault (68010) */
	FMT9SIZE,	/* type 9 - coprocessor mid-instruction (68020/030) */
	FMTASIZE,	/* type A - short bus fault (68020/030) */
	FMTBSIZE,	/* type B - long bus fault (68020/030) */
	-1, -1, -1, -1	/* type C-F - undefined */
};

#ifdef DEBUG
int mmudebug = 0;
#endif

extern struct pcb *curpcb;
int _write_back(u_int, u_int, u_int, u_int, struct vm_map *);
static void userret(struct lwp *, int, u_quad_t);
void panictrap(int, u_int, u_int, struct frame *);
void trapcpfault(struct lwp *, struct frame *, int);
void trapmmufault(int, u_int, u_int, struct frame *, struct lwp *,
			u_quad_t);
void trap(struct frame *, int, u_int, u_int);
#ifdef DDB
#include <m68k/db_machdep.h>
int kdb_trap(int, db_regs_t *);
#endif
void _wb_fault(void);


static void
userret(struct lwp *l, int pc, u_quad_t oticks)
{
	struct proc *p = l->l_proc;

	/* Invoke MI userret code */
	mi_userret(l);

	/*
	 * If profiling, charge recent system time.
	 */
	if (p->p_stflag & PST_PROFIL) {
		extern int psratio;

		addupc_task(l, pc, (int)(p->p_sticks - oticks) * psratio);
	}
}

/*
 * Used by the common m68k syscall() and child_return() functions.
 * XXX: Temporary until all m68k ports share common trap()/userret() code.
 */
void machine_userret(struct lwp *, struct frame *, u_quad_t);

void
machine_userret(struct lwp *l, struct frame *f, u_quad_t t)
{

	userret(l, f->f_pc, t);
}

void
panictrap(int type, u_int code, u_int v, struct frame *fp)
{
	static int panicking = 0;
	if (panicking++ == 0) {
		printf("trap type %d, code = %x, v = %x\n", type, code, v);
		regdump((struct trapframe *)fp, 128);
	}
	type &= ~T_USER;
#ifdef DEBUG
	DCIS(); 		/* XXX? push cache */
#endif
	if ((u_int)type < trap_types)
		panic(trap_type[type]);
	panic("trap");
	/*NOTREACHED*/
}

/*
 * return to fault handler
 */
void
trapcpfault(struct lwp *l, struct frame *fp, int error)
{
	struct pcb *pcb = lwp_getpcb(l);

	/*
	 * We have arranged to catch this fault in one of the
	 * copy to/from user space routines, set PC to return to
	 * indicated location and set flag informing buserror code
	 * that it may need to clean up stack frame.
	 */
	fp->f_stackadj = exframesize[fp->f_format];
	fp->f_format = fp->f_vector = 0;
	fp->f_pc = (int)pcb->pcb_onfault;
	fp->f_regs[D0] = error;
}

int donomore = 0;

void
trapmmufault(int type, u_int code, u_int v, struct frame *fp, struct lwp *l, u_quad_t sticks)
{
#if defined(DEBUG) && defined(M68060)
	static u_int oldcode=0, oldv=0;
	static struct proc *oldp=0;
#endif
	extern struct vm_map *kernel_map;
	struct proc *p = l->l_proc;
	struct vmspace *vm = NULL;
	struct vm_map *map;
	struct pcb *pcb;
	void *onfault;
	vm_prot_t ftype;
	vaddr_t va;
	ksiginfo_t ksi;
	int rv;

	pcb = lwp_getpcb(l);
	onfault = pcb->pcb_onfault;

	KSI_INIT_TRAP(&ksi);
	ksi.ksi_trap = type & ~T_USER;

	/*
	 * It is only a kernel address space fault iff:
	 * 	1. (type & T_USER) == 0  and
	 * 	2. pcb_onfault not set or
	 *	3. pcb_onfault set but supervisor space data fault
	 * The last can occur during an exec() copyin where the
	 * argument space is lazy-allocated.
	 */
#ifdef DEBUG
	/*
	 * Print out some data about the fault
	 */
#ifdef DEBUG_PAGE0
	if (v < PAGE_SIZE)				/* XXX PAGE0 */
		mmudebug |= 0x100;			/* XXX PAGE0 */
#endif
	if (mmudebug && mmutype == MMU_68040) {
#ifdef M68060
		if (machineid & AMIGA_68060) {
			if (--donomore == 0 || mmudebug & 1) {
				char bits[64];
				snprintb(bits, sizeof(bits), FSLW_STRING, code);
				printf ("68060 access error: pc %x, code %s,"
				     " ea %x\n", fp->f_pc, bits, v);
			}
			if (p == oldp && v == oldv && code == oldcode)
				panic("Identical fault backtoback!");
			if (donomore == 0)
				panic("Tired of faulting.");
			oldp = p;
			oldv = v;
			oldcode = code;
		} else
#endif
		printf("68040 access error: pc %x, code %x,"
		    " ea %x, fa %x\n", fp->f_pc, code, fp->f_fmt7.f_ea, v);
		if (curpcb)
			printf(" curpcb %p\n", curpcb);


#ifdef DDB						/* XXX PAGE0 */
		if (v < PAGE_SIZE)			/* XXX PAGE0 */
			Debugger();			/* XXX PAGE0 */
#endif							/* XXX PAGE0 */
	}
#ifdef DEBUG_PAGE0
	mmudebug &= ~0x100;				/* XXX PAGE0 */
#endif
#endif

	if (p)
		vm = p->p_vmspace;

	if (type == T_MMUFLT && (l == &lwp0 || onfault == 0 || (
#ifdef M68060
	     machineid & AMIGA_68060 ? code & FSLW_TM_SV :
#endif
	     mmutype == MMU_68040 ? (code & SSW_TMMASK) == FC_SUPERD :
	     (code & (SSW_DF|FC_SUPERD)) == (SSW_DF|FC_SUPERD))))
		map = kernel_map;
	else
		map = &vm->vm_map;

	if (
#ifdef M68060
	    machineid & AMIGA_68060 ? code & FSLW_RW_W :
#endif
	    mmutype == MMU_68040 ? (code & (SSW_LK|SSW_RW040)) != SSW_RW040 :
	    ((code & SSW_DF) != 0 &&
	    ((code & SSW_RW) == 0 || (code & SSW_RM) != 0)))
		ftype = VM_PROT_WRITE;
	else
		ftype = VM_PROT_READ;
	va = trunc_page((vaddr_t)v);
#ifdef DEBUG
	if (map == kernel_map && va == 0 && onfault == 0) {
		printf("trap: bad kernel access at %x pc %x\n", v, fp->f_pc);
		panictrap(type, code, v, fp);
	}

	if (mmudebug)
		printf("vm_fault(%p,%lx,%d)\n", map, va, ftype);
#endif

	pcb->pcb_onfault = NULL;
	rv = uvm_fault(map, va, ftype);
	pcb->pcb_onfault = onfault;

#ifdef DEBUG
	if (mmudebug)
		printf("vmfault %s %lx returned %d\n",
		    map == kernel_map ? "kernel" : "user", va, rv);
#endif

#ifdef M68060
	if ((machineid & AMIGA_68060) == 0 && mmutype == MMU_68040) {
#else
	if (mmutype == MMU_68040) {
#endif
		if (rv != 0) {
			goto nogo;
		}

		/*
		 * The 68040 doesn't re-run instructions that cause
		 * write page faults (unless due to a move16 isntruction).
		 * So once the page is repaired, we have to write the
		 * value of WB2D out to memory ourselves.  Because
		 * the writeback could possibly span two pages in
		 * memory, so we need to check both "ends" of the
		 * address to see if they are in the same page or not.
		 * If not, then we need to make sure the second page
		 * is valid, and bring it into memory if it's not.
		 * 
		 * This whole process needs to be repeated for WB3 as well.
		 * <sigh>
		 */

		/* Check WB1 */
		if (fp->f_fmt7.f_wb1s & WBS_VALID) {
			printf ("trap: wb1 was valid, not handled yet\n");
			panictrap(type, code, v, fp);
		}

		/*
		 * Check WB2
		 * skip if it's for a move16 instruction
		 */
		if(fp->f_fmt7.f_wb2s & WBS_VALID &&
		   ((fp->f_fmt7.f_wb2s & WBS_TTMASK)==WBS_TT_MOVE16) == 0) {
			if (_write_back(2, fp->f_fmt7.f_wb2s,
			    fp->f_fmt7.f_wb2d, fp->f_fmt7.f_wb2a, map) != 0)
				goto nogo;
			if ((fp->f_fmt7.f_wb2s & WBS_TMMASK)
			    != (code & SSW_TMMASK))
				panictrap(type, code, v, fp);
		}

		/* Check WB3 */
		if(fp->f_fmt7.f_wb3s & WBS_VALID) {
			struct vm_map *wb3_map;

			if ((fp->f_fmt7.f_wb3s & WBS_TMMASK) == WBS_TM_SDATA)
				wb3_map = kernel_map;
			else
				wb3_map = &vm->vm_map;
			if (_write_back(3, fp->f_fmt7.f_wb3s,
			    fp->f_fmt7.f_wb3d, fp->f_fmt7.f_wb3a, wb3_map) != 0)
				goto nogo;
		}
	}

	/*
	 * If this was a stack access we keep track of the maximum
	 * accessed stack size.  Also, if vm_fault gets a protection
	 * failure it is due to accessing the stack region outside
	 * the current limit and we need to reflect that as an access
	 * error.
	 */
	if (rv == 0) {
		if (map != kernel_map && (void *)va >= vm->vm_maxsaddr)
			uvm_grow(p, va); 

		if (type == T_MMUFLT)
			return;
		userret(l, fp->f_pc, sticks);
		return;
	}
nogo:
	if (type == T_MMUFLT) {
		if (onfault) {
			trapcpfault(l, fp, rv);
			return;
		}
		printf("uvm_fault(%p, 0x%lx, 0x%x) -> 0x%x\n",
		    map, va, ftype, rv);
		printf("  type %x, code [mmu,,ssw]: %x\n",
		       type, code);
		panictrap(type, code, v, fp);
	}
	ksi.ksi_addr = (void *)v;
	switch (rv) {
	case ENOMEM:
		printf("UVM: pid %d (%s), uid %d killed: out of swap\n",
		    p->p_pid, p->p_comm,
		    l->l_cred ? kauth_cred_geteuid(l->l_cred) : -1);
		ksi.ksi_signo = SIGKILL;
		break;
	case EINVAL:
		ksi.ksi_signo = SIGBUS;
		ksi.ksi_code = BUS_ADRERR;
		break;
	case EACCES:
		ksi.ksi_signo = SIGSEGV;
		ksi.ksi_code = SEGV_ACCERR;
		break;
	default:
		ksi.ksi_signo = SIGSEGV;
		ksi.ksi_code = SEGV_MAPERR;
		break;
	}
	trapsignal(l, &ksi);
	if ((type & T_USER) == 0)
		return;
	userret(l, fp->f_pc, sticks);
}
/*
 * Trap is called from locore to handle most types of processor traps,
 * including events such as simulated software interrupts/AST's.
 * System calls are broken out for efficiency.
 */
/*ARGSUSED*/
void
trap(struct frame *fp, int type, u_int code, u_int v)
{
	struct lwp *l;
	struct proc *p;
	struct pcb *pcb;
	ksiginfo_t ksi;
	u_quad_t sticks = 0;

	l = curlwp;
	p = l->l_proc;
	pcb = lwp_getpcb(l);

	curcpu()->ci_data.cpu_ntrap++;

	KSI_INIT_TRAP(&ksi);
	ksi.ksi_trap = type & ~T_USER;

	if (USERMODE(fp->f_sr)) {
		type |= T_USER;
		sticks = p->p_sticks;
		l->l_md.md_regs = fp->f_regs;
	}

#ifdef DDB
	if (type == T_TRACE || type == T_BREAKPOINT) {
		if (kdb_trap(type, (db_regs_t *)fp))
			return;
	}
#endif
#ifdef DEBUG
	if (mmudebug & 2)
	printf("%s: t %x c %x v %x adj %x sr %x pc %x fmt %x vc %x\n",
	    __func__, type, code, v, fp->f_stackadj, fp->f_sr,
	    fp->f_pc, fp->f_format, fp->f_vector);
#endif
	switch (type) {
	default:
		panictrap(type, code, v, fp);
	/*
	 * Kernel Bus error
	 */
	case T_BUSERR:
		if (!pcb->pcb_onfault)
			panictrap(type, code, v, fp);
		trapcpfault(l, fp, EFAULT);
		return;
	/*
	 * User Bus/Addr error.
	 */
	case T_BUSERR|T_USER:
	case T_ADDRERR|T_USER:
		ksi.ksi_addr = (void *)v;
		ksi.ksi_signo = SIGBUS;
		ksi.ksi_code = (type == (T_BUSERR|T_USER)) ?
			BUS_OBJERR : BUS_ADRERR;
		break;
	/*
	 * User illegal/privleged inst fault
	 */
	case T_ILLINST|T_USER:
	case T_PRIVINST|T_USER:
		ksi.ksi_addr = (void *)(int)fp->f_format;
				/* XXX was ILL_PRIVIN_FAULT */
		ksi.ksi_signo = SIGILL;
		ksi.ksi_code = (type == (T_PRIVINST|T_USER)) ?
			ILL_PRVOPC : ILL_ILLOPC;
		break;
	/*
	 * divde by zero, CHK/TRAPV inst
	 */
	case T_ZERODIV|T_USER:
		ksi.ksi_code = FPE_INTDIV;
	case T_CHKINST|T_USER:
	case T_TRAPVINST|T_USER:
		ksi.ksi_addr = (void *)(int)fp->f_format;
		ksi.ksi_signo = SIGFPE;
		break;

	case T_FPEMULI|T_USER:
	case T_FPEMULD|T_USER:
#ifdef FPU_EMULATE
		if (fpu_emulate(fp, &pcb->pcb_fpregs, &ksi) == 0)
			; /* XXX - Deal with tracing? (fp->f_sr & PSL_T) */
#else
		printf("pid %d killed: no floating point support\n", p->p_pid);
		ksi.ksi_signo = SIGILL;
		ksi.ksi_code = ILL_ILLOPC;
#endif
		break;

#ifdef FPCOPROC
	/*
	 * User coprocessor violation
	 */
	case T_COPERR|T_USER:
	/* XXX What is a proper response here? */
		ksi.ksi_signo = SIGFPE;
		ksi.ksi_code = FPE_FLTINV;
		break;
	/*
	 * 6888x exceptions
	 */
	case T_FPERR|T_USER:
		/*
		 * We pass along the 68881 status register which locore
		 * stashed in code for us.
		 */
		ksi.ksi_signo = SIGFPE;
		ksi.ksi_code = fpsr2siginfocode(code);
		break;
	/*
	 * Kernel coprocessor violation
	 */
	case T_COPERR:
		/*FALLTHROUGH*/
#endif
	/*
	 * Kernel format error
	 */
	case T_FMTERR:
		/*
		 * The user has most likely trashed the RTE or FP state info
		 * in the stack frame of a signal handler.
		 */
		type |= T_USER;
#ifdef DEBUG
		printf("pid %d: kernel %s exception\n", p->p_pid,
		    type==T_COPERR ? "coprocessor" : "format");
#endif
		mutex_enter(p->p_lock);
		SIGACTION(p, SIGILL).sa_handler = SIG_DFL;
		sigdelset(&p->p_sigctx.ps_sigignore, SIGILL);
		sigdelset(&p->p_sigctx.ps_sigcatch, SIGILL);
		sigdelset(&l->l_sigmask, SIGILL);
		mutex_exit(p->p_lock);

		ksi.ksi_signo = SIGILL;
		ksi.ksi_addr = (void *)(int)fp->f_format;
				/* XXX was ILL_RESAD_FAULT */
		ksi.ksi_code = (type == T_COPERR) ?
			ILL_COPROC : ILL_ILLOPC;
		break;
	/*
	 * Trace traps.
	 *
	 * M68k NetBSD uses trap #2,
	 * SUN 3.x uses trap #15,
	 * KGDB uses trap #15 (for kernel breakpoints; handled elsewhere).
	 *
	 * Amiga traps get mapped by locore.s into T_TRACE.
	 * SUN 3.x traps get passed through as T_TRAP15 and are not really
	 * supported yet.
	 */
	case T_TRACE:
	case T_TRAP15:
		fp->f_sr &= ~PSL_T;
		ksi.ksi_signo = SIGTRAP;
		break;
	case T_TRACE|T_USER:
	case T_TRAP15|T_USER:
#ifdef COMPAT_SUNOS
		/*
		 * SunOS uses Trap #2 for a "CPU cache flush".
		 * Just flush the on-chip caches and return.
		 */
		if (p->p_emul == &emul_sunos) {
			ICIA();
			DCIU();
			return;
		}
#endif
		fp->f_sr &= ~PSL_T;
		ksi.ksi_addr = (void *)fp->f_pc;
		ksi.ksi_signo = SIGTRAP;
		if (type == (T_TRAP15|T_USER))
			ksi.ksi_code = TRAP_BRKPT;
		else
			ksi.ksi_code = TRAP_TRACE;
		break;
	/*
	 * Kernel AST (should not happen)
	 */
	case T_ASTFLT:
		panictrap(type, code, v, fp);
	/*
	 * User AST
	 */
	case T_ASTFLT|T_USER:
		astpending = 0;
		spl0();
		if (l->l_pflag & LP_OWEUPC) {
			l->l_pflag &= ~LP_OWEUPC;
			ADDUPROF(l);
		}
		userret(l, fp->f_pc, sticks);
		return;
	/*
	 * Kernel/User page fault
	 */
	case T_MMUFLT:
	case T_MMUFLT|T_USER:	/* page fault */
		trapmmufault(type, code, v, fp, l, sticks);
		return;
	}

#ifdef DEBUG
	if (ksi.ksi_signo != SIGTRAP)
		printf("trapsignal(%d, %d, %d, %x, %x)\n", p->p_pid,
		    ksi.ksi_signo, ksi.ksi_code, v, fp->f_pc);
#endif
	if (ksi.ksi_signo)
		trapsignal(l, &ksi);
	if ((type & T_USER) == 0)
		return;
	userret(l, fp->f_pc, sticks);
}

/*
 * Process a pending write back
 */
int
_write_back (u_int wb, u_int wb_sts, u_int wb_data, u_int wb_addr, struct vm_map *wb_map)
	/* wb:	 writeback type: 1, 2, or 3 */
	/* wb_sts:	 writeback status information */
	/* wb_data:	 data to writeback */
	/* wb_addr:	 address to writeback to */
{
	u_int wb_extra_page = 0;
	u_int wb_rc, mmusr;
	void *onfault;

#ifdef DEBUG
	if (mmudebug)
		printf("wb%d valid: %x %x %x\n",wb,wb_sts,wb_addr,wb_data);
#endif

	/* See if we're going to span two pages (for word or long transfers) */

	if((wb_sts & WBS_SZMASK) == WBS_SIZE_WORD)
		if(trunc_page((vaddr_t)wb_addr) !=
		    trunc_page((vaddr_t)wb_addr+1))
			wb_extra_page = 1;

	if((wb_sts & WBS_SZMASK) == WBS_SIZE_LONG)
		if(trunc_page((vaddr_t)wb_addr) !=
		    trunc_page((vaddr_t)wb_addr+3))
			wb_extra_page = 3;

	/*
	 * if it's writeback 3, we need to check the first page
	 */
	if (wb == 3) {
		mmusr = probeva(wb_addr, wb_sts & WBS_TMMASK);
#ifdef DEBUG
	if (mmudebug)
		printf("wb3: probeva(%x,%x) = %x\n",
		    wb_addr + wb_extra_page, wb_sts & WBS_TMMASK, mmusr);
#endif

		if((mmusr & (MMUSR_R | MMUSR_W)) != MMUSR_R) {
#ifdef DEBUG
			if (mmudebug)
				printf("wb3: need to bring in first page\n");
#endif
			onfault = curpcb->pcb_onfault;
			curpcb->pcb_onfault = NULL;
			wb_rc = uvm_fault(wb_map,
			    trunc_page((vm_offset_t)wb_addr),
			    VM_PROT_READ | VM_PROT_WRITE);
			curpcb->pcb_onfault = onfault;

			if (wb_rc != 0)
				return (wb_rc);
#ifdef DEBUG
			if (mmudebug)
				printf("wb3: first page brought in.\n");
#endif
		}
	}

	/*
	 * now check to see if a second page is required
	 */
	if(wb_extra_page) {

		mmusr = probeva(wb_addr+wb_extra_page, wb_sts & WBS_TMMASK);
#ifdef DEBUG
		if (mmudebug)
			printf("wb%d: probeva %x %x = %x\n",
			    wb, wb_addr + wb_extra_page,
			    wb_sts & WBS_TMMASK,mmusr);
#endif

		if((mmusr & (MMUSR_R | MMUSR_W)) != MMUSR_R) {
#ifdef DEBUG
			if (mmudebug)
				printf("wb%d: page boundary crossed."
				    "  Bringing in extra page.\n",wb);
#endif

			onfault = curpcb->pcb_onfault;
			curpcb->pcb_onfault = NULL;
			wb_rc = uvm_fault(wb_map,
			    trunc_page((vm_offset_t)wb_addr + wb_extra_page),
			    VM_PROT_READ | VM_PROT_WRITE);
			curpcb->pcb_onfault = onfault;

			if (wb_rc != 0)
				return (wb_rc);
		}
#ifdef DEBUG
		if (mmudebug)
			printf("wb%d: extra page brought in okay.\n", wb);
#endif
	}

	/* Actually do the write now */

	if ((wb_sts & WBS_TMMASK) == FC_USERD &&
	    !curpcb->pcb_onfault) {
	    	curpcb->pcb_onfault = (void *) _wb_fault;
	}

	switch(wb_sts & WBS_SZMASK) {

	case WBS_SIZE_BYTE :
		__asm volatile ("movec %0,%%dfc ; movesb %1,%2@":: "d" (wb_sts & WBS_TMMASK),
								 "d" (wb_data),
								 "a" (wb_addr));
		break;

	case WBS_SIZE_WORD :
		__asm volatile ("movec %0,%%dfc ; movesw %1,%2@":: "d" (wb_sts & WBS_TMMASK),
								 "d" (wb_data),
								 "a" (wb_addr));
		break;

	case WBS_SIZE_LONG :
		__asm volatile ("movec %0,%%dfc ; movesl %1,%2@":: "d" (wb_sts & WBS_TMMASK),
								 "d" (wb_data),
								 "a" (wb_addr));
		break;

	}
	if (curpcb->pcb_onfault == (void *) _wb_fault)
		curpcb->pcb_onfault = NULL;
	if ((wb_sts & WBS_TMMASK) != FC_USERD)
		__asm volatile ("movec %0,%%dfc\n" : : "d" (FC_USERD));
	return 0;
}

/*
 * fault handler for write back
 */
void
_wb_fault(void)
{
#ifdef DEBUG
	printf ("trap: writeback fault\n");
#endif
	return;
}
