141475Smckusick /* 241475Smckusick * Copyright (c) 1988 University of Utah. 3*63472Sbostic * Copyright (c) 1982, 1986, 1990, 1993 4*63472Sbostic * The Regents of the University of California. All rights reserved. 541475Smckusick * 641475Smckusick * This code is derived from software contributed to Berkeley by 741475Smckusick * the Systems Programming Group of the University of Utah Computer 841475Smckusick * Science Department. 941475Smckusick * 1041475Smckusick * %sccs.include.redist.c% 1141475Smckusick * 1257344Shibler * from: Utah $Hdr: trap.c 1.37 92/12/20$ 1341475Smckusick * 14*63472Sbostic * @(#)trap.c 8.1 (Berkeley) 06/16/93 1541475Smckusick */ 1641475Smckusick 1756508Sbostic #include <sys/param.h> 1856508Sbostic #include <sys/systm.h> 1956508Sbostic #include <sys/proc.h> 2056508Sbostic #include <sys/acct.h> 2156508Sbostic #include <sys/kernel.h> 2256508Sbostic #include <sys/signalvar.h> 2356508Sbostic #include <sys/resourcevar.h> 2456508Sbostic #include <sys/syscall.h> 2556508Sbostic #include <sys/syslog.h> 2656508Sbostic #include <sys/user.h> 2748465Skarels #ifdef KTRACE 2856508Sbostic #include <sys/ktrace.h> 2948465Skarels #endif 3048465Skarels 3156508Sbostic #include <machine/psl.h> 3256508Sbostic #include <machine/trap.h> 3356508Sbostic #include <machine/cpu.h> 3456508Sbostic #include <machine/reg.h> 3556508Sbostic #include <machine/mtpr.h> 3641475Smckusick 3756508Sbostic #include <vm/vm.h> 3856508Sbostic #include <vm/pmap.h> 3945751Smckusick 4041475Smckusick #ifdef HPUXCOMPAT 4156508Sbostic #include <hp/hpux/hpux.h> 4241475Smckusick #endif 4341475Smckusick 4441475Smckusick struct sysent sysent[]; 4541475Smckusick int nsysent; 4641475Smckusick 4741475Smckusick char *trap_type[] = { 4841475Smckusick "Bus error", 4941475Smckusick "Address error", 5041475Smckusick "Illegal instruction", 5141475Smckusick "Zero divide", 5241475Smckusick "CHK instruction", 5341475Smckusick "TRAPV instruction", 5441475Smckusick "Privilege violation", 5541475Smckusick "Trace trap", 5641475Smckusick "MMU fault", 5741475Smckusick "SSIR trap", 5841475Smckusick "Format error", 5941475Smckusick "68881 exception", 6041475Smckusick "Coprocessor violation", 6141475Smckusick "Async system trap" 6241475Smckusick }; 6341475Smckusick #define TRAP_TYPES (sizeof trap_type / sizeof trap_type[0]) 6441475Smckusick 6549317Shibler /* 6649317Shibler * Size of various exception stack frames (minus the standard 8 bytes) 6749317Shibler */ 6849317Shibler short exframesize[] = { 6949317Shibler FMT0SIZE, /* type 0 - normal (68020/030/040) */ 7049317Shibler FMT1SIZE, /* type 1 - throwaway (68020/030/040) */ 7149317Shibler FMT2SIZE, /* type 2 - normal 6-word (68020/030/040) */ 7253933Shibler FMT3SIZE, /* type 3 - FP post-instruction (68040) */ 7349317Shibler -1, -1, -1, /* type 4-6 - undefined */ 7453933Shibler FMT7SIZE, /* type 7 - access error (68040) */ 7549317Shibler 58, /* type 8 - bus fault (68010) */ 7649317Shibler FMT9SIZE, /* type 9 - coprocessor mid-instruction (68020/030) */ 7749317Shibler FMTASIZE, /* type A - short bus fault (68020/030) */ 7849317Shibler FMTBSIZE, /* type B - long bus fault (68020/030) */ 7949317Shibler -1, -1, -1, -1 /* type C-F - undefined */ 8049317Shibler }; 8149317Shibler 8254801Storek #ifdef HP380 8353933Shibler #define KDFAULT(c) (mmutype == MMU_68040 ? \ 8453933Shibler ((c) & SSW4_TMMASK) == SSW4_TMKD : \ 8553933Shibler ((c) & (SSW_DF|FC_SUPERD)) == (SSW_DF|FC_SUPERD)) 8653933Shibler #define WRFAULT(c) (mmutype == MMU_68040 ? \ 8753933Shibler ((c) & SSW4_RW) == 0 : \ 8853933Shibler ((c) & (SSW_DF|SSW_RW)) == SSW_DF) 8953933Shibler #else 9053933Shibler #define KDFAULT(c) (((c) & (SSW_DF|SSW_FCMASK)) == (SSW_DF|FC_SUPERD)) 9153933Shibler #define WRFAULT(c) (((c) & (SSW_DF|SSW_RW)) == SSW_DF) 9253933Shibler #endif 9353933Shibler 9441475Smckusick #ifdef DEBUG 9541475Smckusick int mmudebug = 0; 9653933Shibler int mmupid = -1; 9753933Shibler #define MDB_FOLLOW 1 9853933Shibler #define MDB_WBFOLLOW 2 9953933Shibler #define MDB_WBFAILED 4 10053933Shibler #define MDB_ISPID(p) (p) == mmupid 10141475Smckusick #endif 10241475Smckusick 10341475Smckusick /* 10454801Storek * trap and syscall both need the following work done before returning 10554801Storek * to user mode. 10654801Storek */ 10754801Storek static inline void 10854801Storek userret(p, fp, oticks, faultaddr, fromtrap) 10954801Storek register struct proc *p; 11054801Storek register struct frame *fp; 11154801Storek u_quad_t oticks; 11254801Storek u_int faultaddr; 11354801Storek int fromtrap; 11454801Storek { 11554801Storek int sig, s; 11654801Storek #ifdef HP380 11754801Storek int beenhere = 0; 11854801Storek 11954801Storek again: 12054801Storek #endif 12154801Storek /* take pending signals */ 12254801Storek while ((sig = CURSIG(p)) != 0) 12354801Storek psig(sig); 12454801Storek p->p_pri = p->p_usrpri; 12554801Storek if (want_resched) { 12654801Storek /* 12754801Storek * Since we are curproc, clock will normally just change 12854801Storek * our priority without moving us from one queue to another 12954801Storek * (since the running process is not on a queue.) 13054801Storek * If that happened after we setrq ourselves but before we 13154801Storek * swtch()'ed, we might not be on the queue indicated by 13254801Storek * our priority. 13354801Storek */ 13454801Storek s = splstatclock(); 13554801Storek setrq(p); 13654801Storek p->p_stats->p_ru.ru_nivcsw++; 13754801Storek swtch(); 13854801Storek splx(s); 13954801Storek while ((sig = CURSIG(p)) != 0) 14054801Storek psig(sig); 14154801Storek } 14254801Storek 14354801Storek /* 14454801Storek * If profiling, charge system time to the trapped pc. 14554801Storek */ 14656318Shibler if (p->p_flag & SPROFIL) { 14756318Shibler extern int psratio; 14856318Shibler 14956318Shibler addupc_task(p, fp->f_pc, 15056318Shibler (int)(p->p_sticks - oticks) * psratio); 15156318Shibler } 15254801Storek #ifdef HP380 15354801Storek /* 15454801Storek * Deal with user mode writebacks (from trap, or from sigreturn). 15554801Storek * If any writeback fails, go back and attempt signal delivery. 15654801Storek * unless we have already been here and attempted the writeback 15754801Storek * (e.g. bad address with user ignoring SIGSEGV). In that case 15854801Storek * we just return to the user without sucessfully completing 15954801Storek * the writebacks. Maybe we should just drop the sucker? 16054801Storek */ 16154801Storek if (mmutype == MMU_68040 && fp->f_format == FMT7) { 16254801Storek if (beenhere) { 16354801Storek #ifdef DEBUG 16454801Storek if (mmudebug & MDB_WBFAILED) 16554801Storek printf(fromtrap ? 16654801Storek "pid %d(%s): writeback aborted, pc=%x, fa=%x\n" : 16754801Storek "pid %d(%s): writeback aborted in sigreturn, pc=%x\n", 16854801Storek p->p_pid, p->p_comm, fp->f_pc, faultaddr); 16954801Storek #endif 17054801Storek } else if (sig = writeback(fp, fromtrap)) { 17154801Storek beenhere = 1; 17254801Storek oticks = p->p_sticks; 17354801Storek trapsignal(p, sig, faultaddr); 17454801Storek goto again; 17554801Storek } 17654801Storek } 17754801Storek #endif 17854801Storek curpri = p->p_pri; 17954801Storek } 18054801Storek 18154801Storek /* 18249531Skarels * Trap is called from locore to handle most types of processor traps, 18349531Skarels * including events such as simulated software interrupts/AST's. 18449531Skarels * System calls are broken out for efficiency. 18541475Smckusick */ 18641475Smckusick /*ARGSUSED*/ 18741475Smckusick trap(type, code, v, frame) 18841475Smckusick int type; 18941475Smckusick unsigned code; 19041475Smckusick register unsigned v; 19141475Smckusick struct frame frame; 19241475Smckusick { 19341475Smckusick register int i; 19454801Storek unsigned ucode; 19554801Storek register struct proc *p; 19654801Storek u_quad_t sticks; 19741475Smckusick unsigned ncode; 19854574Storek extern char fswintr[]; 19941475Smckusick 20041475Smckusick cnt.v_trap++; 20154801Storek p = curproc; 20254801Storek ucode = 0; 20341475Smckusick if (USERMODE(frame.f_sr)) { 20449531Skarels type |= T_USER; 20554801Storek sticks = p->p_sticks; 20652380Smckusick p->p_md.md_regs = frame.f_regs; 20741475Smckusick } 20841475Smckusick switch (type) { 20941475Smckusick 21041475Smckusick default: 21141475Smckusick dopanic: 21241475Smckusick printf("trap type %d, code = %x, v = %x\n", type, code, v); 21357344Shibler regdump(&frame, 128); 21449531Skarels type &= ~T_USER; 21541475Smckusick if ((unsigned)type < TRAP_TYPES) 21641475Smckusick panic(trap_type[type]); 21741475Smckusick panic("trap"); 21841475Smckusick 21941475Smckusick case T_BUSERR: /* kernel bus error */ 22049125Skarels if (!p->p_addr->u_pcb.pcb_onfault) 22141475Smckusick goto dopanic; 22241475Smckusick /* 22341475Smckusick * If we have arranged to catch this fault in any of the 22441475Smckusick * copy to/from user space routines, set PC to return to 22541475Smckusick * indicated location and set flag informing buserror code 22641475Smckusick * that it may need to clean up stack frame. 22741475Smckusick */ 22841475Smckusick copyfault: 22949317Shibler frame.f_stackadj = exframesize[frame.f_format]; 23049317Shibler frame.f_format = frame.f_vector = 0; 23149125Skarels frame.f_pc = (int) p->p_addr->u_pcb.pcb_onfault; 23241475Smckusick return; 23341475Smckusick 23449531Skarels case T_BUSERR|T_USER: /* bus error */ 23549531Skarels case T_ADDRERR|T_USER: /* address error */ 23653933Shibler ucode = v; 23741475Smckusick i = SIGBUS; 23841475Smckusick break; 23941475Smckusick 24041475Smckusick #ifdef FPCOPROC 24141475Smckusick case T_COPERR: /* kernel coprocessor violation */ 24241475Smckusick #endif 24353933Shibler case T_FMTERR|T_USER: /* do all RTE errors come in as T_USER? */ 24453933Shibler case T_FMTERR: /* ...just in case... */ 24541475Smckusick /* 24641475Smckusick * The user has most likely trashed the RTE or FP state info 24741475Smckusick * in the stack frame of a signal handler. 24841475Smckusick */ 24949531Skarels type |= T_USER; 25048465Skarels printf("pid %d: kernel %s exception\n", p->p_pid, 25141475Smckusick type==T_COPERR ? "coprocessor" : "format"); 25248465Skarels p->p_sigacts->ps_sigact[SIGILL] = SIG_DFL; 25341475Smckusick i = sigmask(SIGILL); 25441475Smckusick p->p_sigignore &= ~i; 25541475Smckusick p->p_sigcatch &= ~i; 25641475Smckusick p->p_sigmask &= ~i; 25742370Skarels i = SIGILL; 25841475Smckusick ucode = frame.f_format; /* XXX was ILL_RESAD_FAULT */ 25942370Skarels break; 26041475Smckusick 26141475Smckusick #ifdef FPCOPROC 26249531Skarels case T_COPERR|T_USER: /* user coprocessor violation */ 26341475Smckusick /* What is a proper response here? */ 26441475Smckusick ucode = 0; 26541475Smckusick i = SIGFPE; 26641475Smckusick break; 26741475Smckusick 26849531Skarels case T_FPERR|T_USER: /* 68881 exceptions */ 26941475Smckusick /* 27041475Smckusick * We pass along the 68881 status register which locore stashed 27141475Smckusick * in code for us. Note that there is a possibility that the 27241475Smckusick * bit pattern of this register will conflict with one of the 27341475Smckusick * FPE_* codes defined in signal.h. Fortunately for us, the 27441475Smckusick * only such codes we use are all in the range 1-7 and the low 27541475Smckusick * 3 bits of the status register are defined as 0 so there is 27641475Smckusick * no clash. 27741475Smckusick */ 27841475Smckusick ucode = code; 27941475Smckusick i = SIGFPE; 28041475Smckusick break; 28141475Smckusick #endif 28241475Smckusick 28354801Storek #ifdef HP380 28453933Shibler case T_FPEMULI|T_USER: /* unimplemented FP instuction */ 28553933Shibler case T_FPEMULD|T_USER: /* unimplemented FP data type */ 28653933Shibler /* XXX need to FSAVE */ 28753933Shibler printf("pid %d(%s): unimplemented FP %s at %x (EA %x)\n", 28853933Shibler p->p_pid, p->p_comm, 28953933Shibler frame.f_format == 2 ? "instruction" : "data type", 29053933Shibler frame.f_pc, frame.f_fmt2.f_iaddr); 29153933Shibler /* XXX need to FRESTORE */ 29253933Shibler i = SIGFPE; 29353933Shibler break; 29453933Shibler #endif 29553933Shibler 29649531Skarels case T_ILLINST|T_USER: /* illegal instruction fault */ 29741475Smckusick #ifdef HPUXCOMPAT 29857344Shibler if (p->p_md.md_flags & MDP_HPUX) { 29941475Smckusick ucode = HPUX_ILL_ILLINST_TRAP; 30041475Smckusick i = SIGILL; 30141475Smckusick break; 30241475Smckusick } 30341475Smckusick /* fall through */ 30441475Smckusick #endif 30549531Skarels case T_PRIVINST|T_USER: /* privileged instruction fault */ 30641475Smckusick #ifdef HPUXCOMPAT 30757344Shibler if (p->p_md.md_flags & MDP_HPUX) 30841475Smckusick ucode = HPUX_ILL_PRIV_TRAP; 30941475Smckusick else 31041475Smckusick #endif 31141475Smckusick ucode = frame.f_format; /* XXX was ILL_PRIVIN_FAULT */ 31241475Smckusick i = SIGILL; 31341475Smckusick break; 31441475Smckusick 31549531Skarels case T_ZERODIV|T_USER: /* Divide by zero */ 31641475Smckusick #ifdef HPUXCOMPAT 31757344Shibler if (p->p_md.md_flags & MDP_HPUX) 31841475Smckusick ucode = HPUX_FPE_INTDIV_TRAP; 31941475Smckusick else 32041475Smckusick #endif 32141475Smckusick ucode = frame.f_format; /* XXX was FPE_INTDIV_TRAP */ 32241475Smckusick i = SIGFPE; 32341475Smckusick break; 32441475Smckusick 32549531Skarels case T_CHKINST|T_USER: /* CHK instruction trap */ 32641475Smckusick #ifdef HPUXCOMPAT 32757344Shibler if (p->p_md.md_flags & MDP_HPUX) { 32841475Smckusick /* handled differently under hp-ux */ 32941475Smckusick i = SIGILL; 33041475Smckusick ucode = HPUX_ILL_CHK_TRAP; 33141475Smckusick break; 33241475Smckusick } 33341475Smckusick #endif 33441475Smckusick ucode = frame.f_format; /* XXX was FPE_SUBRNG_TRAP */ 33541475Smckusick i = SIGFPE; 33641475Smckusick break; 33741475Smckusick 33849531Skarels case T_TRAPVINST|T_USER: /* TRAPV instruction trap */ 33941475Smckusick #ifdef HPUXCOMPAT 34057344Shibler if (p->p_md.md_flags & MDP_HPUX) { 34141475Smckusick /* handled differently under hp-ux */ 34241475Smckusick i = SIGILL; 34341475Smckusick ucode = HPUX_ILL_TRAPV_TRAP; 34441475Smckusick break; 34541475Smckusick } 34641475Smckusick #endif 34741475Smckusick ucode = frame.f_format; /* XXX was FPE_INTOVF_TRAP */ 34841475Smckusick i = SIGFPE; 34941475Smckusick break; 35041475Smckusick 35141475Smckusick /* 35241475Smckusick * XXX: Trace traps are a nightmare. 35341475Smckusick * 35441475Smckusick * HP-UX uses trap #1 for breakpoints, 35541475Smckusick * HPBSD uses trap #2, 35641475Smckusick * SUN 3.x uses trap #15, 35748465Skarels * KGDB uses trap #15 (for kernel breakpoints; handled elsewhere). 35841475Smckusick * 35941475Smckusick * HPBSD and HP-UX traps both get mapped by locore.s into T_TRACE. 36041475Smckusick * SUN 3.x traps get passed through as T_TRAP15 and are not really 36148465Skarels * supported yet. 36241475Smckusick */ 36341475Smckusick case T_TRACE: /* kernel trace trap */ 36448465Skarels case T_TRAP15: /* SUN trace trap */ 36541475Smckusick frame.f_sr &= ~PSL_T; 36641475Smckusick i = SIGTRAP; 36741475Smckusick break; 36841475Smckusick 36949531Skarels case T_TRACE|T_USER: /* user trace trap */ 37049531Skarels case T_TRAP15|T_USER: /* SUN user trace trap */ 37141475Smckusick frame.f_sr &= ~PSL_T; 37241475Smckusick i = SIGTRAP; 37341475Smckusick break; 37441475Smckusick 37543413Shibler case T_ASTFLT: /* system async trap, cannot happen */ 37641475Smckusick goto dopanic; 37741475Smckusick 37849531Skarels case T_ASTFLT|T_USER: /* user async trap */ 37949125Skarels astpending = 0; 38041475Smckusick /* 38141475Smckusick * We check for software interrupts first. This is because 38241475Smckusick * they are at a higher level than ASTs, and on a VAX would 38341475Smckusick * interrupt the AST. We assume that if we are processing 38441475Smckusick * an AST that we must be at IPL0 so we don't bother to 38541475Smckusick * check. Note that we ensure that we are at least at SIR 38641475Smckusick * IPL while processing the SIR. 38741475Smckusick */ 38841475Smckusick spl1(); 38941475Smckusick /* fall into... */ 39041475Smckusick 39141475Smckusick case T_SSIR: /* software interrupt */ 39249531Skarels case T_SSIR|T_USER: 39341475Smckusick if (ssir & SIR_NET) { 39441475Smckusick siroff(SIR_NET); 39541475Smckusick cnt.v_soft++; 39641475Smckusick netintr(); 39741475Smckusick } 39841475Smckusick if (ssir & SIR_CLOCK) { 39941475Smckusick siroff(SIR_CLOCK); 40041475Smckusick cnt.v_soft++; 40154801Storek softclock(); 40241475Smckusick } 40341475Smckusick /* 40441475Smckusick * If this was not an AST trap, we are all done. 40541475Smckusick */ 40650753Skarels if (type != (T_ASTFLT|T_USER)) { 40741475Smckusick cnt.v_trap--; 40841475Smckusick return; 40941475Smckusick } 41041475Smckusick spl0(); 41154801Storek if (p->p_flag & SOWEUPC) { 41248465Skarels p->p_flag &= ~SOWEUPC; 41354801Storek ADDUPROF(p); 41441475Smckusick } 41541475Smckusick goto out; 41641475Smckusick 41741475Smckusick case T_MMUFLT: /* kernel mode page fault */ 41854574Storek /* 41954574Storek * If we were doing profiling ticks or other user mode 42054574Storek * stuff from interrupt code, Just Say No. 42154574Storek */ 42254574Storek if (p->p_addr->u_pcb.pcb_onfault == fswintr) 42354574Storek goto copyfault; 42441475Smckusick /* fall into ... */ 42541475Smckusick 42649531Skarels case T_MMUFLT|T_USER: /* page fault */ 42745751Smckusick { 42845751Smckusick register vm_offset_t va; 42948465Skarels register struct vmspace *vm = p->p_vmspace; 43045751Smckusick register vm_map_t map; 43145751Smckusick int rv; 43245751Smckusick vm_prot_t ftype; 43345751Smckusick extern vm_map_t kernel_map; 43445751Smckusick 43553933Shibler #ifdef DEBUG 43653933Shibler if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid)) 43753933Shibler printf("trap: T_MMUFLT pid=%d, code=%x, v=%x, pc=%x, sr=%x\n", 43853933Shibler p->p_pid, code, v, frame.f_pc, frame.f_sr); 43953933Shibler #endif 44041475Smckusick /* 44145751Smckusick * It is only a kernel address space fault iff: 44249531Skarels * 1. (type & T_USER) == 0 and 44345751Smckusick * 2. pcb_onfault not set or 44445751Smckusick * 3. pcb_onfault set but supervisor space data fault 44545751Smckusick * The last can occur during an exec() copyin where the 44645751Smckusick * argument space is lazy-allocated. 44741475Smckusick */ 44845751Smckusick if (type == T_MMUFLT && 44953933Shibler (!p->p_addr->u_pcb.pcb_onfault || KDFAULT(code))) 45045751Smckusick map = kernel_map; 45145751Smckusick else 45248465Skarels map = &vm->vm_map; 45353933Shibler if (WRFAULT(code)) 45445751Smckusick ftype = VM_PROT_READ | VM_PROT_WRITE; 45545751Smckusick else 45645751Smckusick ftype = VM_PROT_READ; 45745751Smckusick va = trunc_page((vm_offset_t)v); 45841475Smckusick #ifdef DEBUG 45945751Smckusick if (map == kernel_map && va == 0) { 46045751Smckusick printf("trap: bad kernel access at %x\n", v); 46141475Smckusick goto dopanic; 46241475Smckusick } 46341475Smckusick #endif 46457344Shibler #ifdef HPUXCOMPAT 46557344Shibler if (ISHPMMADDR(va)) { 46657344Shibler vm_offset_t bva; 46757344Shibler 46857344Shibler rv = pmap_mapmulti(map->pmap, va); 46957344Shibler if (rv != KERN_SUCCESS) { 47057344Shibler bva = HPMMBASEADDR(va); 47157344Shibler rv = vm_fault(map, bva, ftype, FALSE); 47257344Shibler if (rv == KERN_SUCCESS) 47357344Shibler (void) pmap_mapmulti(map->pmap, va); 47457344Shibler } 47557344Shibler } else 47657344Shibler #endif 47749317Shibler rv = vm_fault(map, va, ftype, FALSE); 47853933Shibler #ifdef DEBUG 47953933Shibler if (rv && MDB_ISPID(p->p_pid)) 48053933Shibler printf("vm_fault(%x, %x, %x, 0) -> %x\n", 48153933Shibler map, va, ftype, rv); 48253933Shibler #endif 48341475Smckusick /* 48449317Shibler * If this was a stack access we keep track of the maximum 48549317Shibler * accessed stack size. Also, if vm_fault gets a protection 48649317Shibler * failure it is due to accessing the stack region outside 48749317Shibler * the current limit and we need to reflect that as an access 48849317Shibler * error. 48941475Smckusick */ 49048465Skarels if ((caddr_t)va >= vm->vm_maxsaddr && map != kernel_map) { 49149317Shibler if (rv == KERN_SUCCESS) { 49249317Shibler unsigned nss; 49349317Shibler 49449317Shibler nss = clrnd(btoc(USRSTACK-(unsigned)va)); 49549317Shibler if (nss > vm->vm_ssize) 49649317Shibler vm->vm_ssize = nss; 49749317Shibler } else if (rv == KERN_PROTECTION_FAILURE) 49849317Shibler rv = KERN_INVALID_ADDRESS; 49941475Smckusick } 50045751Smckusick if (rv == KERN_SUCCESS) { 50153933Shibler if (type == T_MMUFLT) { 50254801Storek #ifdef HP380 50353933Shibler if (mmutype == MMU_68040) 50453933Shibler (void) writeback(&frame, 1); 50553933Shibler #endif 50641475Smckusick return; 50753933Shibler } 50841475Smckusick goto out; 50941475Smckusick } 51045751Smckusick if (type == T_MMUFLT) { 51149125Skarels if (p->p_addr->u_pcb.pcb_onfault) 51245751Smckusick goto copyfault; 51345751Smckusick printf("vm_fault(%x, %x, %x, 0) -> %x\n", 51445751Smckusick map, va, ftype, rv); 51545751Smckusick printf(" type %x, code [mmu,,ssw]: %x\n", 51645751Smckusick type, code); 51745751Smckusick goto dopanic; 51845751Smckusick } 51948465Skarels ucode = v; 52045751Smckusick i = (rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV; 52145751Smckusick break; 52245751Smckusick } 52341475Smckusick } 52448465Skarels trapsignal(p, i, ucode); 52549531Skarels if ((type & T_USER) == 0) 52641475Smckusick return; 52741475Smckusick out: 52854801Storek userret(p, &frame, sticks, v, 1); 52941475Smckusick } 53041475Smckusick 53154801Storek #ifdef HP380 53253933Shibler #ifdef DEBUG 53353933Shibler struct writebackstats { 53453933Shibler int calls; 53553933Shibler int cpushes; 53653933Shibler int move16s; 53753933Shibler int wb1s, wb2s, wb3s; 53853933Shibler int wbsize[4]; 53953933Shibler } wbstats; 54053933Shibler 54153933Shibler char *f7sz[] = { "longword", "byte", "word", "line" }; 54253933Shibler char *f7tt[] = { "normal", "MOVE16", "AFC", "ACK" }; 54353933Shibler char *f7tm[] = { "d-push", "u-data", "u-code", "M-data", 54453933Shibler "M-code", "k-data", "k-code", "RES" }; 54553933Shibler char wberrstr[] = 54653933Shibler "WARNING: pid %d(%s) writeback [%s] failed, pc=%x fa=%x wba=%x wbd=%x\n"; 54753933Shibler #endif 54853933Shibler 54953933Shibler writeback(fp, docachepush) 55053933Shibler struct frame *fp; 55153933Shibler int docachepush; 55253933Shibler { 55353933Shibler register struct fmt7 *f = &fp->f_fmt7; 55453933Shibler register struct proc *p = curproc; 55553933Shibler int err = 0; 55653933Shibler u_int fa; 55753933Shibler caddr_t oonfault = p->p_addr->u_pcb.pcb_onfault; 55853933Shibler 55953933Shibler #ifdef DEBUG 56053933Shibler if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid)) { 56153933Shibler printf(" pid=%d, fa=%x,", p->p_pid, f->f_fa); 56253933Shibler dumpssw(f->f_ssw); 56353933Shibler } 56453933Shibler wbstats.calls++; 56553933Shibler #endif 56653933Shibler /* 56753933Shibler * Deal with special cases first. 56853933Shibler */ 56953933Shibler if ((f->f_ssw & SSW4_TMMASK) == SSW4_TMDCP) { 57053933Shibler /* 57153933Shibler * Dcache push fault. 57253933Shibler * Line-align the address and write out the push data to 57353933Shibler * the indicated physical address. 57453933Shibler */ 57553933Shibler #ifdef DEBUG 57653933Shibler if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid)) { 57753933Shibler printf(" pushing %s to PA %x, data %x", 57853933Shibler f7sz[(f->f_ssw & SSW4_SZMASK) >> 5], 57953933Shibler f->f_fa, f->f_pd0); 58053933Shibler if ((f->f_ssw & SSW4_SZMASK) == SSW4_SZLN) 58153933Shibler printf("/%x/%x/%x", 58253933Shibler f->f_pd1, f->f_pd2, f->f_pd3); 58353933Shibler printf("\n"); 58453933Shibler } 58553933Shibler if (f->f_wb1s & SSW4_WBSV) 58653933Shibler panic("writeback: cache push with WB1S valid"); 58753933Shibler wbstats.cpushes++; 58853933Shibler #endif 58953933Shibler /* 59053933Shibler * XXX there are security problems if we attempt to do a 59153933Shibler * cache push after a signal handler has been called. 59253933Shibler */ 59353933Shibler if (docachepush) { 59453933Shibler pmap_enter(kernel_pmap, (vm_offset_t)vmmap, 59553933Shibler trunc_page(f->f_fa), VM_PROT_WRITE, TRUE); 59653933Shibler fa = (u_int)&vmmap[(f->f_fa & PGOFSET) & ~0xF]; 59753933Shibler bcopy((caddr_t)&f->f_pd0, (caddr_t)fa, 16); 59853933Shibler DCFL(pmap_extract(kernel_pmap, (vm_offset_t)fa)); 59953933Shibler pmap_remove(kernel_pmap, (vm_offset_t)vmmap, 60053933Shibler (vm_offset_t)&vmmap[NBPG]); 60153933Shibler } else 60253933Shibler printf("WARNING: pid %d(%s) uid %d: CPUSH not done\n", 60353933Shibler p->p_pid, p->p_comm, p->p_ucred->cr_uid); 60453933Shibler } else if ((f->f_ssw & (SSW4_RW|SSW4_TTMASK)) == SSW4_TTM16) { 60553933Shibler /* 60653933Shibler * MOVE16 fault. 60753933Shibler * Line-align the address and write out the push data to 60853933Shibler * the indicated virtual address. 60953933Shibler */ 61053933Shibler #ifdef DEBUG 61153933Shibler if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid)) 61253933Shibler printf(" MOVE16 to VA %x(%x), data %x/%x/%x/%x\n", 61353933Shibler f->f_fa, f->f_fa & ~0xF, f->f_pd0, f->f_pd1, 61453933Shibler f->f_pd2, f->f_pd3); 61553933Shibler if (f->f_wb1s & SSW4_WBSV) 61653933Shibler panic("writeback: MOVE16 with WB1S valid"); 61753933Shibler wbstats.move16s++; 61853933Shibler #endif 61953933Shibler if (KDFAULT(f->f_wb1s)) 62053933Shibler bcopy((caddr_t)&f->f_pd0, (caddr_t)(f->f_fa & ~0xF), 16); 62153933Shibler else 62253933Shibler err = suline((caddr_t)(f->f_fa & ~0xF), (caddr_t)&f->f_pd0); 62353933Shibler if (err) { 62453933Shibler fa = f->f_fa & ~0xF; 62553933Shibler #ifdef DEBUG 62653933Shibler if (mmudebug & MDB_WBFAILED) 62753933Shibler printf(wberrstr, p->p_pid, p->p_comm, 62853933Shibler "MOVE16", fp->f_pc, f->f_fa, 62953933Shibler f->f_fa & ~0xF, f->f_pd0); 63053933Shibler #endif 63153933Shibler } 63253933Shibler } else if (f->f_wb1s & SSW4_WBSV) { 63353933Shibler /* 63453933Shibler * Writeback #1. 63553933Shibler * Position the "memory-aligned" data and write it out. 63653933Shibler */ 63753933Shibler register u_int wb1d = f->f_wb1d; 63853933Shibler register int off; 63953933Shibler 64053933Shibler #ifdef DEBUG 64153933Shibler if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid)) 64253933Shibler dumpwb(1, f->f_wb1s, f->f_wb1a, f->f_wb1d); 64353933Shibler wbstats.wb1s++; 64453933Shibler wbstats.wbsize[(f->f_wb2s&SSW4_SZMASK)>>5]++; 64553933Shibler #endif 64653933Shibler off = (f->f_wb1a & 3) * 8; 64753933Shibler switch (f->f_wb1s & SSW4_SZMASK) { 64853933Shibler case SSW4_SZLW: 64953933Shibler if (off) 65053933Shibler wb1d = (wb1d >> (32 - off)) | (wb1d << off); 65153933Shibler if (KDFAULT(f->f_wb1s)) 65253933Shibler *(long *)f->f_wb1a = wb1d; 65353933Shibler else 65453933Shibler err = suword((caddr_t)f->f_wb1a, wb1d); 65553933Shibler break; 65653933Shibler case SSW4_SZB: 65753933Shibler off = 24 - off; 65853933Shibler if (off) 65953933Shibler wb1d >>= off; 66053933Shibler if (KDFAULT(f->f_wb1s)) 66153933Shibler *(char *)f->f_wb1a = wb1d; 66253933Shibler else 66353933Shibler err = subyte((caddr_t)f->f_wb1a, wb1d); 66453933Shibler break; 66553933Shibler case SSW4_SZW: 66653933Shibler off = (off + 16) % 32; 66753933Shibler if (off) 66853933Shibler wb1d = (wb1d >> (32 - off)) | (wb1d << off); 66953933Shibler if (KDFAULT(f->f_wb1s)) 67053933Shibler *(short *)f->f_wb1a = wb1d; 67153933Shibler else 67253933Shibler err = susword((caddr_t)f->f_wb1a, wb1d); 67353933Shibler break; 67453933Shibler } 67553933Shibler if (err) { 67653933Shibler fa = f->f_wb1a; 67753933Shibler #ifdef DEBUG 67853933Shibler if (mmudebug & MDB_WBFAILED) 67953933Shibler printf(wberrstr, p->p_pid, p->p_comm, 68053933Shibler "#1", fp->f_pc, f->f_fa, 68153933Shibler f->f_wb1a, f->f_wb1d); 68253933Shibler #endif 68353933Shibler } 68453933Shibler } 68553933Shibler /* 68653933Shibler * Deal with the "normal" writebacks. 68753933Shibler * 68853933Shibler * XXX writeback2 is known to reflect a LINE size writeback after 68953933Shibler * a MOVE16 was already dealt with above. Ignore it. 69053933Shibler */ 69153933Shibler if (err == 0 && (f->f_wb2s & SSW4_WBSV) && 69253933Shibler (f->f_wb2s & SSW4_SZMASK) != SSW4_SZLN) { 69353933Shibler #ifdef DEBUG 69453933Shibler if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid)) 69553933Shibler dumpwb(2, f->f_wb2s, f->f_wb2a, f->f_wb2d); 69653933Shibler wbstats.wb2s++; 69753933Shibler wbstats.wbsize[(f->f_wb2s&SSW4_SZMASK)>>5]++; 69853933Shibler #endif 69953933Shibler switch (f->f_wb2s & SSW4_SZMASK) { 70053933Shibler case SSW4_SZLW: 70153933Shibler if (KDFAULT(f->f_wb2s)) 70253933Shibler *(long *)f->f_wb2a = f->f_wb2d; 70353933Shibler else 70453933Shibler err = suword((caddr_t)f->f_wb2a, f->f_wb2d); 70553933Shibler break; 70653933Shibler case SSW4_SZB: 70753933Shibler if (KDFAULT(f->f_wb2s)) 70853933Shibler *(char *)f->f_wb2a = f->f_wb2d; 70953933Shibler else 71053933Shibler err = subyte((caddr_t)f->f_wb2a, f->f_wb2d); 71153933Shibler break; 71253933Shibler case SSW4_SZW: 71353933Shibler if (KDFAULT(f->f_wb2s)) 71453933Shibler *(short *)f->f_wb2a = f->f_wb2d; 71553933Shibler else 71653933Shibler err = susword((caddr_t)f->f_wb2a, f->f_wb2d); 71753933Shibler break; 71853933Shibler } 71953933Shibler if (err) { 72053933Shibler fa = f->f_wb2a; 72153933Shibler #ifdef DEBUG 72253933Shibler if (mmudebug & MDB_WBFAILED) { 72353933Shibler printf(wberrstr, p->p_pid, p->p_comm, 72453933Shibler "#2", fp->f_pc, f->f_fa, 72553933Shibler f->f_wb2a, f->f_wb2d); 72653933Shibler dumpssw(f->f_ssw); 72753933Shibler dumpwb(2, f->f_wb2s, f->f_wb2a, f->f_wb2d); 72853933Shibler } 72953933Shibler #endif 73053933Shibler } 73153933Shibler } 73253933Shibler if (err == 0 && (f->f_wb3s & SSW4_WBSV)) { 73353933Shibler #ifdef DEBUG 73453933Shibler if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid)) 73553933Shibler dumpwb(3, f->f_wb3s, f->f_wb3a, f->f_wb3d); 73653933Shibler wbstats.wb3s++; 73753933Shibler wbstats.wbsize[(f->f_wb3s&SSW4_SZMASK)>>5]++; 73853933Shibler #endif 73953933Shibler switch (f->f_wb3s & SSW4_SZMASK) { 74053933Shibler case SSW4_SZLW: 74153933Shibler if (KDFAULT(f->f_wb3s)) 74253933Shibler *(long *)f->f_wb3a = f->f_wb3d; 74353933Shibler else 74453933Shibler err = suword((caddr_t)f->f_wb3a, f->f_wb3d); 74553933Shibler break; 74653933Shibler case SSW4_SZB: 74753933Shibler if (KDFAULT(f->f_wb3s)) 74853933Shibler *(char *)f->f_wb3a = f->f_wb3d; 74953933Shibler else 75053933Shibler err = subyte((caddr_t)f->f_wb3a, f->f_wb3d); 75153933Shibler break; 75253933Shibler case SSW4_SZW: 75353933Shibler if (KDFAULT(f->f_wb3s)) 75453933Shibler *(short *)f->f_wb3a = f->f_wb3d; 75553933Shibler else 75653933Shibler err = susword((caddr_t)f->f_wb3a, f->f_wb3d); 75753933Shibler break; 75853933Shibler #ifdef DEBUG 75953933Shibler case SSW4_SZLN: 76053933Shibler panic("writeback: wb3s indicates LINE write"); 76153933Shibler #endif 76253933Shibler } 76353933Shibler if (err) { 76453933Shibler fa = f->f_wb3a; 76553933Shibler #ifdef DEBUG 76653933Shibler if (mmudebug & MDB_WBFAILED) 76753933Shibler printf(wberrstr, p->p_pid, p->p_comm, 76853933Shibler "#3", fp->f_pc, f->f_fa, 76953933Shibler f->f_wb3a, f->f_wb3d); 77053933Shibler #endif 77153933Shibler } 77253933Shibler } 77353933Shibler p->p_addr->u_pcb.pcb_onfault = oonfault; 77453933Shibler /* 77553933Shibler * Determine the cause of the failure if any translating to 77653933Shibler * a signal. If the corresponding VA is valid and RO it is 77753933Shibler * a protection fault (SIGBUS) otherwise consider it an 77853933Shibler * illegal reference (SIGSEGV). 77953933Shibler */ 78053933Shibler if (err) { 78153933Shibler if (vm_map_check_protection(&p->p_vmspace->vm_map, 78253933Shibler trunc_page(fa), round_page(fa), 78353933Shibler VM_PROT_READ) && 78453933Shibler !vm_map_check_protection(&p->p_vmspace->vm_map, 78553933Shibler trunc_page(fa), round_page(fa), 78653933Shibler VM_PROT_WRITE)) 78753933Shibler err = SIGBUS; 78853933Shibler else 78953933Shibler err = SIGSEGV; 79053933Shibler } 79153933Shibler return(err); 79253933Shibler } 79353933Shibler 79453933Shibler #ifdef DEBUG 79553933Shibler dumpssw(ssw) 79653933Shibler register u_short ssw; 79753933Shibler { 79853933Shibler printf(" SSW: %x: ", ssw); 79953933Shibler if (ssw & SSW4_CP) 80053933Shibler printf("CP,"); 80153933Shibler if (ssw & SSW4_CU) 80253933Shibler printf("CU,"); 80353933Shibler if (ssw & SSW4_CT) 80453933Shibler printf("CT,"); 80553933Shibler if (ssw & SSW4_CM) 80653933Shibler printf("CM,"); 80753933Shibler if (ssw & SSW4_MA) 80853933Shibler printf("MA,"); 80953933Shibler if (ssw & SSW4_ATC) 81053933Shibler printf("ATC,"); 81153933Shibler if (ssw & SSW4_LK) 81253933Shibler printf("LK,"); 81353933Shibler if (ssw & SSW4_RW) 81453933Shibler printf("RW,"); 81553933Shibler printf(" SZ=%s, TT=%s, TM=%s\n", 81653933Shibler f7sz[(ssw & SSW4_SZMASK) >> 5], 81753933Shibler f7tt[(ssw & SSW4_TTMASK) >> 3], 81853933Shibler f7tm[ssw & SSW4_TMMASK]); 81953933Shibler } 82053933Shibler 82153933Shibler dumpwb(num, s, a, d) 82253933Shibler int num; 82353933Shibler u_short s; 82453933Shibler u_int a, d; 82553933Shibler { 82653933Shibler register struct proc *p = curproc; 82753933Shibler vm_offset_t pa; 82853933Shibler 82953933Shibler printf(" writeback #%d: VA %x, data %x, SZ=%s, TT=%s, TM=%s\n", 83053933Shibler num, a, d, f7sz[(s & SSW4_SZMASK) >> 5], 83153933Shibler f7tt[(s & SSW4_TTMASK) >> 3], f7tm[s & SSW4_TMMASK]); 83253933Shibler printf(" PA "); 83353933Shibler pa = pmap_extract(&p->p_vmspace->vm_pmap, (vm_offset_t)a); 83453933Shibler if (pa == 0) 83553933Shibler printf("<invalid address>"); 83653933Shibler else 83753933Shibler printf("%x, current value %x", pa, fuword((caddr_t)a)); 83853933Shibler printf("\n"); 83953933Shibler } 84053933Shibler #endif 84153933Shibler #endif 84253933Shibler 84341475Smckusick /* 84449531Skarels * Proces a system call. 84541475Smckusick */ 84641475Smckusick syscall(code, frame) 84754801Storek u_int code; 84841475Smckusick struct frame frame; 84941475Smckusick { 85041475Smckusick register caddr_t params; 85141475Smckusick register struct sysent *callp; 85254801Storek register struct proc *p; 85350753Skarels int error, opc, numsys, s; 85454801Storek u_int argsize; 85544018Skarels struct args { 85644018Skarels int i[8]; 85744018Skarels } args; 85844018Skarels int rval[2]; 85954801Storek u_quad_t sticks; 86041475Smckusick #ifdef HPUXCOMPAT 86141475Smckusick extern struct sysent hpuxsysent[]; 86241475Smckusick extern int hpuxnsysent, notimp(); 86341475Smckusick #endif 86441475Smckusick 86541475Smckusick cnt.v_syscall++; 86641475Smckusick if (!USERMODE(frame.f_sr)) 86741475Smckusick panic("syscall"); 86854801Storek p = curproc; 86954801Storek sticks = p->p_sticks; 87052380Smckusick p->p_md.md_regs = frame.f_regs; 87141475Smckusick opc = frame.f_pc - 2; 87241475Smckusick #ifdef HPUXCOMPAT 87357344Shibler if (p->p_md.md_flags & MDP_HPUX) 87454801Storek callp = hpuxsysent, numsys = hpuxnsysent; 87554801Storek else 87641475Smckusick #endif 87754801Storek callp = sysent, numsys = nsysent; 87849531Skarels params = (caddr_t)frame.f_regs[SP] + sizeof(int); 87954801Storek switch (code) { 88054801Storek 88163469Smckusick case SYS_syscall: 88254801Storek /* 88354801Storek * Code is first argument, followed by actual args. 88454801Storek */ 88542370Skarels code = fuword(params); 88649531Skarels params += sizeof(int); 88757344Shibler /* 88857344Shibler * XXX sigreturn requires special stack manipulation 88957344Shibler * that is only done if entered via the sigreturn 89057344Shibler * trap. Cannot allow it here so make sure we fail. 89157344Shibler */ 89257344Shibler if (code == SYS_sigreturn) 89357344Shibler code = numsys; 89454801Storek break; 89554801Storek 89663469Smckusick case SYS___syscall: 89754801Storek /* 89863469Smckusick * Like syscall, but code is a quad, so as to maintain 89954801Storek * quad alignment for the rest of the arguments. 90054801Storek */ 90141475Smckusick #ifdef HPUXCOMPAT 90257344Shibler if (p->p_md.md_flags & MDP_HPUX) 90354801Storek break; 90441475Smckusick #endif 90554865Smckusick code = fuword(params + _QUAD_LOWWORD * sizeof(int)); 90654865Smckusick params += sizeof(quad_t); 90754801Storek break; 90854801Storek 90954865Smckusick default: 91054865Smckusick /* nothing to do by default */ 91154865Smckusick break; 91254801Storek } 91354801Storek if (code < numsys) 91454801Storek callp += code; 91554801Storek else 91663469Smckusick callp += SYS_syscall; /* => nosys */ 91754801Storek argsize = callp->sy_narg * sizeof(int); 91854801Storek if (argsize && (error = copyin(params, (caddr_t)&args, argsize))) { 91941475Smckusick #ifdef KTRACE 92043641Skarels if (KTRPOINT(p, KTR_SYSCALL)) 92144018Skarels ktrsyscall(p->p_tracep, code, callp->sy_narg, args.i); 92241475Smckusick #endif 92354801Storek goto bad; 92441475Smckusick } 92541475Smckusick #ifdef KTRACE 92643641Skarels if (KTRPOINT(p, KTR_SYSCALL)) 92744018Skarels ktrsyscall(p->p_tracep, code, callp->sy_narg, args.i); 92841475Smckusick #endif 92943641Skarels rval[0] = 0; 93043641Skarels rval[1] = frame.f_regs[D1]; 93141475Smckusick #ifdef HPUXCOMPAT 93242370Skarels /* debug kludge */ 93342370Skarels if (callp->sy_call == notimp) 93448465Skarels error = notimp(p, args.i, rval, code, callp->sy_narg); 93542370Skarels else 93641475Smckusick #endif 93754801Storek error = (*callp->sy_call)(p, &args, rval); 93854801Storek switch (error) { 93942370Skarels 94054801Storek case 0: 94141475Smckusick /* 94254801Storek * Reinitialize proc pointer `p' as it may be different 94354801Storek * if this is a child returning from fork syscall. 94441475Smckusick */ 94554801Storek p = curproc; 94654801Storek frame.f_regs[D0] = rval[0]; 94754801Storek frame.f_regs[D1] = rval[1]; 94854801Storek frame.f_sr &= ~PSL_C; 94954801Storek break; 95041475Smckusick 95154801Storek case ERESTART: 95254801Storek frame.f_pc = opc; 95354801Storek break; 95454801Storek 95554801Storek case EJUSTRETURN: 95654801Storek break; /* nothing to do */ 95754801Storek 95854801Storek default: 95954801Storek bad: 96054801Storek #ifdef HPUXCOMPAT 96157344Shibler if (p->p_md.md_flags & MDP_HPUX) 96254801Storek error = bsdtohpuxerrno(error); 96341475Smckusick #endif 96454801Storek frame.f_regs[D0] = error; 96554801Storek frame.f_sr |= PSL_C; 96654801Storek break; 96741475Smckusick } 96854801Storek 96954801Storek userret(p, &frame, sticks, (u_int)0, 0); 97041475Smckusick #ifdef KTRACE 97143641Skarels if (KTRPOINT(p, KTR_SYSRET)) 97243641Skarels ktrsysret(p->p_tracep, code, error, rval[0]); 97341475Smckusick #endif 97441475Smckusick } 975