From 54697fa4bc434c7d1b27b21a7dea9bb824af8781 Mon Sep 17 00:00:00 2001 From: briggs Date: Thu, 21 Apr 1994 23:32:43 +0000 Subject: [PATCH] Almost a copy from Amiga. --- sys/arch/mac68k/mac68k/trap.c | 902 ++++++++++++++++++++++------------ 1 file changed, 601 insertions(+), 301 deletions(-) diff --git a/sys/arch/mac68k/mac68k/trap.c b/sys/arch/mac68k/mac68k/trap.c index 10443ee0f1d3..38438bcfa92e 100644 --- a/sys/arch/mac68k/mac68k/trap.c +++ b/sys/arch/mac68k/mac68k/trap.c @@ -1,6 +1,6 @@ /* * Copyright (c) 1988 University of Utah. - * Copyright (c) 1982, 1990 The Regents of the University of California. + * 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 @@ -34,12 +34,11 @@ * 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$ * - * from: @(#)trap.c 7.15 (Berkeley) 8/2/91 - * $Id: trap.c,v 1.9 1994/04/06 02:59:52 briggs Exp $ + * @(#)trap.c 7.15 (Berkeley) 8/2/91 + * $Id: trap.c,v 1.10 1994/04/21 23:32:43 briggs Exp $ */ #include @@ -60,22 +59,18 @@ #include #include #include +#include #include #include #include -#ifdef COMPAT_SUNOS -#include -#endif - -extern int dbg_flg; - struct sysent sysent[]; int nsysent; #ifdef COMPAT_SUNOS -struct sysent sun_sysent[]; -int nsun_sysent; +#include +struct sysent sun_sysent[]; +int nsun_sysent; #endif char *trap_type[] = { @@ -94,7 +89,7 @@ char *trap_type[] = { "Coprocessor violation", "Async system trap" }; -int trap_types = (sizeof trap_type / sizeof trap_type[0]); +int trap_types = sizeof trap_type / sizeof trap_type[0]; /* * Size of various exception stack frames (minus the standard 8 bytes) @@ -103,9 +98,9 @@ short exframesize[] = { FMT0SIZE, /* type 0 - normal (68020/030/040) */ FMT1SIZE, /* type 1 - throwaway (68020/030/040) */ FMT2SIZE, /* type 2 - normal 6-word (68020/030/040) */ - -1, /* type 3 - FP post-instruction (68040) */ + FMT3SIZE, /* type 3 - FP post-instruction (68040) */ -1, -1, -1, /* type 4-6 - undefined */ - -1, /* type 7 - access error (68040) */ + 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) */ @@ -113,21 +108,20 @@ short exframesize[] = { -1, -1, -1, -1 /* type C-F - undefined */ }; - -int dostacklimits = 0; /* BG, 10PM 12/6; 386BSD has a stack limiting feature */ - /* So I put this in here just for now. */ - #ifdef DEBUG int mmudebug = 0; #endif +extern struct pcb *curpcb; +extern int cpu040; + static void userret(p, pc, oticks) - struct proc *p; - int pc; - struct timeval oticks; + struct proc *p; + int pc; + struct timeval *oticks; { - int sig, s; + int sig, s; while ((sig = CURSIG(p)) != 0) psig(sig); @@ -155,8 +149,8 @@ userret(p, pc, oticks) int ticks; struct timeval *tv = &p->p_stime; - ticks = ((tv->tv_sec - oticks.tv_sec) * 1000 + - (tv->tv_usec - oticks.tv_usec) / 1000) / (tick / 1000); + ticks = ((tv->tv_sec - oticks->tv_sec) * 1000 + + (tv->tv_usec - oticks->tv_usec) / 1000) / (tick / 1000); if (ticks) { #ifdef PROFTIMER extern int profscale; @@ -169,6 +163,239 @@ userret(p, pc, oticks) curpri = p->p_pri; } +void +panictrap(type, code, v, fp) + int type; + u_int code, v; + struct frame *fp; +{ + static int panicing = 0; + if (panicing++ == 0) { + printf("trap type %d, code = %x, v = %x\n", type, code, v); + regdump(fp->f_regs, 128); + } + type &= ~T_USER; + DCIS(); /* XXX? push cache */ + if ((u_int)type < trap_types) + panic(trap_type[type]); + panic("trap"); + /*NOTREACHED*/ +} + +/* + * return to fault handler + */ +void +trapcpfault(p, fp) + struct proc *p; + struct frame *fp; +{ + /* + * 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) p->p_addr->u_pcb.pcb_onfault; +} + +void +trapmmufault(type, code, v, fp, p, sticks) + int type; + u_int code, v; + struct frame *fp; + struct proc *p; + struct timeval *sticks; +{ + extern vm_map_t kernel_map; + struct vmspace *vm; + vm_prot_t ftype; + vm_offset_t va; + vm_map_t map; + u_int nss; + int rv; + + vm = p->p_vmspace; + + /* + * 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 + */ + if (mmudebug && cpu040) { + 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 %x ->pcb_ustp %x / %x\n", + curpcb, curpcb->pcb_ustp, + curpcb->pcb_ustp << PG_SHIFT); + } +#endif + if (type == T_MMUFLT && + (p->p_addr->u_pcb.pcb_onfault == 0 || + (cpu040 && (code & SSW_TMMASK) == FC_SUPERD) || + (!cpu040 && (code & (SSW_DF|FC_SUPERD)) == (SSW_DF|FC_SUPERD)))) + map = kernel_map; + else + map = &vm->vm_map; + if ((cpu040 && (code & SSW_RW040) == 0) || + (!cpu040 && (code & (SSW_DF|SSW_RW)) == + SSW_DF)) /* what about RMW? */ + ftype = VM_PROT_READ | VM_PROT_WRITE; + else + ftype = VM_PROT_READ; + va = trunc_page((vm_offset_t)v); +#ifdef DEBUG + if (map == kernel_map && va == 0) { + printf("trap: bad kernel access at %x\n", v); + panictrap(type, code, v, fp); + } +#endif +#ifndef no_386bsd_code + /* + * XXX: rude hack to make stack limits "work" + */ + nss = 0; + if ((caddr_t)va >= vm->vm_maxsaddr && map != kernel_map) { + nss = clrnd(btoc(USRSTACK - (unsigned)va)); + if (nss > btoc(p->p_rlimit[RLIMIT_STACK].rlim_cur)) { + rv = KERN_FAILURE; + goto nogo; + } + } +#endif + +#ifdef DEBUG + if (mmudebug) + printf("vm_fault(%x,%x,%d,0)\n", map, va, ftype); +#endif + + rv = vm_fault(map, va, ftype, FALSE); + +#ifdef DEBUG + if (mmudebug) + printf("vmfault %s %x returned %d\n", + map == kernel_map ? "kernel" : "user", va, rv); +#endif + + if (cpu040) { + if(rv != KERN_SUCCESS) { + 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. + * + */ + + /* 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) + != KERN_SUCCESS) + 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) { + vm_map_t 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) + != KERN_SUCCESS) + goto nogo; + } + } + +#ifdef no_386bsd_code + /* + * 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 ((caddr_t)va >= vm->vm_maxsaddr && map != kernel_map) { + if (rv == KERN_SUCCESS) { + nss = clrnd(btoc(USRSTACK-(unsigned)va)); + if (nss > vm->vm_ssize) + vm->vm_ssize = nss; + } else if (rv == KERN_PROTECTION_FAILURE) + rv = KERN_INVALID_ADDRESS; + } + + if (rv == KERN_SUCCESS) { + if (type == T_MMUFLT) + return; + userret(p, fp->f_pc, sticks); + reutrn; + } +#else /* use hacky 386bsd_code */ + if (rv == KERN_SUCCESS) { + /* + * XXX: continuation of rude stack hack + */ + if (nss > vm->vm_ssize) + vm->vm_ssize = nss; + if (type == T_MMUFLT) + return; + userret(p, fp->f_pc, sticks); + return; + } +nogo: +#endif + if (type == T_MMUFLT) { + if (p->p_addr->u_pcb.pcb_onfault) { + trapcpfault(p, fp); + return; + } + printf("vm_fault(%x, %x, %x, 0) -> %x\n", + map, va, ftype, rv); + printf(" type %x, code [mmu,,ssw]: %x\n", + type, code); + panictrap(type, code, v, fp); + } + trapsignal(p, (rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV, v); + if ((type & T_USER) == 0) + return; + userret(p, 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. @@ -177,77 +404,110 @@ userret(p, pc, oticks) /*ARGSUSED*/ trap(type, code, v, frame) int type; - unsigned code; - register unsigned v; + u_int code, v; struct frame frame; { - clockframe clk; - register int i; - unsigned ucode = 0; - register struct proc *p = curproc; struct timeval syst; - unsigned ncode; - int s; + struct proc *p; + u_int ncode, ucode; + int i, s; + p = curproc; + ucode = 0; cnt.v_trap++; - syst = p->p_stime; + if (USERMODE(frame.f_sr)) { type |= T_USER; p->p_regs = frame.f_regs; } -#if DDB - if (type == T_TRAP15 || type == T_TRACE) { -printf("kernel trap: calling kdb_trap(%d, &frame).\n", type); +#ifdef DDB + if (type == T_TRACE || type == T_BREAKPOINT) { if (kdb_trap(type, &frame)) return; } #endif switch (type) { - default: -dopanic: - printf("trap type %d, code = %x, v = %x\n", type, code, v); - regdump(frame.f_regs, 128); - type &= ~T_USER; -/* stacknquit(); */ - if ((unsigned)type < trap_types) - panic(trap_type[type]); - panic("trap"); - - case T_BUSERR: /* kernel bus error */ + panictrap(type, code, v, &frame); + /* + * Kernel Bus error + */ + case T_BUSERR: if (!p->p_addr->u_pcb.pcb_onfault) - goto dopanic; - /* - * If we have arranged to catch this fault in any 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. - */ -copyfault: - frame.f_stackadj = exframesize[frame.f_format]; - frame.f_format = frame.f_vector = 0; - frame.f_pc = (int) p->p_addr->u_pcb.pcb_onfault; + panictrap(type, code, v, &frame); + trapcpfault(p, &frame); return; - - case T_BUSERR|T_USER: /* bus error */ - case T_ADDRERR|T_USER: /* address error */ + /* + * User Bus/Addr error. + */ + case T_BUSERR|T_USER: + case T_ADDRERR|T_USER: i = SIGBUS; break; - -#ifdef FPCOPROC - case T_COPERR: /* kernel coprocessor violation */ -#endif - case T_FMTERR: /* kernel format error */ /* - * The user has most likely trashed the RTE or FP state info - * in the stack frame of a signal handler. + * User illegal/privleged inst fault */ + case T_ILLINST|T_USER: + case T_PRIVINST|T_USER: + ucode = frame.f_format; /* XXX was ILL_PRIVIN_FAULT */ + i = SIGILL; + break; + /* + * divde by zero, CHK/TRAPV inst + */ + case T_ZERODIV|T_USER: + case T_CHKINST|T_USER: + case T_TRAPVINST|T_USER: + ucode = frame.f_format; + i = SIGFPE; + break; +#ifdef FPCOPROC + /* + * User coprocessor violation + */ + case T_COPERR|T_USER: + ucode = 0; + i = SIGFPE; /* XXX What is a proper response here? */ + break; + /* + * 6888x exceptions + */ + case T_FPERR|T_USER: + /* + * We pass along the 68881 status register which locore + * stashed in code for us. Note that there is a + * possibility that the bit pattern of this register + * will conflict with one of the FPE_* codes defined + * in signal.h. Fortunately for us, the only such + * codes we use are all in the range 1-7 and the low + * 3 bits of the status register are defined as 0 so + * there is no clash. + */ + ucode = code; + i = SIGFPE; + 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"); + type==T_COPERR ? "coprocessor" : "format"); +#endif p->p_sigacts->ps_sigact[SIGILL] = SIG_DFL; i = sigmask(SIGILL); p->p_sigignore &= ~i; @@ -256,89 +516,48 @@ copyfault: i = SIGILL; ucode = frame.f_format; /* XXX was ILL_RESAD_FAULT */ break; - -#ifdef FPCOPROC - case T_COPERR|T_USER: /* user coprocessor violation */ - /* What is a proper response here? */ - ucode = 0; - i = SIGFPE; - break; - - case T_FPERR|T_USER: /* 68881 exceptions */ /* - * We pass along the 68881 status register which locore stashed - * in code for us. Note that there is a possibility that the - * bit pattern of this register will conflict with one of the - * FPE_* codes defined in signal.h. Fortunately for us, the - * only such codes we use are all in the range 1-7 and the low - * 3 bits of the status register are defined as 0 so there is - * no clash. - */ - ucode = code; - i = SIGFPE; - break; -#endif - - case T_ILLINST|T_USER: /* illegal instruction fault */ -/* 06/04/92,22:41:58 BG deleted HPUXCOMPAT */ - case T_PRIVINST|T_USER: /* privileged instruction fault */ -/* 06/04/92,22:41:58 BG deleted HPUXCOMPAT */ - ucode = frame.f_format; /* XXX was ILL_PRIVIN_FAULT */ - i = SIGILL; - break; - - case T_ZERODIV|T_USER: /* Divide by zero */ -/* 06/04/92,22:41:58 BG deleted HPUXCOMPAT */ - ucode = frame.f_format; /* XXX was FPE_INTDIV_TRAP */ - i = SIGFPE; - break; - - case T_CHKINST|T_USER: /* CHK instruction trap */ -/* 06/04/92,22:41:58 BG deleted HPUXCOMPAT */ - ucode = frame.f_format; /* XXX was FPE_SUBRNG_TRAP */ - i = SIGFPE; - break; - - case T_TRAPVINST|T_USER: /* TRAPV instruction trap */ -/* 06/04/92,22:41:58 BG deleted HPUXCOMPAT */ - ucode = frame.f_format; /* XXX was FPE_INTOVF_TRAP */ - i = SIGFPE; - break; - - /* - * XXX: Trace traps are a nightmare. + * Trace traps. * - * HP-UX uses trap #1 for breakpoints, - * HPBSD uses trap #2, - * SUN 3.x uses trap #15, - * KGDB uses trap #15 (for kernel breakpoints; handled elsewhere). + * M68k NetBSD uses trap #2, + * SUN 3.x uses trap #15, + * KGDB uses trap #15 (for kernel breakpoints; handled elsewhere). * - * HPBSD and HP-UX traps both get mapped by locore.s into T_TRACE. + * 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: /* kernel trace trap */ - case T_TRAP15: /* SUN trace trap */ + case T_TRACE: + case T_TRAP15: frame.f_sr &= ~PSL_T; i = SIGTRAP; break; - - case T_TRACE|T_USER: /* user trace trap */ - case T_TRAP15|T_USER: /* SUN user trace trap */ + case T_TRACE|T_USER: + case T_TRAP15|T_USER: #ifdef COMPAT_SUNOS - /* SunOS seems to use Trap #2 for some obscure fpu operations. - So far, just ignore it, but DONT trap on it.. */ - if (p->p_emul == EMUL_SUNOS) - goto out; + /* + * XXX This comment/code is not consistent XXX + * SunOS seems to use Trap #2 for some obscure + * fpu operations. So far, just ignore it, but + * DONT trap on it.. + */ + if (p->p_emul == EMUL_SUNOS) { + userret(p, frame.f_pc, &syst); + return; + } #endif frame.f_sr &= ~PSL_T; i = SIGTRAP; break; - - case T_ASTFLT: /* system async trap, cannot happen */ - goto dopanic; - - case T_ASTFLT|T_USER: /* user async trap */ + /* + * Kernel AST (should not happen) + */ + case T_ASTFLT: + panictrap(type, code, v, &frame); + /* + * User AST + */ + case T_ASTFLT|T_USER: astpending = 0; /* * We check for software interrupts first. This is because @@ -349,14 +568,16 @@ copyfault: * IPL while processing the SIR. */ spl1(); - /* fall into... */ - - case T_SSIR: /* software interrupt */ + /*FALLTHROUGH*/ + /* + * Software interrupt + */ + case T_SSIR: case T_SSIR|T_USER: if (ssir & SIR_SERIAL) { siroff(SIR_SERIAL); cnt.v_soft++; - sersir(); + serintr(); } if (ssir & SIR_NET) { siroff(SIR_NET); @@ -366,9 +587,7 @@ copyfault: if (ssir & SIR_CLOCK) { siroff(SIR_CLOCK); cnt.v_soft++; - clk.pc = (caddr_t) frame.f_pc; - clk.ps = (caddr_t) frame.f_sr; - softclock(&clk); + softclock(&frame.f_stackadj); } /* * If this was not an AST trap, we are all done. @@ -384,87 +603,26 @@ copyfault: p->p_flag &= ~SOWEUPC; } #endif - goto out; - - case T_MMUFLT: /* kernel mode page fault */ - /* fall into ... */ - + userret(p, frame.f_pc, &syst); + return; + /* + * Kernel/User page fault + */ + case T_MMUFLT: case T_MMUFLT|T_USER: /* page fault */ - { - register vm_offset_t va; - register struct vmspace *vm = p->p_vmspace; - register vm_map_t map; - int rv; - vm_prot_t ftype; - extern vm_map_t kernel_map; - - /* - * 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. - */ - if (type == T_MMUFLT && - (!p->p_addr->u_pcb.pcb_onfault || - (code & (SSW_DF|FC_SUPERD)) == (SSW_DF|FC_SUPERD))) - map = kernel_map; - else - map = &vm->vm_map; - if ((code & (SSW_DF|SSW_RW)) == SSW_DF) /* what about RMW? */ - ftype = VM_PROT_READ | VM_PROT_WRITE; - else - ftype = VM_PROT_READ; - va = trunc_page((vm_offset_t)v); -#ifdef DEBUG - if (map == kernel_map && va == 0) { - printf("trap: bad kernel access at %x\n", v); - goto dopanic; - } -#endif - rv = vm_fault(map, va, ftype, FALSE); - /* - * 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 ((caddr_t)va >= vm->vm_maxsaddr && map != kernel_map) { - if (rv == KERN_SUCCESS) { - unsigned nss; - - nss = clrnd(btoc(USRSTACK-(unsigned)va)); - if (nss > vm->vm_ssize) - vm->vm_ssize = nss; - } else if (rv == KERN_PROTECTION_FAILURE) - rv = KERN_INVALID_ADDRESS; - } - if (rv == KERN_SUCCESS) { - if (type == T_MMUFLT) - return; - goto out; - } - if (type == T_MMUFLT) { - if (p->p_addr->u_pcb.pcb_onfault) - goto copyfault; - printf("vm_fault(%x, %x, %x, 0) -> %x\n", - map, va, ftype, rv); - printf(" type %x, code [mmu,,ssw]: %x\n", - type, code); - goto dopanic; - } - ucode = v; - i = (rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV; - break; - } + trapmmufault(type, code, v, &frame, p, &syst); + return; } + +#ifdef DEBUG + if (i != SIGTRAP) + printf("trapsignal(%d, %d, %d, %x, %x)\n", p->p_pid, i, + ucode, v, frame.f_regs[PC]); +#endif trapsignal(p, i, ucode); if ((type & T_USER) == 0) return; -out: - userret(p, frame.f_pc, syst); + userret(p, frame.f_pc, &syst); } /* @@ -474,82 +632,86 @@ syscall(code, frame) volatile int code; struct frame frame; { - register caddr_t params; - register int i; - register struct sysent *callp; - register struct proc *p = curproc; - int error, opc, numsys, s; - int rval[2], args[8]; struct timeval syst; + struct sysent *callp; struct sysent *systab; + int rval[2], args[8], error, opc, numsys, s, i; + caddr_t params; + struct proc *p; - if(dbg_flg) printf("syscall(%d,0x%08x)\n", code, - frame.f_pc); - - if (!USERMODE(frame.f_sr)) + if (USERMODE(frame.f_sr) == 0) panic("syscall"); - + cnt.v_syscall++; - syst = p->p_stime; + + p = curproc; p->p_regs = frame.f_regs; - opc = frame.f_pc - 2; - p->p_md.md_flags &= ~MDP_STACKADJ; - switch (p->p_emul) - { + syst = p->p_stime; + opc = frame.f_pc - 2; + error = 0; + + switch (p->p_emul) { #ifdef COMPAT_SUNOS - case EMUL_SUNOS: - systab = sun_sysent; - numsys = nsun_sysent; + case EMUL_SUNOS: + systab = sun_sysent; + numsys = nsun_sysent; - /* SunOS passes the syscall-number on the stack, whereas - BSD passes it in D0. So, we have to get the real "code" - from the stack, and clean up the stack, as SunOS glue - code assumes the kernel pops the syscall argument the - glue pushed on the stack. Sigh... */ - code = fuword ((caddr_t) frame.f_regs[SP]); - /* XXX don't do this for sun_sigreturn, as there's no - XXX stored pc on the stack to skip, the argument follows - XXX the syscall number without a gap. */ - if (code != SUN_SYS_sigreturn ) - { - frame.f_regs[SP] += sizeof (int); - /* remember that we adjusted the SP, might have to undo - this if the system call returns ERESTART. */ - p->p_md.md_flags |= MDP_STACKADJ; - } - break; + /* + * SunOS passes the syscall-number on the stack, whereas + * BSD passes it in D0. So, we have to get the real "code" + * from the stack, and clean up the stack, as SunOS glue + * code assumes the kernel pops the syscall argument the + * glue pushed on the stack. Sigh... + */ + code = fuword ((caddr_t) frame.f_regs[SP]); + + /* + * XXX don't do this for sun_sigreturn, as there's no + * XXX stored pc on the stack to skip, the argument follows + * XXX the syscall number without a gap. + */ + if (code != SUN_SYS_sigreturn) { + frame.f_regs[SP] += sizeof (int); + /* + * remember that we adjusted the SP, + * might have to undo this if the system call + * returns ERESTART. + */ + p->p_md.md_flags |= MDP_STACKADJ; + } + break; #endif - - case EMUL_NETBSD: - default: - systab = sysent; - numsys = nsysent; - break; - } + case EMUL_NETBSD: + default: + systab = sysent; + numsys = nsysent; + break; + } params = (caddr_t)frame.f_regs[SP] + sizeof(int); + switch (code) { - case SYS_syscall: - code = fuword(params); - params += sizeof(int); - break; - case SYS___syscall: - if (systab != sysent) - break; - code = fuword(params + _QUAD_LOWWORD * sizeof(int)); - params += sizeof(quad_t); - break; - default: + case SYS_syscall: + code = fuword(params); + params += sizeof(int); + break; + case SYS___syscall: + if (systab != sysent) break; + code = fuword(params + _QUAD_LOWWORD * sizeof(int)); + params += sizeof(quad_t); + break; + default: + break; } + if (code < 0 || code >= numsys) callp = &systab[0]; /* indir (illegal) */ else callp = &systab[code]; - error = 0; - i = callp->sy_narg * sizeof (int); + i = callp->sy_narg * sizeof(int); if (i != 0) error = copyin(params, (caddr_t)args, (u_int)i); @@ -557,7 +719,7 @@ syscall(code, frame) if (KTRPOINT(p, KTR_SYSCALL)) ktrsyscall(p->p_tracep, code, callp->sy_narg, args); #endif - + if (error == 0) { rval[0] = 0; rval[1] = frame.f_regs[D1]; @@ -565,22 +727,21 @@ syscall(code, frame) } switch (error) { - case 0: - frame.f_regs[D0] = rval[0]; - frame.f_regs[D1] = rval[1]; - frame.f_sr &= ~PSL_C; - break; - case ERESTART: - frame.f_pc = opc; - break; - case EJUSTRETURN: - break; - default: - frame.f_regs[D0] = error; - frame.f_sr |= PSL_C; /* carry bit */ - break; + case 0: + frame.f_regs[D0] = rval[0]; + frame.f_regs[D1] = rval[1]; + frame.f_sr &= ~PSL_C; + break; + case ERESTART: + frame.f_pc = opc; + break; + case EJUSTRETURN: + break; + default: + frame.f_regs[D0] = error; + frame.f_sr |= PSL_C; /* carry bit */ + break; } - /* * Reinitialize proc pointer `p' as it may be different * if this is a child returning from fork syscall. @@ -588,15 +749,154 @@ syscall(code, frame) p = curproc; #ifdef COMPAT_SUNOS /* need new p-value for this */ - if (error == ERESTART && (p->p_md.md_flags & MDP_STACKADJ)) - { - frame.f_regs[SP] -= sizeof (int); - p->p_md.md_flags &= ~MDP_STACKADJ; - } + if (error == ERESTART && (p->p_md.md_flags & MDP_STACKADJ)) { + frame.f_regs[SP] -= sizeof (int); + p->p_md.md_flags &= ~MDP_STACKADJ; + } #endif - userret(p, frame.f_pc, syst); + userret(p, frame.f_pc, &syst); #ifdef KTRACE if (KTRPOINT(p, KTR_SYSRET)) ktrsysret(p->p_tracep, code, error, rval[0]); #endif } + +/* + * Process a pending write back + */ + +_write_back (wb, wb_sts, wb_data, wb_addr, wb_map) + u_int wb; /* writeback type: 1, 2, or 3 */ + u_int wb_sts; /* writeback status information */ + u_int wb_data; /* data to writeback */ + u_int wb_addr; /* address to writeback to */ + vm_map_t wb_map; +{ + u_int wb_extra_page = 0; + u_int wb_rc, mmusr; + void _wb_fault (); /* fault handler for write back */ + +#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((vm_offset_t)wb_addr) != + trunc_page((vm_offset_t)wb_addr+1)) + wb_extra_page = 1; + + if((wb_sts & WBS_SZMASK) == WBS_SIZE_LONG) + if(trunc_page((vm_offset_t)wb_addr) != + trunc_page((vm_offset_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)) { +#ifdef DEBUG + if (mmudebug) + printf("wb3: need to bring in first page\n"); +#endif + wb_rc = vm_fault(wb_map, + trunc_page((vm_offset_t)wb_addr), + VM_PROT_READ | VM_PROT_WRITE, FALSE); + + if(wb_rc != KERN_SUCCESS) + 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)) { +#ifdef DEBUG + if (mmudebug) + printf("wb%d: page boundary crossed." + " Bringing in extra page.\n",wb); +#endif + + wb_rc = vm_fault(wb_map, + trunc_page((vm_offset_t)wb_addr + wb_extra_page), + VM_PROT_READ | VM_PROT_WRITE,FALSE); + + if(wb_rc != KERN_SUCCESS) + 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 = (caddr_t) _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 == (caddr_t) _wb_fault) + curpcb->pcb_onfault = NULL; + if ((wb_sts & WBS_TMMASK) != FC_USERD) + asm volatile ("movec %0,dfc\n" : : "d" (FC_USERD)); + return (KERN_SUCCESS); +} + +/* + * fault handler for write back + */ +void _wb_fault() +{ +#ifdef DEBUG + printf ("trap: writeback fault\n"); +#endif + return; +}