141475Smckusick /* 241475Smckusick * Copyright (c) 1988 University of Utah. 363472Sbostic * Copyright (c) 1982, 1986, 1990, 1993 463472Sbostic * 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*65483Sbostic * @(#)trap.c 8.5 (Berkeley) 01/04/94 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) 12364615Sbostic postsig(sig); 12464615Sbostic p->p_priority = 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.) 13064542Sbostic * If that happened after we put ourselves on the run queue 13164615Sbostic * but before we mi_switch()'ed, we might not be on the queue 13264542Sbostic * indicated by our priority. 13354801Storek */ 13454801Storek s = splstatclock(); 13564542Sbostic setrunqueue(p); 13654801Storek p->p_stats->p_ru.ru_nivcsw++; 13764615Sbostic mi_switch(); 13854801Storek splx(s); 13954801Storek while ((sig = CURSIG(p)) != 0) 14064615Sbostic postsig(sig); 14154801Storek } 14254801Storek 14354801Storek /* 14454801Storek * If profiling, charge system time to the trapped pc. 14554801Storek */ 14664615Sbostic if (p->p_flag & P_PROFIL) { 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 17864615Sbostic curpriority = p->p_priority; 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 { 193*65483Sbostic extern char fswintr[]; 194*65483Sbostic register struct proc *p; 19541475Smckusick register int i; 196*65483Sbostic u_int ucode; 19754801Storek u_quad_t sticks; 19841475Smckusick 19941475Smckusick cnt.v_trap++; 20054801Storek p = curproc; 20154801Storek ucode = 0; 20241475Smckusick if (USERMODE(frame.f_sr)) { 20349531Skarels type |= T_USER; 20454801Storek sticks = p->p_sticks; 20552380Smckusick p->p_md.md_regs = frame.f_regs; 20641475Smckusick } 20741475Smckusick switch (type) { 20841475Smckusick 20941475Smckusick default: 21041475Smckusick dopanic: 21141475Smckusick printf("trap type %d, code = %x, v = %x\n", type, code, v); 21257344Shibler regdump(&frame, 128); 21349531Skarels type &= ~T_USER; 21441475Smckusick if ((unsigned)type < TRAP_TYPES) 21541475Smckusick panic(trap_type[type]); 21641475Smckusick panic("trap"); 21741475Smckusick 21841475Smckusick case T_BUSERR: /* kernel bus error */ 21949125Skarels if (!p->p_addr->u_pcb.pcb_onfault) 22041475Smckusick goto dopanic; 22141475Smckusick /* 22241475Smckusick * If we have arranged to catch this fault in any of the 22341475Smckusick * copy to/from user space routines, set PC to return to 22441475Smckusick * indicated location and set flag informing buserror code 22541475Smckusick * that it may need to clean up stack frame. 22641475Smckusick */ 22741475Smckusick copyfault: 22849317Shibler frame.f_stackadj = exframesize[frame.f_format]; 22949317Shibler frame.f_format = frame.f_vector = 0; 23049125Skarels frame.f_pc = (int) p->p_addr->u_pcb.pcb_onfault; 23141475Smckusick return; 23241475Smckusick 23349531Skarels case T_BUSERR|T_USER: /* bus error */ 23449531Skarels case T_ADDRERR|T_USER: /* address error */ 23553933Shibler ucode = v; 23641475Smckusick i = SIGBUS; 23741475Smckusick break; 23841475Smckusick 23941475Smckusick #ifdef FPCOPROC 24041475Smckusick case T_COPERR: /* kernel coprocessor violation */ 24141475Smckusick #endif 24253933Shibler case T_FMTERR|T_USER: /* do all RTE errors come in as T_USER? */ 24353933Shibler case T_FMTERR: /* ...just in case... */ 24441475Smckusick /* 24541475Smckusick * The user has most likely trashed the RTE or FP state info 24641475Smckusick * in the stack frame of a signal handler. 24741475Smckusick */ 24849531Skarels type |= T_USER; 24948465Skarels printf("pid %d: kernel %s exception\n", p->p_pid, 25041475Smckusick type==T_COPERR ? "coprocessor" : "format"); 25148465Skarels p->p_sigacts->ps_sigact[SIGILL] = SIG_DFL; 25241475Smckusick i = sigmask(SIGILL); 25341475Smckusick p->p_sigignore &= ~i; 25441475Smckusick p->p_sigcatch &= ~i; 25541475Smckusick p->p_sigmask &= ~i; 25642370Skarels i = SIGILL; 25741475Smckusick ucode = frame.f_format; /* XXX was ILL_RESAD_FAULT */ 25842370Skarels break; 25941475Smckusick 26041475Smckusick #ifdef FPCOPROC 26149531Skarels case T_COPERR|T_USER: /* user coprocessor violation */ 26241475Smckusick /* What is a proper response here? */ 26341475Smckusick ucode = 0; 26441475Smckusick i = SIGFPE; 26541475Smckusick break; 26641475Smckusick 26749531Skarels case T_FPERR|T_USER: /* 68881 exceptions */ 26841475Smckusick /* 26941475Smckusick * We pass along the 68881 status register which locore stashed 27041475Smckusick * in code for us. Note that there is a possibility that the 27141475Smckusick * bit pattern of this register will conflict with one of the 27241475Smckusick * FPE_* codes defined in signal.h. Fortunately for us, the 27341475Smckusick * only such codes we use are all in the range 1-7 and the low 27441475Smckusick * 3 bits of the status register are defined as 0 so there is 27541475Smckusick * no clash. 27641475Smckusick */ 27741475Smckusick ucode = code; 27841475Smckusick i = SIGFPE; 27941475Smckusick break; 28041475Smckusick #endif 28141475Smckusick 28254801Storek #ifdef HP380 28353933Shibler case T_FPEMULI|T_USER: /* unimplemented FP instuction */ 28453933Shibler case T_FPEMULD|T_USER: /* unimplemented FP data type */ 28553933Shibler /* XXX need to FSAVE */ 28653933Shibler printf("pid %d(%s): unimplemented FP %s at %x (EA %x)\n", 28753933Shibler p->p_pid, p->p_comm, 28853933Shibler frame.f_format == 2 ? "instruction" : "data type", 28953933Shibler frame.f_pc, frame.f_fmt2.f_iaddr); 29053933Shibler /* XXX need to FRESTORE */ 29153933Shibler i = SIGFPE; 29253933Shibler break; 29353933Shibler #endif 29453933Shibler 29549531Skarels case T_ILLINST|T_USER: /* illegal instruction fault */ 29641475Smckusick #ifdef HPUXCOMPAT 29757344Shibler if (p->p_md.md_flags & MDP_HPUX) { 29841475Smckusick ucode = HPUX_ILL_ILLINST_TRAP; 29941475Smckusick i = SIGILL; 30041475Smckusick break; 30141475Smckusick } 30241475Smckusick /* fall through */ 30341475Smckusick #endif 30449531Skarels case T_PRIVINST|T_USER: /* privileged instruction fault */ 30541475Smckusick #ifdef HPUXCOMPAT 30657344Shibler if (p->p_md.md_flags & MDP_HPUX) 30741475Smckusick ucode = HPUX_ILL_PRIV_TRAP; 30841475Smckusick else 30941475Smckusick #endif 31041475Smckusick ucode = frame.f_format; /* XXX was ILL_PRIVIN_FAULT */ 31141475Smckusick i = SIGILL; 31241475Smckusick break; 31341475Smckusick 31449531Skarels case T_ZERODIV|T_USER: /* Divide by zero */ 31541475Smckusick #ifdef HPUXCOMPAT 31657344Shibler if (p->p_md.md_flags & MDP_HPUX) 31741475Smckusick ucode = HPUX_FPE_INTDIV_TRAP; 31841475Smckusick else 31941475Smckusick #endif 32041475Smckusick ucode = frame.f_format; /* XXX was FPE_INTDIV_TRAP */ 32141475Smckusick i = SIGFPE; 32241475Smckusick break; 32341475Smckusick 32449531Skarels case T_CHKINST|T_USER: /* CHK instruction trap */ 32541475Smckusick #ifdef HPUXCOMPAT 32657344Shibler if (p->p_md.md_flags & MDP_HPUX) { 32741475Smckusick /* handled differently under hp-ux */ 32841475Smckusick i = SIGILL; 32941475Smckusick ucode = HPUX_ILL_CHK_TRAP; 33041475Smckusick break; 33141475Smckusick } 33241475Smckusick #endif 33341475Smckusick ucode = frame.f_format; /* XXX was FPE_SUBRNG_TRAP */ 33441475Smckusick i = SIGFPE; 33541475Smckusick break; 33641475Smckusick 33749531Skarels case T_TRAPVINST|T_USER: /* TRAPV instruction trap */ 33841475Smckusick #ifdef HPUXCOMPAT 33957344Shibler if (p->p_md.md_flags & MDP_HPUX) { 34041475Smckusick /* handled differently under hp-ux */ 34141475Smckusick i = SIGILL; 34241475Smckusick ucode = HPUX_ILL_TRAPV_TRAP; 34341475Smckusick break; 34441475Smckusick } 34541475Smckusick #endif 34641475Smckusick ucode = frame.f_format; /* XXX was FPE_INTOVF_TRAP */ 34741475Smckusick i = SIGFPE; 34841475Smckusick break; 34941475Smckusick 35041475Smckusick /* 35141475Smckusick * XXX: Trace traps are a nightmare. 35241475Smckusick * 35341475Smckusick * HP-UX uses trap #1 for breakpoints, 35441475Smckusick * HPBSD uses trap #2, 35541475Smckusick * SUN 3.x uses trap #15, 35648465Skarels * KGDB uses trap #15 (for kernel breakpoints; handled elsewhere). 35741475Smckusick * 35841475Smckusick * HPBSD and HP-UX traps both get mapped by locore.s into T_TRACE. 35941475Smckusick * SUN 3.x traps get passed through as T_TRAP15 and are not really 36048465Skarels * supported yet. 36141475Smckusick */ 36241475Smckusick case T_TRACE: /* kernel trace trap */ 36348465Skarels case T_TRAP15: /* SUN trace trap */ 36441475Smckusick frame.f_sr &= ~PSL_T; 36541475Smckusick i = SIGTRAP; 36641475Smckusick break; 36741475Smckusick 36849531Skarels case T_TRACE|T_USER: /* user trace trap */ 36949531Skarels case T_TRAP15|T_USER: /* SUN user trace trap */ 37041475Smckusick frame.f_sr &= ~PSL_T; 37141475Smckusick i = SIGTRAP; 37241475Smckusick break; 37341475Smckusick 37443413Shibler case T_ASTFLT: /* system async trap, cannot happen */ 37541475Smckusick goto dopanic; 37641475Smckusick 37749531Skarels case T_ASTFLT|T_USER: /* user async trap */ 37849125Skarels astpending = 0; 37941475Smckusick /* 38041475Smckusick * We check for software interrupts first. This is because 38141475Smckusick * they are at a higher level than ASTs, and on a VAX would 38241475Smckusick * interrupt the AST. We assume that if we are processing 38341475Smckusick * an AST that we must be at IPL0 so we don't bother to 38441475Smckusick * check. Note that we ensure that we are at least at SIR 38541475Smckusick * IPL while processing the SIR. 38641475Smckusick */ 38741475Smckusick spl1(); 38841475Smckusick /* fall into... */ 38941475Smckusick 39041475Smckusick case T_SSIR: /* software interrupt */ 39149531Skarels case T_SSIR|T_USER: 39241475Smckusick if (ssir & SIR_NET) { 39341475Smckusick siroff(SIR_NET); 39441475Smckusick cnt.v_soft++; 39541475Smckusick netintr(); 39641475Smckusick } 39741475Smckusick if (ssir & SIR_CLOCK) { 39841475Smckusick siroff(SIR_CLOCK); 39941475Smckusick cnt.v_soft++; 40054801Storek softclock(); 40141475Smckusick } 40241475Smckusick /* 40341475Smckusick * If this was not an AST trap, we are all done. 40441475Smckusick */ 40550753Skarels if (type != (T_ASTFLT|T_USER)) { 40641475Smckusick cnt.v_trap--; 40741475Smckusick return; 40841475Smckusick } 40941475Smckusick spl0(); 41064615Sbostic if (p->p_flag & P_OWEUPC) { 41164615Sbostic p->p_flag &= ~P_OWEUPC; 41254801Storek ADDUPROF(p); 41341475Smckusick } 41441475Smckusick goto out; 41541475Smckusick 41641475Smckusick case T_MMUFLT: /* kernel mode page fault */ 41754574Storek /* 41854574Storek * If we were doing profiling ticks or other user mode 41954574Storek * stuff from interrupt code, Just Say No. 42054574Storek */ 42154574Storek if (p->p_addr->u_pcb.pcb_onfault == fswintr) 42254574Storek goto copyfault; 42341475Smckusick /* fall into ... */ 42441475Smckusick 42549531Skarels case T_MMUFLT|T_USER: /* page fault */ 42645751Smckusick { 42745751Smckusick register vm_offset_t va; 42848465Skarels register struct vmspace *vm = p->p_vmspace; 42945751Smckusick register vm_map_t map; 43045751Smckusick int rv; 43145751Smckusick vm_prot_t ftype; 43245751Smckusick extern vm_map_t kernel_map; 43345751Smckusick 43453933Shibler #ifdef DEBUG 43553933Shibler if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid)) 43653933Shibler printf("trap: T_MMUFLT pid=%d, code=%x, v=%x, pc=%x, sr=%x\n", 43753933Shibler p->p_pid, code, v, frame.f_pc, frame.f_sr); 43853933Shibler #endif 43941475Smckusick /* 44045751Smckusick * It is only a kernel address space fault iff: 44149531Skarels * 1. (type & T_USER) == 0 and 44245751Smckusick * 2. pcb_onfault not set or 44345751Smckusick * 3. pcb_onfault set but supervisor space data fault 44445751Smckusick * The last can occur during an exec() copyin where the 44545751Smckusick * argument space is lazy-allocated. 44641475Smckusick */ 44745751Smckusick if (type == T_MMUFLT && 44853933Shibler (!p->p_addr->u_pcb.pcb_onfault || KDFAULT(code))) 44945751Smckusick map = kernel_map; 45045751Smckusick else 45148465Skarels map = &vm->vm_map; 45253933Shibler if (WRFAULT(code)) 45345751Smckusick ftype = VM_PROT_READ | VM_PROT_WRITE; 45445751Smckusick else 45545751Smckusick ftype = VM_PROT_READ; 45645751Smckusick va = trunc_page((vm_offset_t)v); 45741475Smckusick #ifdef DEBUG 45845751Smckusick if (map == kernel_map && va == 0) { 45945751Smckusick printf("trap: bad kernel access at %x\n", v); 46041475Smckusick goto dopanic; 46141475Smckusick } 46241475Smckusick #endif 46357344Shibler #ifdef HPUXCOMPAT 46457344Shibler if (ISHPMMADDR(va)) { 46557344Shibler vm_offset_t bva; 46657344Shibler 46757344Shibler rv = pmap_mapmulti(map->pmap, va); 46857344Shibler if (rv != KERN_SUCCESS) { 46957344Shibler bva = HPMMBASEADDR(va); 47057344Shibler rv = vm_fault(map, bva, ftype, FALSE); 47157344Shibler if (rv == KERN_SUCCESS) 47257344Shibler (void) pmap_mapmulti(map->pmap, va); 47357344Shibler } 47457344Shibler } else 47557344Shibler #endif 47649317Shibler rv = vm_fault(map, va, ftype, FALSE); 47753933Shibler #ifdef DEBUG 47853933Shibler if (rv && MDB_ISPID(p->p_pid)) 47953933Shibler printf("vm_fault(%x, %x, %x, 0) -> %x\n", 48053933Shibler map, va, ftype, rv); 48153933Shibler #endif 48241475Smckusick /* 48349317Shibler * If this was a stack access we keep track of the maximum 48449317Shibler * accessed stack size. Also, if vm_fault gets a protection 48549317Shibler * failure it is due to accessing the stack region outside 48649317Shibler * the current limit and we need to reflect that as an access 48749317Shibler * error. 48841475Smckusick */ 48948465Skarels if ((caddr_t)va >= vm->vm_maxsaddr && map != kernel_map) { 49049317Shibler if (rv == KERN_SUCCESS) { 49149317Shibler unsigned nss; 49249317Shibler 49349317Shibler nss = clrnd(btoc(USRSTACK-(unsigned)va)); 49449317Shibler if (nss > vm->vm_ssize) 49549317Shibler vm->vm_ssize = nss; 49649317Shibler } else if (rv == KERN_PROTECTION_FAILURE) 49749317Shibler rv = KERN_INVALID_ADDRESS; 49841475Smckusick } 49945751Smckusick if (rv == KERN_SUCCESS) { 50053933Shibler if (type == T_MMUFLT) { 50154801Storek #ifdef HP380 50253933Shibler if (mmutype == MMU_68040) 50353933Shibler (void) writeback(&frame, 1); 50453933Shibler #endif 50541475Smckusick return; 50653933Shibler } 50741475Smckusick goto out; 50841475Smckusick } 50945751Smckusick if (type == T_MMUFLT) { 51049125Skarels if (p->p_addr->u_pcb.pcb_onfault) 51145751Smckusick goto copyfault; 51245751Smckusick printf("vm_fault(%x, %x, %x, 0) -> %x\n", 51345751Smckusick map, va, ftype, rv); 51445751Smckusick printf(" type %x, code [mmu,,ssw]: %x\n", 51545751Smckusick type, code); 51645751Smckusick goto dopanic; 51745751Smckusick } 51848465Skarels ucode = v; 51945751Smckusick i = (rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV; 52045751Smckusick break; 52145751Smckusick } 52241475Smckusick } 52348465Skarels trapsignal(p, i, ucode); 52449531Skarels if ((type & T_USER) == 0) 52541475Smckusick return; 52641475Smckusick out: 52754801Storek userret(p, &frame, sticks, v, 1); 52841475Smckusick } 52941475Smckusick 53054801Storek #ifdef HP380 53153933Shibler #ifdef DEBUG 53253933Shibler struct writebackstats { 53353933Shibler int calls; 53453933Shibler int cpushes; 53553933Shibler int move16s; 53653933Shibler int wb1s, wb2s, wb3s; 53753933Shibler int wbsize[4]; 53853933Shibler } wbstats; 53953933Shibler 54053933Shibler char *f7sz[] = { "longword", "byte", "word", "line" }; 54153933Shibler char *f7tt[] = { "normal", "MOVE16", "AFC", "ACK" }; 54253933Shibler char *f7tm[] = { "d-push", "u-data", "u-code", "M-data", 54353933Shibler "M-code", "k-data", "k-code", "RES" }; 54453933Shibler char wberrstr[] = 54553933Shibler "WARNING: pid %d(%s) writeback [%s] failed, pc=%x fa=%x wba=%x wbd=%x\n"; 54653933Shibler #endif 54753933Shibler 54853933Shibler writeback(fp, docachepush) 54953933Shibler struct frame *fp; 55053933Shibler int docachepush; 55153933Shibler { 55253933Shibler register struct fmt7 *f = &fp->f_fmt7; 55353933Shibler register struct proc *p = curproc; 55453933Shibler int err = 0; 55553933Shibler u_int fa; 55653933Shibler caddr_t oonfault = p->p_addr->u_pcb.pcb_onfault; 55753933Shibler 55853933Shibler #ifdef DEBUG 55953933Shibler if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid)) { 56053933Shibler printf(" pid=%d, fa=%x,", p->p_pid, f->f_fa); 56153933Shibler dumpssw(f->f_ssw); 56253933Shibler } 56353933Shibler wbstats.calls++; 56453933Shibler #endif 56553933Shibler /* 56653933Shibler * Deal with special cases first. 56753933Shibler */ 56853933Shibler if ((f->f_ssw & SSW4_TMMASK) == SSW4_TMDCP) { 56953933Shibler /* 57053933Shibler * Dcache push fault. 57153933Shibler * Line-align the address and write out the push data to 57253933Shibler * the indicated physical address. 57353933Shibler */ 57453933Shibler #ifdef DEBUG 57553933Shibler if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid)) { 57653933Shibler printf(" pushing %s to PA %x, data %x", 57753933Shibler f7sz[(f->f_ssw & SSW4_SZMASK) >> 5], 57853933Shibler f->f_fa, f->f_pd0); 57953933Shibler if ((f->f_ssw & SSW4_SZMASK) == SSW4_SZLN) 58053933Shibler printf("/%x/%x/%x", 58153933Shibler f->f_pd1, f->f_pd2, f->f_pd3); 58253933Shibler printf("\n"); 58353933Shibler } 58453933Shibler if (f->f_wb1s & SSW4_WBSV) 58553933Shibler panic("writeback: cache push with WB1S valid"); 58653933Shibler wbstats.cpushes++; 58753933Shibler #endif 58853933Shibler /* 58953933Shibler * XXX there are security problems if we attempt to do a 59053933Shibler * cache push after a signal handler has been called. 59153933Shibler */ 59253933Shibler if (docachepush) { 59353933Shibler pmap_enter(kernel_pmap, (vm_offset_t)vmmap, 59453933Shibler trunc_page(f->f_fa), VM_PROT_WRITE, TRUE); 59553933Shibler fa = (u_int)&vmmap[(f->f_fa & PGOFSET) & ~0xF]; 59653933Shibler bcopy((caddr_t)&f->f_pd0, (caddr_t)fa, 16); 59753933Shibler DCFL(pmap_extract(kernel_pmap, (vm_offset_t)fa)); 59853933Shibler pmap_remove(kernel_pmap, (vm_offset_t)vmmap, 59953933Shibler (vm_offset_t)&vmmap[NBPG]); 60053933Shibler } else 60153933Shibler printf("WARNING: pid %d(%s) uid %d: CPUSH not done\n", 60253933Shibler p->p_pid, p->p_comm, p->p_ucred->cr_uid); 60353933Shibler } else if ((f->f_ssw & (SSW4_RW|SSW4_TTMASK)) == SSW4_TTM16) { 60453933Shibler /* 60553933Shibler * MOVE16 fault. 60653933Shibler * Line-align the address and write out the push data to 60753933Shibler * the indicated virtual address. 60853933Shibler */ 60953933Shibler #ifdef DEBUG 61053933Shibler if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid)) 61153933Shibler printf(" MOVE16 to VA %x(%x), data %x/%x/%x/%x\n", 61253933Shibler f->f_fa, f->f_fa & ~0xF, f->f_pd0, f->f_pd1, 61353933Shibler f->f_pd2, f->f_pd3); 61453933Shibler if (f->f_wb1s & SSW4_WBSV) 61553933Shibler panic("writeback: MOVE16 with WB1S valid"); 61653933Shibler wbstats.move16s++; 61753933Shibler #endif 61853933Shibler if (KDFAULT(f->f_wb1s)) 61953933Shibler bcopy((caddr_t)&f->f_pd0, (caddr_t)(f->f_fa & ~0xF), 16); 62053933Shibler else 62153933Shibler err = suline((caddr_t)(f->f_fa & ~0xF), (caddr_t)&f->f_pd0); 62253933Shibler if (err) { 62353933Shibler fa = f->f_fa & ~0xF; 62453933Shibler #ifdef DEBUG 62553933Shibler if (mmudebug & MDB_WBFAILED) 62653933Shibler printf(wberrstr, p->p_pid, p->p_comm, 62753933Shibler "MOVE16", fp->f_pc, f->f_fa, 62853933Shibler f->f_fa & ~0xF, f->f_pd0); 62953933Shibler #endif 63053933Shibler } 63153933Shibler } else if (f->f_wb1s & SSW4_WBSV) { 63253933Shibler /* 63353933Shibler * Writeback #1. 63453933Shibler * Position the "memory-aligned" data and write it out. 63553933Shibler */ 63653933Shibler register u_int wb1d = f->f_wb1d; 63753933Shibler register int off; 63853933Shibler 63953933Shibler #ifdef DEBUG 64053933Shibler if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid)) 64153933Shibler dumpwb(1, f->f_wb1s, f->f_wb1a, f->f_wb1d); 64253933Shibler wbstats.wb1s++; 64353933Shibler wbstats.wbsize[(f->f_wb2s&SSW4_SZMASK)>>5]++; 64453933Shibler #endif 64553933Shibler off = (f->f_wb1a & 3) * 8; 64653933Shibler switch (f->f_wb1s & SSW4_SZMASK) { 64753933Shibler case SSW4_SZLW: 64853933Shibler if (off) 64953933Shibler wb1d = (wb1d >> (32 - off)) | (wb1d << off); 65053933Shibler if (KDFAULT(f->f_wb1s)) 65153933Shibler *(long *)f->f_wb1a = wb1d; 65253933Shibler else 65353933Shibler err = suword((caddr_t)f->f_wb1a, wb1d); 65453933Shibler break; 65553933Shibler case SSW4_SZB: 65653933Shibler off = 24 - off; 65753933Shibler if (off) 65853933Shibler wb1d >>= off; 65953933Shibler if (KDFAULT(f->f_wb1s)) 66053933Shibler *(char *)f->f_wb1a = wb1d; 66153933Shibler else 66253933Shibler err = subyte((caddr_t)f->f_wb1a, wb1d); 66353933Shibler break; 66453933Shibler case SSW4_SZW: 66553933Shibler off = (off + 16) % 32; 66653933Shibler if (off) 66753933Shibler wb1d = (wb1d >> (32 - off)) | (wb1d << off); 66853933Shibler if (KDFAULT(f->f_wb1s)) 66953933Shibler *(short *)f->f_wb1a = wb1d; 67053933Shibler else 67153933Shibler err = susword((caddr_t)f->f_wb1a, wb1d); 67253933Shibler break; 67353933Shibler } 67453933Shibler if (err) { 67553933Shibler fa = f->f_wb1a; 67653933Shibler #ifdef DEBUG 67753933Shibler if (mmudebug & MDB_WBFAILED) 67853933Shibler printf(wberrstr, p->p_pid, p->p_comm, 67953933Shibler "#1", fp->f_pc, f->f_fa, 68053933Shibler f->f_wb1a, f->f_wb1d); 68153933Shibler #endif 68253933Shibler } 68353933Shibler } 68453933Shibler /* 68553933Shibler * Deal with the "normal" writebacks. 68653933Shibler * 68753933Shibler * XXX writeback2 is known to reflect a LINE size writeback after 68853933Shibler * a MOVE16 was already dealt with above. Ignore it. 68953933Shibler */ 69053933Shibler if (err == 0 && (f->f_wb2s & SSW4_WBSV) && 69153933Shibler (f->f_wb2s & SSW4_SZMASK) != SSW4_SZLN) { 69253933Shibler #ifdef DEBUG 69353933Shibler if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid)) 69453933Shibler dumpwb(2, f->f_wb2s, f->f_wb2a, f->f_wb2d); 69553933Shibler wbstats.wb2s++; 69653933Shibler wbstats.wbsize[(f->f_wb2s&SSW4_SZMASK)>>5]++; 69753933Shibler #endif 69853933Shibler switch (f->f_wb2s & SSW4_SZMASK) { 69953933Shibler case SSW4_SZLW: 70053933Shibler if (KDFAULT(f->f_wb2s)) 70153933Shibler *(long *)f->f_wb2a = f->f_wb2d; 70253933Shibler else 70353933Shibler err = suword((caddr_t)f->f_wb2a, f->f_wb2d); 70453933Shibler break; 70553933Shibler case SSW4_SZB: 70653933Shibler if (KDFAULT(f->f_wb2s)) 70753933Shibler *(char *)f->f_wb2a = f->f_wb2d; 70853933Shibler else 70953933Shibler err = subyte((caddr_t)f->f_wb2a, f->f_wb2d); 71053933Shibler break; 71153933Shibler case SSW4_SZW: 71253933Shibler if (KDFAULT(f->f_wb2s)) 71353933Shibler *(short *)f->f_wb2a = f->f_wb2d; 71453933Shibler else 71553933Shibler err = susword((caddr_t)f->f_wb2a, f->f_wb2d); 71653933Shibler break; 71753933Shibler } 71853933Shibler if (err) { 71953933Shibler fa = f->f_wb2a; 72053933Shibler #ifdef DEBUG 72153933Shibler if (mmudebug & MDB_WBFAILED) { 72253933Shibler printf(wberrstr, p->p_pid, p->p_comm, 72353933Shibler "#2", fp->f_pc, f->f_fa, 72453933Shibler f->f_wb2a, f->f_wb2d); 72553933Shibler dumpssw(f->f_ssw); 72653933Shibler dumpwb(2, f->f_wb2s, f->f_wb2a, f->f_wb2d); 72753933Shibler } 72853933Shibler #endif 72953933Shibler } 73053933Shibler } 73153933Shibler if (err == 0 && (f->f_wb3s & SSW4_WBSV)) { 73253933Shibler #ifdef DEBUG 73353933Shibler if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid)) 73453933Shibler dumpwb(3, f->f_wb3s, f->f_wb3a, f->f_wb3d); 73553933Shibler wbstats.wb3s++; 73653933Shibler wbstats.wbsize[(f->f_wb3s&SSW4_SZMASK)>>5]++; 73753933Shibler #endif 73853933Shibler switch (f->f_wb3s & SSW4_SZMASK) { 73953933Shibler case SSW4_SZLW: 74053933Shibler if (KDFAULT(f->f_wb3s)) 74153933Shibler *(long *)f->f_wb3a = f->f_wb3d; 74253933Shibler else 74353933Shibler err = suword((caddr_t)f->f_wb3a, f->f_wb3d); 74453933Shibler break; 74553933Shibler case SSW4_SZB: 74653933Shibler if (KDFAULT(f->f_wb3s)) 74753933Shibler *(char *)f->f_wb3a = f->f_wb3d; 74853933Shibler else 74953933Shibler err = subyte((caddr_t)f->f_wb3a, f->f_wb3d); 75053933Shibler break; 75153933Shibler case SSW4_SZW: 75253933Shibler if (KDFAULT(f->f_wb3s)) 75353933Shibler *(short *)f->f_wb3a = f->f_wb3d; 75453933Shibler else 75553933Shibler err = susword((caddr_t)f->f_wb3a, f->f_wb3d); 75653933Shibler break; 75753933Shibler #ifdef DEBUG 75853933Shibler case SSW4_SZLN: 75953933Shibler panic("writeback: wb3s indicates LINE write"); 76053933Shibler #endif 76153933Shibler } 76253933Shibler if (err) { 76353933Shibler fa = f->f_wb3a; 76453933Shibler #ifdef DEBUG 76553933Shibler if (mmudebug & MDB_WBFAILED) 76653933Shibler printf(wberrstr, p->p_pid, p->p_comm, 76753933Shibler "#3", fp->f_pc, f->f_fa, 76853933Shibler f->f_wb3a, f->f_wb3d); 76953933Shibler #endif 77053933Shibler } 77153933Shibler } 77253933Shibler p->p_addr->u_pcb.pcb_onfault = oonfault; 77353933Shibler /* 77453933Shibler * Determine the cause of the failure if any translating to 77553933Shibler * a signal. If the corresponding VA is valid and RO it is 77653933Shibler * a protection fault (SIGBUS) otherwise consider it an 77753933Shibler * illegal reference (SIGSEGV). 77853933Shibler */ 77953933Shibler if (err) { 78053933Shibler if (vm_map_check_protection(&p->p_vmspace->vm_map, 78153933Shibler trunc_page(fa), round_page(fa), 78253933Shibler VM_PROT_READ) && 78353933Shibler !vm_map_check_protection(&p->p_vmspace->vm_map, 78453933Shibler trunc_page(fa), round_page(fa), 78553933Shibler VM_PROT_WRITE)) 78653933Shibler err = SIGBUS; 78753933Shibler else 78853933Shibler err = SIGSEGV; 78953933Shibler } 79053933Shibler return(err); 79153933Shibler } 79253933Shibler 79353933Shibler #ifdef DEBUG 79453933Shibler dumpssw(ssw) 79553933Shibler register u_short ssw; 79653933Shibler { 79753933Shibler printf(" SSW: %x: ", ssw); 79853933Shibler if (ssw & SSW4_CP) 79953933Shibler printf("CP,"); 80053933Shibler if (ssw & SSW4_CU) 80153933Shibler printf("CU,"); 80253933Shibler if (ssw & SSW4_CT) 80353933Shibler printf("CT,"); 80453933Shibler if (ssw & SSW4_CM) 80553933Shibler printf("CM,"); 80653933Shibler if (ssw & SSW4_MA) 80753933Shibler printf("MA,"); 80853933Shibler if (ssw & SSW4_ATC) 80953933Shibler printf("ATC,"); 81053933Shibler if (ssw & SSW4_LK) 81153933Shibler printf("LK,"); 81253933Shibler if (ssw & SSW4_RW) 81353933Shibler printf("RW,"); 81453933Shibler printf(" SZ=%s, TT=%s, TM=%s\n", 81553933Shibler f7sz[(ssw & SSW4_SZMASK) >> 5], 81653933Shibler f7tt[(ssw & SSW4_TTMASK) >> 3], 81753933Shibler f7tm[ssw & SSW4_TMMASK]); 81853933Shibler } 81953933Shibler 82053933Shibler dumpwb(num, s, a, d) 82153933Shibler int num; 82253933Shibler u_short s; 82353933Shibler u_int a, d; 82453933Shibler { 82553933Shibler register struct proc *p = curproc; 82653933Shibler vm_offset_t pa; 82753933Shibler 82853933Shibler printf(" writeback #%d: VA %x, data %x, SZ=%s, TT=%s, TM=%s\n", 82953933Shibler num, a, d, f7sz[(s & SSW4_SZMASK) >> 5], 83053933Shibler f7tt[(s & SSW4_TTMASK) >> 3], f7tm[s & SSW4_TMMASK]); 83153933Shibler printf(" PA "); 83253933Shibler pa = pmap_extract(&p->p_vmspace->vm_pmap, (vm_offset_t)a); 83353933Shibler if (pa == 0) 83453933Shibler printf("<invalid address>"); 83553933Shibler else 83653933Shibler printf("%x, current value %x", pa, fuword((caddr_t)a)); 83753933Shibler printf("\n"); 83853933Shibler } 83953933Shibler #endif 84053933Shibler #endif 84153933Shibler 84241475Smckusick /* 84349531Skarels * Proces a system call. 84441475Smckusick */ 84541475Smckusick syscall(code, frame) 84654801Storek u_int code; 84741475Smckusick struct frame frame; 84841475Smckusick { 84941475Smckusick register caddr_t params; 85041475Smckusick register struct sysent *callp; 85154801Storek register struct proc *p; 852*65483Sbostic int error, opc, numsys; 85354801Storek u_int argsize; 85444018Skarels struct args { 85544018Skarels int i[8]; 85644018Skarels } args; 85744018Skarels int rval[2]; 85854801Storek u_quad_t sticks; 85941475Smckusick #ifdef HPUXCOMPAT 86041475Smckusick extern struct sysent hpuxsysent[]; 86141475Smckusick extern int hpuxnsysent, notimp(); 86241475Smckusick #endif 86341475Smckusick 86441475Smckusick cnt.v_syscall++; 86541475Smckusick if (!USERMODE(frame.f_sr)) 86641475Smckusick panic("syscall"); 86754801Storek p = curproc; 86854801Storek sticks = p->p_sticks; 86952380Smckusick p->p_md.md_regs = frame.f_regs; 87041475Smckusick opc = frame.f_pc - 2; 87141475Smckusick #ifdef HPUXCOMPAT 87257344Shibler if (p->p_md.md_flags & MDP_HPUX) 87354801Storek callp = hpuxsysent, numsys = hpuxnsysent; 87454801Storek else 87541475Smckusick #endif 87654801Storek callp = sysent, numsys = nsysent; 87749531Skarels params = (caddr_t)frame.f_regs[SP] + sizeof(int); 87854801Storek switch (code) { 87954801Storek 88063469Smckusick case SYS_syscall: 88154801Storek /* 88254801Storek * Code is first argument, followed by actual args. 88354801Storek */ 88442370Skarels code = fuword(params); 88549531Skarels params += sizeof(int); 88657344Shibler /* 88757344Shibler * XXX sigreturn requires special stack manipulation 88857344Shibler * that is only done if entered via the sigreturn 88957344Shibler * trap. Cannot allow it here so make sure we fail. 89057344Shibler */ 89157344Shibler if (code == SYS_sigreturn) 89257344Shibler code = numsys; 89354801Storek break; 89454801Storek 89563469Smckusick case SYS___syscall: 89654801Storek /* 89763469Smckusick * Like syscall, but code is a quad, so as to maintain 89854801Storek * quad alignment for the rest of the arguments. 89954801Storek */ 90041475Smckusick #ifdef HPUXCOMPAT 90157344Shibler if (p->p_md.md_flags & MDP_HPUX) 90254801Storek break; 90341475Smckusick #endif 90454865Smckusick code = fuword(params + _QUAD_LOWWORD * sizeof(int)); 90554865Smckusick params += sizeof(quad_t); 90654801Storek break; 90754801Storek 90854865Smckusick default: 90954865Smckusick /* nothing to do by default */ 91054865Smckusick break; 91154801Storek } 91254801Storek if (code < numsys) 91354801Storek callp += code; 91454801Storek else 91563469Smckusick callp += SYS_syscall; /* => nosys */ 91654801Storek argsize = callp->sy_narg * sizeof(int); 91754801Storek if (argsize && (error = copyin(params, (caddr_t)&args, argsize))) { 91841475Smckusick #ifdef KTRACE 91943641Skarels if (KTRPOINT(p, KTR_SYSCALL)) 92044018Skarels ktrsyscall(p->p_tracep, code, callp->sy_narg, args.i); 92141475Smckusick #endif 92254801Storek goto bad; 92341475Smckusick } 92441475Smckusick #ifdef KTRACE 92543641Skarels if (KTRPOINT(p, KTR_SYSCALL)) 92644018Skarels ktrsyscall(p->p_tracep, code, callp->sy_narg, args.i); 92741475Smckusick #endif 92843641Skarels rval[0] = 0; 92943641Skarels rval[1] = frame.f_regs[D1]; 93041475Smckusick #ifdef HPUXCOMPAT 93142370Skarels /* debug kludge */ 93242370Skarels if (callp->sy_call == notimp) 93348465Skarels error = notimp(p, args.i, rval, code, callp->sy_narg); 93442370Skarels else 93541475Smckusick #endif 93654801Storek error = (*callp->sy_call)(p, &args, rval); 93754801Storek switch (error) { 93842370Skarels 93954801Storek case 0: 94041475Smckusick /* 94154801Storek * Reinitialize proc pointer `p' as it may be different 94254801Storek * if this is a child returning from fork syscall. 94341475Smckusick */ 94454801Storek p = curproc; 94554801Storek frame.f_regs[D0] = rval[0]; 94654801Storek frame.f_regs[D1] = rval[1]; 94754801Storek frame.f_sr &= ~PSL_C; 94854801Storek break; 94941475Smckusick 95054801Storek case ERESTART: 95154801Storek frame.f_pc = opc; 95254801Storek break; 95354801Storek 95454801Storek case EJUSTRETURN: 95554801Storek break; /* nothing to do */ 95654801Storek 95754801Storek default: 95854801Storek bad: 95954801Storek #ifdef HPUXCOMPAT 96057344Shibler if (p->p_md.md_flags & MDP_HPUX) 96154801Storek error = bsdtohpuxerrno(error); 96241475Smckusick #endif 96354801Storek frame.f_regs[D0] = error; 96454801Storek frame.f_sr |= PSL_C; 96554801Storek break; 96641475Smckusick } 96754801Storek 96854801Storek userret(p, &frame, sticks, (u_int)0, 0); 96941475Smckusick #ifdef KTRACE 97043641Skarels if (KTRPOINT(p, KTR_SYSRET)) 97143641Skarels ktrsysret(p->p_tracep, code, error, rval[0]); 97241475Smckusick #endif 97341475Smckusick } 974