#ifndef lint static char sccsid[] = "@(#)trap.c 1.1 94/10/31"; #endif /* * Copyright (c) 1990 by Sun Microsystems, Inc. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef SUNDBE #include #endif /* SUNDBE */ #if defined(SUN4M_35) extern int small_4m, no_vme; #endif #define USER 0x10000 /* user-mode flag added to type */ #ifdef SYSCALLTRACE extern char* syscallnames[]; #endif /* SYSCALLTRACE */ extern struct sysent sysent[]; extern int nsysent; char *trap_type[] = { "Zero", #ifdef SPARC_V8_TRAPS "Instruction access exception", #else "Text fault", #endif "Illegal instruction", "Privileged instruction", "Floating point unit disabled", "Window overflow", "Window underflow", "Memory address alignment", "Floating point exception", #ifdef SPARC_V8_TRAPS "Data access exception", #else "Data fault", #endif "Tag overflow", "Trap 0x0B", "Trap 0x0C", "Trap 0x0D", "Trap 0x0E", "Trap 0x0F", "Spurious interrupt", "Interrupt level 1", "Interrupt level 2", "Interrupt level 3", "Interrupt level 4", "Interrupt level 5", "Interrupt level 6", "Interrupt level 7", "Interrupt level 8", "Interrupt level 9", "Interrupt level A", "Interrupt level B", "Interrupt level C", "Interrupt level D", "Interrupt level E", #ifdef SPARC_V8_TRAPS "Interrupt level F", "Trap 0x20", "Instruction access error", "Trap 0x22", "Trap 0x23", "Coprocessor unit disabled", "Unimplemented flush", "Trap 0x26", "Trap 0x27", "Coprocessor exception", "Data access error", "Divide by zero", "Data store error", #else "AST", #endif }; #define TRAP_TYPES (sizeof (trap_type) / sizeof (trap_type[0])) int tudebug = 0; int tudebugbpt = 0; int tudebugfpe = 0; int aligndebug = 0; int alignfaults = 0; #ifndef OPENPROMS #define prom_write ??? #else OPENPROMS #ifndef MULTIPROCESSOR extern void prom_write(); #else MULTIPROCESSOR #define prom_write mpprom_write #endif MULTIPROCESSOR #endif OPENPROMS #if defined(TRAPDEBUG) || defined(lint) int tdebug = 0; int lodebug = 0; int faultdebug = 0; #else #define tdebug 0 #define lodebug 0 #define faultdebug 0 #endif defined(TRAPDEBUG) || defined(lint) #define SIMU_SUCCESS 1 /* simulation worked */ #define SIMU_ILLEGAL 0 /* tried to simulate an illegal instruction */ #define SIMU_FAULT -1 /* simulation generated an illegal access */ #define SIMU_DZERO -2 /* divided by zero detected */ u_int beval = FT_INVALID_ADDR << FS_FTSHIFT; /* used by fp_traps to setup * a datafault trap */ #define TRAPTRACE #ifdef TRAPTRACE int traptrace = 0; #endif TRAPTRACE void badtrap(type, rp, addr, mmu_fsr, rw) register unsigned type; register struct regs *rp; register addr_t addr; register u_int mmu_fsr; register enum seg_rw rw; { extern int cpuid; trigger_logan(); (void) spl7(); printf("BAD TRAP: cpu=%d type=%x rp=%x addr=%x mmu_fsr=%x rw=%x\n", cpuid, type, rp, addr, mmu_fsr, rw); mmu_print_sfsr(mmu_fsr); #if defined(MULTIPROCESSOR) && defined(PROM_PARANOIA) mpprom_eprintf("PROM_PARANOIA: inside badtrap()\n"); #endif printf("regs at %x:\n", rp); printf("\tpsr=%x pc=%x npc=%x\n", rp->r_psr, rp->r_pc, rp->r_npc); printf("\ty: %x g1: %x g2: %x g3: %x\n", rp->r_y, rp->r_g1, rp->r_g2, rp->r_g3); printf("\tg4: %x g5: %x g6: %x g7: %x\n", rp->r_g4, rp->r_g5, rp->r_g6, rp->r_g7); printf("\to0: %x o1: %x o2: %x o3: %x\n", rp->r_o0, rp->r_o1, rp->r_o2, rp->r_o3); printf("\to4: %x o5: %x sp: %x ra: %x\n", rp->r_o4, rp->r_o5, rp->r_o6, rp->r_o7); showregs(type, rp, addr, mmu_fsr, rw); traceback((caddr_t)rp->r_sp); if (type < TRAP_TYPES) panic(trap_type[type]); panic("trap"); } enum fault_type get_faulttype(type, rp, addr, mmu_fsr, rw) register unsigned type; register struct regs *rp; register addr_t addr; register u_int mmu_fsr; register enum seg_rw rw; { enum fault_type fault_type; #ifdef TRAPTRACE int pid; if (u.u_procp) pid = u.u_procp->p_pid; else pid = -1; #endif TRAPTRACE switch (X_FAULT_TYPE(mmu_fsr)) { /* * FT_NONE can't happen, locore stops us from getting here * if sfsr has not ft_type */ case FT_TRANS_ERROR: case FT_ACC_BUSERR: case FT_INTERNAL: default: printf("Unexpected trap %d fault %x\n", type, X_FAULT_TYPE(mmu_fsr)); badtrap(type, rp, addr, mmu_fsr, rw); /* NO RETURN */ case FT_INVALID_ADDR: #ifdef TRAPTRACE if (traptrace) { printf("%d: data fault at 0x%x: ", pid, addr); printf("address not mapped\n"); } #endif if (tdebug) printf("FT_INV\n"); fault_type = F_INVAL; break; case FT_PROT_ERROR: case FT_PRIV_ERROR: #ifdef TRAPTRACE if (traptrace) { printf("%d: data fault at 0x%x: ", pid, addr); printf("protection violation\n"); } #endif if (tdebug) printf("FT_PROT\n"); fault_type = F_PROT; break; } return (fault_type); } void check_fsr(type, rp, addr, mmu_fsr, rw) register unsigned type; register struct regs *rp; register addr_t addr; register u_int mmu_fsr; register enum seg_rw rw; { extern int vac_parity_chk_dis(); if ((mmu_fsr & MMU_SFSR_FATAL) || (mmu_fsr & MMU_SFSR_UD)) { /* bad bits in the SFSR */ if (lodebug) showregs(type, rp, addr, mmu_fsr, rw); /* * If this trap was caused by a MBUS Uncorrectable * error, it's an ECC uncorrectable error on read. * This requires to print out the detailed info ( * including the SIMM number) before calling panic */ if ((mmu_fsr & MMU_SFSR_UC) || (mmu_fsr & MMU_SFSR_UD)) { struct pte pte; addr_t paddr; int parity_err; (void) spl7(); parity_err = vac_parity_chk_dis(mmu_fsr, 0); if (parity_err) printf("module parity error:\n"); else printf("fatal system fault:\n"); mmu_getpte(addr, &pte); if (pte_valid(&pte)) { paddr = (caddr_t) (pte.PhysicalPageNumber << MMU_PAGESHIFT) + ((int) addr & MMU_PAGEOFFSET); log_mem_err(mmu_fsr, (u_int) 0, (u_int) paddr, (u_int) 1); } else printf("addr %x is not valid\n", addr); printf("Control Registers:\n"); printf("\tsfsr = 0x%x, %s fault ", mmu_fsr, (rw == S_WRITE? "write": "read")); printf("at vaddr 0x%x\n", addr); if (lodebug) mmu_print_sfsr(mmu_fsr); panic("memory error"); /* NOTREACHED */ } } } #ifdef VME /* * If "vme_int_ack_warn" is set, we will print * a warning message whenever we drop a VME INT-ACK. */ int vme_int_ack_warn = 0; /* * "vme_int_ack_drops" is a quick count of how many * times we have dropped a VME INT-ACK cycle. It should * stay at zero. */ int vme_int_ack_drops = 0; #endif VME /* * Called from the trap handler when a processor trap occurs. * Addr, mmu_fsr and rw only are passed for text and data faults. */ /*VARARGS2*/ void trap(type, rp, addr, mmu_fsr, rw) register unsigned type; register struct regs *rp; addr_t addr; register u_int mmu_fsr; register enum seg_rw rw; { register int i = 0; register struct proc *p; struct timeval syst; int lofault; faultcode_t pagefault(), res; u_int inst; enum fault_type fault_type; int mask; #ifdef TRAPTRACE int pid; #endif TRAPTRACE extern void module_wkaround(); #ifdef MULTIPROCESSOR klock_enter(); #endif MULTIPROCESSOR p = u.u_procp; #ifdef TRAPTRACE if (p) pid = p->p_pid; else pid = -1; #endif TRAPTRACE cnt.v_trap++; syst = u.u_ru.ru_stime; if (tdebug) showregs(type, rp, addr, mmu_fsr, rw); if (USERMODE(rp->r_psr)) { if (tdebug) printf("Setting user bit\n"); type |= USER; u.u_ar0 = (int *)rp; } /* * take any pending floating point exceptions now */ syncfpu(rp); switch (type) { case T_ALIGNMENT: /* supv alignment error */ /* printf("kernel alignment fault\n"); */ goto die; case T_DATA_STORE: /* store buffer exception */ case T_DATA_STORE + USER: /* store buffer exception */ #if defined(SUN4M_35) if (!small_4m) (void) check_fsr(type, rp, addr, mmu_fsr, rw); #else (void) check_fsr(type, rp, addr, mmu_fsr, rw); #endif /* * FIXME: currently we panic the system when store * buffer exception occurs. We should try to recover * from it. */ if (tdebug) { printf("T_DATA_STORE mmu_fsr %x ", mmu_fsr); showregs(type, rp, addr, mmu_fsr, rw); } goto die; /* NOTREACHED */ default: /* * Check for user software trap. */ if (type & USER) { #ifdef TRAPTRACE if (traptrace) { printf("%d: bad user software trap 0x%x\n", pid, type); } #endif if (tudebug) showregs(type, rp, (addr_t)0, 0, S_OTHER); if (((type & ~USER) >= T_SOFTWARE_TRAP) || ((type & ~USER) & CP_BIT)) { u.u_addr = (char *)rp->r_pc; u.u_code = type &~ USER; i = SIGILL; break; } } die: badtrap(type, rp, addr, mmu_fsr, rw); /* NOTREACHED */ #ifdef SPARC_V8_TRAPS case T_TEXT_FAULT: /* system text access exception */ case T_TEXT_ERROR: /* system text access error */ #else case T_TEXT_FAULT: /* system text access fault */ #endif #if defined(SUN4M_35) if (!small_4m) (void) check_fsr(type, rp, addr, mmu_fsr, rw); #else (void) check_fsr(type, rp, addr, mmu_fsr, rw); #endif /* * 605 overwrite bit is not checked here. * whether set or not kernel is going to die any way * */ /* do the lda of sup/user inst space for completeness */ #ifdef TRAPTRACE if (traptrace) { printf("%d: text fault at 0x%x\n", pid, addr); } #endif #if defined (SUN4M_35) if (cpu == CPU_SUN4M_35 && X_EBE(mmu_fsr)) { if (ebe_handler(MERR_SYNC, mmu_fsr, addr, type, rp) != -1) return; } #endif if (lodebug) showregs(type, rp, addr, mmu_fsr, rw); goto die; #ifdef SPARC_V8_TRAPS case T_DATA_FAULT: /* system data access exception */ case T_DATA_ERROR: /* system data access error */ #else case T_DATA_FAULT: /* system data access fault */ #endif /* may have been expected by C (e.g., bus probe) */ /* * 605 overwrite bit story * if set says the second fault could have been a * a translation error on an instruction fault only. * In any case translation errors are panics and hence * we print info and giveup */ if (tdebug) printf("got to DATAFAULT\n"); if (nofault) { label_t *ftmp; ftmp = nofault; nofault = 0; longjmp(ftmp); } #if defined (SUN4M_35) if (cpu == CPU_SUN4M_35 && X_EBE(mmu_fsr)) { if (ebe_handler(MERR_SYNC, mmu_fsr, addr, type, rp) != -1) return; } #endif #ifdef VME /* * If this trap was caused by a VME device not * completing an interrupt acknowledge cycle, * print a warning message and continue. * NOTE: leaves the destination register of the load * entirely unmodified ... */ #if defined(SUN4M_35) if ((no_vme == 0) && (type == T_DATA_FAULT) && (mmu_fsr & MMU_SFSR_FATAL) && #else if ((type == T_DATA_FAULT) && (mmu_fsr & MMU_SFSR_FATAL) && #endif ((int)addr & ~0xF) == V_VMEBUS_VEC) { vme_int_ack_drops ++; if (vme_int_ack_warn) { printf("Warning: VME dropped an INT-ACK cycle\n"); mmu_print_sfsr(mmu_fsr); } rp->r_pc = rp->r_npc; rp->r_npc = rp->r_npc + 4; return; } #endif VME /* do module specific workarounds if any */ module_wkaround(&addr, rp, rw, mmu_fsr); #if defined(SUN4M_35) if (!small_4m) (void) check_fsr(type, rp, addr, mmu_fsr, rw); #else (void) check_fsr(type, rp, addr, mmu_fsr, rw); #endif /* get_faulttype can panic if bad trap */ fault_type = get_faulttype(type, rp, addr, mmu_fsr, rw); /* * See if we can handle as pagefault. Save lofault * across this. Here we assume that an address * less than KERNELBASE + sizeof (int) is a user fault. * We can do this as copy.s routines verify that the * starting address is less than KERNELBASE before * starting and because we know that we always have * KERNELBASE mapped as invalid to serve as a "barrier". * Because of SF9010 bug (see below), we must validate * the bus error register when more than one bit is on. */ lofault = u.u_lofault; u.u_lofault = 0; if (addr < (addr_t)KERNELBASE + sizeof (int)) { if (lofault == 0) { goto die; } res = pagefault(addr, rw, 0, (u_int) fault_type); if (res != 0 && grow((int)addr)) res = 0; } else { res = pagefault(addr, rw, 1, (u_int) fault_type); } /* * Restore lofault. If we resolved the fault, exit. * If we didn't and lofault wasn't set, die. */ u.u_lofault = lofault; if (res == 0) return; if (lofault == 0) goto die; /* * Cannot resolve fault. Return to lofault. */ if (lodebug) { showregs(type, rp, addr, mmu_fsr, rw); traceback((caddr_t)rp->r_sp); } if (FC_CODE(res) == FC_OBJERR) res = FC_ERRNO(res); else res = EFAULT; rp->r_g1 = res; rp->r_pc = lofault; rp->r_npc = lofault + 4; return; #ifdef SPARC_V8_TRAPS case T_DATA_FAULT + USER: /* user data access exception */ case T_DATA_ERROR + USER: /* user data access error */ #else case T_DATA_FAULT + USER: /* user data access fault */ #endif /* module specific workarounds if any */ /* we know the vikings need workaround in the case of * data faults. See vik_module_wkaround() for deatails */ module_wkaround(&addr, rp, rw, mmu_fsr); /* FALL THROUGH */ #ifdef SPARC_V8_TRAPS case T_TEXT_FAULT + USER: /* user text access exception */ case T_TEXT_ERROR + USER: /* user text access error */ #else case T_TEXT_FAULT + USER: /* user text access fault */ #endif #if defined (SUN4M_35) /* possible parity error? */ if (cpu == CPU_SUN4M_35 && X_EBE(mmu_fsr)) if (ebe_handler(MERR_SYNC, mmu_fsr, addr, type, rp) != -1) return; #endif /* * 605 fault overwrite story. * Instruction-instruction: Resolve at PC and let the * other one happen again. The second fault could be * for a prefetch of instructions. Hence we handle the * fault pc only. * instruction-translation: Translation is treated as * bad thing by the kernel. panic * translation-otherfault: bad panic * data - data: CANNOT happen on 601 IU * data - translation: panic because of trans error */ if ((mmu_fsr&MMU_SFSR_OW) && (X_FAULT_TYPE(mmu_fsr) == FT_TRANS_ERROR)) { printf("cpu %d: Multiple faults occurred\n", cpuid); printf("\t first fault %s at pc %x \n", cpuid, (type == (T_DATA_FAULT+USER)? "User Data ":"User text ")); printf("\t second fault: translation error "); printf("at addr %x\n", addr); } if (tdebug) { printf("T_DATA_FAULT | USER mmu_fsr %x ", mmu_fsr); printf("X_FAULT_TYPE %x\n", (u_int)X_FAULT_TYPE(mmu_fsr)); } if ((mmu_fsr & (MMU_SFSR_TO | MMU_SFSR_BE)) && !(mmu_fsr & MMU_SFSR_UC)) { res = FC_HWERR; goto badbus; } #if defined(SUN4M_35) if (!small_4m) (void) check_fsr(type, rp, addr, mmu_fsr, rw); #else (void) check_fsr(type, rp, addr, mmu_fsr, rw); #endif /* get_faulttype can panic if bad trap */ fault_type = get_faulttype(type, rp, addr, mmu_fsr, rw); if (faultdebug) { char *fault_str; switch (rw) { case S_READ: fault_str = "read"; break; case S_WRITE: fault_str = "write"; break; case S_EXEC: fault_str = "exec"; break; default: fault_str = ""; break; } printf("user %s fault: addr=0x%x mmu_fsr=0x%x\n", fault_str, addr, mmu_fsr); } if (tdebug) { printf("Calling pagefault: "); printf("addr %x rw %x fault_type %x\n", addr, rw, fault_type); } res = pagefault(addr, rw, 0, (u_int) fault_type); if (res == 0) return; if (type == T_DATA_FAULT + USER) { /* * Grow the stack automatically. */ if (grow((int)addr)) goto out; } if (tudebug) showregs(type, rp, addr, mmu_fsr, rw); /* * In the case where both pagefault and grow fail, * set the code to the value provided by pagefault. * We map errors relating to the underlying object * to SIGBUS, others to SIGSEGV. */ badbus: u.u_addr = (char *)addr; u.u_code = res; switch (FC_CODE(res)) { case FC_HWERR: case FC_OBJERR: i = SIGBUS; break; default: i = SIGSEGV; } break; case T_ALIGNMENT + USER: /* user alignment error */ #ifdef TRAPTRACE if (traptrace) { printf("%d: alignment error at 0x%x\n", pid, addr); } #endif if (tudebug) showregs(type, rp, (addr_t)0, 0, S_OTHER); /* * if the user has to do unaligned references * the ugly stuff gets done here */ alignfaults++; if (u.u_pcb.pcb_flags & FIX_ALIGNMENT) { if (do_unaligned(rp)) { rp->r_pc = rp->r_npc; rp->r_npc += 4; return; } } u.u_addr = (char *)rp->r_pc; /* not quite right */ u.u_code = FC_ALIGN; i = SIGBUS; break; case T_PRIV_INSTR + USER: /* privileged instruction fault */ #ifdef TRAPTRACE if (traptrace) { printf("%d: privileged instruction at 0x%x\n", pid, rp->r_pc); } #endif if (tudebug) showregs(type, rp, (addr_t)0, 0, S_OTHER); u.u_addr = (char *)rp->r_pc; u.u_code = ILL_PRIVINSTR_FAULT; i = SIGILL; break; case T_UNIMP_INSTR + USER: /* illegal instruction fault */ #ifdef TRAPTRACE if (traptrace) { printf("%d: unimplemented instruction at 0x%x\n", pid, rp->r_pc); } #endif if (tudebug) showregs(type, rp, (addr_t)0, 0, S_OTHER); switch (simulate_unimp(rp)) { case SIMU_SUCCESS: /* skip the successfully simulated instruction */ rp->r_pc = rp->r_npc; rp->r_npc += 4; return; case SIMU_FAULT: /* * tried to reference an illegal address * u.u_{addr, code} set in simulation called above */ i = SIGSEGV; break; case SIMU_DZERO: /* a simulated division had a divisor of zero */ u.u_addr = (char *)rp->r_pc; u.u_code = (int)FPE_INTDIV_TRAP; i = SIGFPE; break; case SIMU_ILLEGAL: default: /* no such instruction */ u.u_addr = (char *)rp->r_pc; u.u_code = ILL_ILLINSTR_FAULT; i = SIGILL; break; } break; case T_DIV0 + USER: /* integer divide by zero */ #ifdef TRAPTRACE if (traptrace) { printf("%d: divide by zero at 0x%x\n", pid, rp->r_pc); } #endif if (tudebug && tudebugfpe) showregs(type, rp, (addr_t)0, 0, S_OTHER); rp->r_pc = rp->r_npc; /* skip trap instruction */ rp->r_npc += 4; u.u_addr = (char *)rp->r_pc; u.u_code = (int)FPE_INTDIV_TRAP; i = SIGFPE; break; case T_INT_OVERFLOW + USER: /* integer overflow */ #ifdef TRAPTRACE if (traptrace) { printf("%d: integer overflow at 0x%x\n", pid, rp->r_pc); } #endif if (tudebug && tudebugfpe) showregs(type, rp, (addr_t)0, 0, S_OTHER); rp->r_pc = rp->r_npc; /* skip trap instruction */ rp->r_npc += 4; u.u_addr = (char *)rp->r_pc; u.u_code = (int)FPE_INTOVF_TRAP; i = SIGFPE; break; case T_FP_EXCEPTION + USER: /* FPU arithmetic exception */ case T_FP_EXCEPTION: #ifdef TRAPTRACE if (traptrace) { printf("%d: flotating point exception at 0x%x\n", pid, rp->r_pc); } #endif if (tudebug && tudebugfpe) showregs(type, rp, addr, 0, S_OTHER); u.u_code = mmu_fsr; /* this is actually fp trap code * from fp_traps() */ u.u_addr = (char *)addr; i = SIGFPE; break; case T_BREAKPOINT + USER: /* breakpoint trap (t 1) */ #ifdef TRAPTRACE if (traptrace) { printf("%d: breakpoint at 0x%x\n", pid, rp->r_pc); } #endif if (tudebug && tudebugbpt) showregs(type, rp, (addr_t)0, 0, S_OTHER); i = SIGTRAP; break; case T_TAG_OVERFLOW + USER: /* tag overflow (taddcctv, tsubcctv) */ #ifdef TRAPTRACE if (traptrace) { printf("%d: tag overflow at 0x%x\n", pid, rp->r_pc); } #endif if (tudebug) showregs(type, rp, (addr_t)0, 0, S_OTHER); u.u_addr = (char *)rp->r_pc; u.u_code = EMT_TAG; i = SIGEMT; break; case T_WIN_OVERFLOW + USER: /* finish user window overflow */ /* * This trap is entered from sys_rtt in locore.s when, upon * return to user is is found that there are user windows in * u.u_wbuf. This happens because they could not be saved on * the user stack, either because it wasn't resident or because * it was misaligned. We flush the user's windows to make * sure pcb_wbcnt does not change while we are doing this. */ { register int j; flush_user_windows(); for (j = 0; j < u.u_pcb.pcb_wbcnt; j++) { register char *sp; sp = u.u_pcb.pcb_spbuf[j]; /* * XXX - do we still need PARTIAL_ALIGN? */ #ifdef PARTIAL_ALIGN if ((partial_align? ((int)sp & 0x3): ((int)sp & 0x7))) { #else if (((int)sp & (STACK_ALIGN-1))) { #endif PARTIAL_ALIGN u.u_addr = (char *)rp->r_pc; u.u_code = ILL_STACK; i = SIGILL; break; } else { #ifdef SAS if (tudebug) { printf("trap: copyout(%x, %x, %x) ", (caddr_t)&u.u_pcb.pcb_wbuf[j], sp, sizeof (struct rwindow)); printf("j %x\n", j); } #endif SAS inst = copyout((caddr_t)&u.u_pcb.pcb_wbuf[j], sp, sizeof (struct rwindow)); if (inst != 0) { #ifdef SAS printf("%d: ", u.u_procp->p_pid); printf("bad copyout ret %x ", inst); printf("pc %x sp %x ", rp->r_pc, sp); printf("wbuf %x j %x\n", u.u_pcb.pcb_wbcnt, j); #endif SAS u.u_addr = (char *)rp->r_pc; u.u_code = ILL_STACK; i = SIGILL; break; } } } if (i == 0) { u.u_pcb.pcb_wbcnt = 0; return; } if (tudebug) showregs(type, rp, (addr_t)0, 0, S_OTHER); } break; case T_AST + USER: /* profiling or resched psuedo trap */ astoff(); if ((p->p_flag & SOWEUPC) && u.u_prof.pr_scale) { addupc(rp->r_pc, &u.u_prof, 1); p->p_flag &= ~SOWEUPC; } goto out; } /* * Before trying to send a signal to the process, make * sure it's not masked, otherwise we'll loop taking * synchronous traps until someone notices and kills the * process. */ mask = sigmask(i); if ((mask & p->p_sigmask) && (i != SIGFPE)) { u.u_signal[i] = SIG_DFL; p->p_sigignore &= ~mask; p->p_sigcatch &= ~mask; p->p_sigmask &= ~mask; } psignal(p, i); out: if (((p->p_flag & STRC) == 0 && p->p_cursig) || ISSIG(p, 0)) psig(); if (runrun) { /* * Since we are u.u_procp, clock will normally just change * our priority without moving us from one queue to another * (since the running process is not on a queue.) * If that happened after we setrq ourselves but before we * swtch()'ed, we might not be on the queue indicated by * our priority. */ (void) spl6(); p->p_pri = p->p_usrpri; setrq(p); u.u_ru.ru_nivcsw++; swtch(); (void) spl0(); } else{ p->p_pri = p->p_usrpri; } if (u.u_prof.pr_scale) { int ticks; struct timeval *tv = &u.u_ru.ru_stime; ticks = ((tv->tv_sec - syst.tv_sec) * 1000 + (tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000); if (ticks) addupc(rp->r_pc, &u.u_prof, ticks); } curpri = p->p_pri; } #ifdef SYSCALLTRACE int syscalltrace = 0; #endif #ifdef SYSCALL_TRACE_STRINGS int syscall_strs[] = { /* which args to print as ascii */ 0, /* 0 = indir */ 0, /* 1 = exit */ 0, /* 2 = fork */ 0, /* 3 = read */ 0, /* 4 = write */ 01, /* 5 = open */ 0, /* 6 = close */ 0, /* 7 = wait4 */ 01, /* 8 = creat */ 03, /* 9 = link */ 01, /* 10 = unlink */ 01, /* 11 = execv */ 01, /* 12 = chdir */ 0, /* 13 = old time */ 01, /* 14 = mknod */ 01, /* 15 = chmod */ 01, /* 16 = chown; now 3 args */ 0, /* 17 = brk */ 01, /* 18 = old stat */ 0, /* 19 = lseek */ 0, /* 20 = getpid */ 0, /* 21 = old mount */ #ifdef UFS 01, /* 22 = old umount */ #else 0, /* 22 = old umount */ #endif 0, /* 23 = old setuid */ 0, /* 24 = getuid */ 0, /* 25 = old stime */ 0, /* 26 = ptrace */ 0, /* 27 = old alarm */ 0, /* 28 = old fstat */ 0, /* 29 = opause */ 01, /* 30 = old utime */ 0, /* 31 = was stty */ 0, /* 32 = was gtty */ 01, /* 33 = access */ 0, /* 34 = old nice */ 0, /* 35 = old ftime */ 0, /* 36 = sync */ 0, /* 37 = kill */ 01, /* 38 = stat */ 0, /* 39 = old setpgrp */ 01, /* 40 = lstat */ 0, /* 41 = dup */ 0, /* 42 = pipe */ 0, /* 43 = old times */ 0, /* 44 = profil */ 0, /* 45 = nosys */ 0, /* 46 = old setgid */ 0, /* 47 = getgid */ 0, /* 48 = old sig */ 0, /* 49 = reserved for USG */ 0, /* 50 = reserved for USG */ #ifdef SYSACCT 0, /* 51 = turn acct off/on */ #else 0, /* 51 = not configured */ #endif SYSACCT 0, /* 52 = old set phys addr */ 0, /* 53 = memory control */ 0, /* 54 = ioctl */ 02, /* 55 = reboot */ #ifdef sparc 0, /* 56 = wait3 */ #else 0, /* 56 = old mpxchan */ #endif sparc 03, /* 57 = symlink */ 01, /* 58 = readlink */ 01, /* 59 = execve */ 0, /* 60 = umask */ 01, /* 61 = chroot */ 0, /* 62 = fstat */ 0, /* 63 = used internally */ 0, /* 64 = getpagesize */ 0, /* 65 = old msync */ 0, /* 66 = vfork */ 0, /* 67 = old vread */ 0, /* 68 = old vwrite */ 0, /* 69 = sbrk */ 0, /* 70 = sstk */ 0, /* 71 = mmap */ 0, /* 72 = old vadvise */ 0, /* 73 = munmap */ 0, /* 74 = mprotect */ 0, /* 75 = old madvise */ 0, /* 76 = vhangup */ 0, /* 77 = old vlimit */ 0, /* 78 = mincore */ 0, /* 79 = getgroups */ 0, /* 80 = setgroups */ 0, /* 81 = getpgrp */ 0, /* 82 = setpgrp */ 0, /* 83 = setitimer */ 0, /* 84 = old wait & wait3 */ 01, /* 85 = swapon */ 0, /* 86 = getitimer */ 0, /* 87 = gethostname */ 01, /* 88 = sethostname */ 0, /* 89 = getdtablesize */ 0, /* 90 = dup2 */ 0, /* 91 = getdopt */ 0, /* 92 = fcntl */ 0, /* 93 = select */ 0, /* 94 = setdopt */ 0, /* 95 = fsync */ 0, /* 96 = setpriority */ 0, /* 97 = socket */ 0, /* 98 = connect */ 0, /* 99 = accept */ 0, /* 100 = getpriority */ 0, /* 101 = send */ 0, /* 102 = recv */ 0, /* 103 = old socketaddr */ 0, /* 104 = bind */ 0, /* 105 = setsockopt */ 0, /* 106 = listen */ 0, /* 107 = old vtimes */ 0, /* 108 = sigvec */ 0, /* 109 = sigblock */ 0, /* 110 = sigsetmask */ 0, /* 111 = sigpause */ 0, /* 112 = sigstack */ 0, /* 113 = recvmsg */ 0, /* 114 = sendmsg */ #ifdef TRACE 0, /* 115 = vtrace */ #else TRACE 0, /* 115 = nosys */ #endif TRACE 0, /* 116 = gettimeofday */ 0, /* 117 = getrusage */ 0, /* 118 = getsockopt */ #ifdef vax 0, /* 119 = resuba */ #else 0, /* 119 = nosys */ #endif 0, /* 120 = readv */ 0, /* 121 = writev */ 0, /* 122 = settimeofday */ 0, /* 123 = fchown */ 0, /* 124 = fchmod */ 0, /* 125 = recvfrom */ 0, /* 126 = setreuid */ 0, /* 127 = setregid */ 03, /* 128 = rename */ 01, /* 129 = truncate */ 0, /* 130 = ftruncate */ 0, /* 131 = flock */ 0, /* 132 = nosys */ 0, /* 133 = sendto */ 0, /* 134 = shutdown */ 0, /* 135 = socketpair */ 01, /* 136 = mkdir */ 01, /* 137 = rmdir */ 01, /* 138 = utimes */ 0, /* 139 = signalcleanup */ 0, /* 140 = adjtime */ 0, /* 141 = getpeername */ 0, /* 142 = gethostid */ 0, /* 143 = old sethostid */ 0, /* 144 = getrlimit */ 0, /* 145 = setrlimit */ 0, /* 146 = killpg */ 0, /* 147 = nosys */ 0, /* XXX */ /* 148 = old quota */ 0, /* XXX */ /* 149 = old qquota */ 0, /* 150 = getsockname */ 0, /* 151 = getmsg */ 0, /* 152 = putmsg */ 0, /* 153 = poll */ #ifdef NFSSERVER 0, /* 154 = old nfs_mount */ 0, /* 155 = nfs_svc */ #else 0, /* 154 = nosys */ 0, /* 155 = errsys */ #endif 0, /* 156 = getdirentries */ 01, /* 157 = statfs */ 0, /* 158 = fstatfs */ 01, /* 159 = unmount */ #ifdef NFSCLIENT 0, /* 160 = async_daemon */ #else 0, /* 160 = errsys */ #endif #ifdef NFSSERVER 0, /* 161 = get file handle */ #else 0, /* 161 = nosys */ #endif 0, /* 162 = getdomainname */ 01, /* 163 = setdomainname */ #ifdef RT_SCHEDULE 0, /* 164 = rtschedule */ #else 0, /* 164 = not configured */ #endif RT_SCHEDULE #ifdef QUOTA 0, /* 165 = quotactl */ #else 0, /* 165 = not configured */ #endif QUOTA #ifdef NFSSERVER 0, /* 166 = exportfs */ #else 0, /* 166 = not configured */ #endif 03, /* 167 = mount */ 0, /* 168 = ustat */ #ifdef IPCSEMAPHORE 0, /* 169 = semsys */ #else 0, /* 169 = not configured */ #endif #ifdef IPCMESSAGE 0, /* 170 = msgsys */ #else 0, /* 170 = not configured */ #endif #ifdef IPCSHMEM 0, /* 171 = shmsys */ #else 0, /* 171 = not configured */ #endif #ifdef SYSAUDIT 0, /* 172 = auditsys (audit control) */ #else 0, /* 172 = not configured */ #endif SYSAUDIT #ifdef RFS 0, /* 173 = RFS calls */ #else 0, /* 173 = not configured */ #endif 0, /* 174 = getdents */ 0, /* 175 = setsid & s5 setpgrp() */ 0, /* 176 = fchdir */ 0, /* 177 = fchroot */ #ifdef VPIX 0, /* 178 = VP/ix system calls */ #else 0, /* 178 = not configured */ #endif #ifdef ASYNCHIO 0, /* 179 = aioread */ 0, /* 180 = aiowrite */ 0, /* 181 = aiowait */ 0, /* 182 = aiocancel */ #else 0, /* 179 not configured */ 0, /* 180 not configured */ 0, /* 181 not configured */ 0, /* 182 not configured */ #endif ASYNCHIO 0, /* 183 = sigpending */ 0, /* 184 = AVAILABLE */ 0, /* 185 = setpgid */ 01, /* 186 = pathconf */ 0, /* 187 = fpathconf */ 0, /* 188 = sysconf */ 01, /* 189 = uname */ #ifdef VDDRV 0, /* 190 = reserved - Loadable syscalls */ 0, /* 191 = reserved - Loadable syscalls */ 0, /* 192 = reserved - Loadable syscalls */ 0, /* 193 = reserved - Loadable syscalls */ 0, /* 194 = reserved - Loadable syscalls */ 0, /* 195 = reserved - Loadable syscalls */ 0, /* 196 = reserved - Loadable syscalls */ 0, /* 197 = reserved - Loadable syscalls */ #endif }; #endif SYSCALL_TRACE_STRINGS #ifdef SYSCALLTRACE #ifdef MULTIPROCESSOR int syscalltracelockok = 0; atom_t syscalltracelock; #endif char syscalltracebuf[4096]; static char * eostr(bp) char *bp; { while (*bp) ++bp; return (bp); } static void prsct(code, na, fmt, arg) unsigned code; char *fmt; { extern char *sprintf(); register int i; char *cp; char *bp = syscalltracebuf; *bp = 0; #ifdef MULTIPROCESSOR /* * Yes, this could be a race, but what are the * chances of both processes coming through here * at the same time before we initialize * this lock? Zero. */ if (!syscalltracelockok) { atom_init(syscalltracelock); syscalltracelockok = 1; } atom_wcs(syscalltracelock); (void) sprintf(bp = eostr(bp), "%d/", cpuid); #endif (void) sprintf(bp = eostr(bp), "%d: ", u.u_procp->p_pid); (void) sprintf(bp = eostr(bp), "sys 0x%x", code); if (code < nsysent) (void) sprintf(bp = eostr(bp), " %s", syscallnames[code]); else (void) sprintf(bp = eostr(bp), " ???"); cp = "("; for (i = 0; i < na; i++) { #ifdef SYSCALL_TRACE_STRINGS if ((code < nsysent) && (syscall_strs[code] & (1<u_procp; code = rp->r_g1; #ifdef MULTIPROCESSOR if (klock) klkbusydokv++; klock_enter(); #endif syscalldokv++; cnt.v_syscall++; /* * take any pending floating point exceptions now */ syncfpu(rp); up->u_ar0 = (int *)rp; if (code >= nsysent) callp = &sysent[63]; else callp = &sysent[code]; up->u_error = 0; if ((callp->sy_narg > 6) || (procp->p_flag & STRCSYS)) { /* * Copy registers and stack arguments into u.u_arg array. */ up->u_arg[0] = rp->r_o0; up->u_arg[1] = rp->r_o1; up->u_arg[2] = rp->r_o2; up->u_arg[3] = rp->r_o3; up->u_arg[4] = rp->r_o4; up->u_arg[5] = rp->r_o5; if (copyin((addr_t)rp->r_sp + MINFRAME, (addr_t)&up->u_arg[6], (u_int)((callp->sy_narg - 6) * sizeof (int)))) { up->u_eosys = NORMALRETURN; up->u_error = EFAULT; goto bad; } up->u_ap = up->u_arg; } else { /* * Use the registers as arguments. */ up->u_ap = &rp->r_o0; } up->u_r.r_val1 = 0; up->u_r.r_val2 = rp->r_o1; up->u_eosys = NORMALRETURN; trace6(TR_SYSCALL, code, u.u_arg[0], u.u_arg[1], u.u_arg[2], u.u_arg[3], u.u_arg[4]); #ifdef SYSCALLTRACE if (syscalltrace) { register int i; char *cp; printf("%d: ", u.u_procp->p_pid); if (code >= nsysent) printf("0x%x", code); else printf("%s", syscallnames[code]); cp = "("; for (i= 0; i < callp->sy_narg; i++) { printf("%s%x", cp, u.u_ap[i]); cp = ", "; } if (i) printf(")"); printf("\n"); } #endif /* * If tracing sys calls signal a trap. * System call code is slipped into u_arg[7]. * No system call has 8 args (at the present time!). */ if ((procp->p_flag & STRCSYS) && code != 0) { int s, save_sigmask; procp->p_flag &= ~STRCSYS; up->u_arg[7] = code; psignal(procp, SIGTRAP); s = splhigh(); save_sigmask = procp->p_sigmask; procp->p_sigmask = ~sigmask(SIGTRAP); (void) issig(0); procp->p_sigmask = save_sigmask; (void) splx(s); } #ifdef just_for_reference if (setjmp(&u.u_qsave)) { if (up->u_error == 0 && up->u_eosys == NORMALRETURN) up->u_error = EINTR; } else { (*(callp->sy_call))(up->u_ap); } #endif return (callp->sy_call); bad: return (NULL); } void syscall_postamble(rp) register struct regs *rp; { register struct user *up; register struct proc *procp; register unsigned code; register struct sysent *callp; up = &u; procp = up->u_procp; if (up->u_eosys == NORMALRETURN) { if (up->u_error) { #ifdef SYSCALLTRACE if (syscalltrace) printf("syscall: error=%d\n", u.u_error); #endif rp->r_o0 = up->u_error; rp->r_psr |= PSR_C; /* set carry bit */ } else { rp->r_psr &= ~PSR_C; /* reset carry bit */ rp->r_o0 = up->u_r.r_val1; rp->r_o1 = up->u_r.r_val2; } /* * The default action is to redo the trap instruction. * We increment the pc and npc past it for NORMALRETURN. * JUSTRETURN has set up a new pc and npc already. * RESTARTSYS automatically restarts by leaving pc and npc * alone. */ rp->r_pc = rp->r_npc; rp->r_npc += 4; } /* If tracing sys calls signal a trap */ if (procp->p_flag & STRCSYS) { procp->p_flag &= ~STRCSYS; up->u_arg[7] = 0; psignal(procp, SIGTRAP); } if (((procp->p_flag & STRC) == 0 && procp->p_cursig) || ISSIG(procp, 0)) psig(); procp->p_pri = procp->p_usrpri; } void syscall_userprof(rp, pid, sec, usec) register struct regs *rp; int pid; long sec; long usec; { register int ticks; struct timeval *tv = &u.u_ru.ru_stime; /* * If pid != pp->p_pid, then we are the child returning from * a "fork" or "vfork" system call. In this case, reset * "syst", since our time was reset in fork. */ if (pid != u.u_procp->p_pid) { sec = usec = 0; } ticks = ((tv->tv_sec - sec) * 1000 + (tv->tv_usec - usec) / 1000) / (tick / 1000); if (ticks) addupc(rp->r_pc, &u.u_prof, ticks); } #else /* SUNDBE */ /* * Called from the trap handler when a system call occurs */ void syscall(rp) register struct regs *rp; { register unsigned code; register struct sysent *callp; register struct proc *p; register syst_flag; struct timeval syst; register short pid; #ifdef MULTIPROCESSOR klock_enter(); #endif MULTIPROCESSOR code = rp->r_g1; cnt.v_syscall++; if (u.u_prof.pr_scale) { syst = u.u_ru.ru_stime; syst_flag = 1; pid = u.u_procp->p_pid; } else syst_flag = 0; #ifdef notdef if (!USERMODE(rp->r_psr)) panic("syscall"); #endif /* * take any pending floating point exceptions now */ syncfpu(rp); u.u_ar0 = (int *)rp; if (code >= nsysent) callp = &sysent[63]; else callp = &sysent[code]; u.u_error = 0; if ((callp->sy_narg > 6) || (u.u_procp->p_flag & STRCSYS)) { /* * Copy registers and stack arguments into u.u_arg array. */ u.u_arg[0] = rp->r_o0; u.u_arg[1] = rp->r_o1; u.u_arg[2] = rp->r_o2; u.u_arg[3] = rp->r_o3; u.u_arg[4] = rp->r_o4; u.u_arg[5] = rp->r_o5; if (copyin((addr_t)rp->r_sp + MINFRAME, (addr_t)&u.u_arg[6], (u_int)((callp->sy_narg - 6) * sizeof (int)))) { u.u_error = EFAULT; goto bad; } u.u_ap = u.u_arg; } else { /* * Use the registers as arguments. */ u.u_ap = &rp->r_o0; } u.u_r.r_val1 = 0; u.u_r.r_val2 = rp->r_o1; if (setjmp(&u.u_qsave)) { if (u.u_error == 0 && u.u_eosys == NORMALRETURN) u.u_error = EINTR; } else { u.u_eosys = NORMALRETURN; trace6(TR_SYSCALL, code, u.u_arg[0], u.u_arg[1], u.u_arg[2], u.u_arg[3], u.u_arg[4]); #ifdef SYSCALLTRACE if (syscalltrace & 1) prsct(code, callp->sy_narg, " ...", 0); #endif SYSCALLTRACE /* * If tracing sys calls signal a trap. * System call code is slipped into u_arg[7]. * No system call has 8 args (at the present time!). */ if ((u.u_procp->p_flag & STRCSYS) && code != 0) { int s, save_sigmask; u.u_procp->p_flag &= ~STRCSYS; u.u_arg[7] = code; psignal(u.u_procp, SIGTRAP); s = splhigh(); save_sigmask = u.u_procp->p_sigmask; u.u_procp->p_sigmask = ~sigmask(SIGTRAP); (void) issig(0); u.u_procp->p_sigmask = save_sigmask; (void) splx(s); } (*(callp->sy_call))(u.u_ap); } if (u.u_eosys == NORMALRETURN) { if (u.u_error) { bad: #ifdef SYSCALLTRACE if (syscalltrace & 2) prsct(code, callp->sy_narg, " error %d", u.u_error); #endif rp->r_o0 = u.u_error; rp->r_psr |= PSR_C; /* set carry bit */ } else { #ifdef SYSCALLTRACE if (syscalltrace & 4) prsct(code, callp->sy_narg, " returns 0x%x", u.u_r.r_val1); #endif rp->r_psr &= ~PSR_C; /* reset carry bit */ rp->r_o0 = u.u_r.r_val1; rp->r_o1 = u.u_r.r_val2; } /* * The default action is to redo the trap instruction. * We increment the pc and npc past it for NORMALRETURN. * JUSTRETURN has set up a new pc and npc already. * RESTARTSYS automatically restarts by leaving pc and npc * alone. */ rp->r_pc = rp->r_npc; rp->r_npc += 4; } /* If tracing sys calls signal a trap */ if (u.u_procp->p_flag & STRCSYS) { u.u_procp->p_flag &= ~STRCSYS; u.u_arg[7] = 0; psignal(u.u_procp, SIGTRAP); } p = u.u_procp; if (((p->p_flag & STRC) == 0 && p->p_cursig) || ISSIG(p, 0)) psig(); if (runrun) { /* * Since we are u.u_procp, clock will normally just change * our priority without moving us from one queue to another * (since the running process is not on a queue.) * If that happened after we setrq ourselves but before we * swtch()'ed, we might not be on the queue indicated by * our priority. */ (void) spl6(); p->p_pri = p->p_usrpri; setrq(p); u.u_ru.ru_nivcsw++; swtch(); (void) spl0(); } else { p->p_pri = p->p_usrpri; } if (syst_flag && u.u_prof.pr_scale) { register int ticks; struct timeval *tv = &u.u_ru.ru_stime; /* * If pid != pp->p_pid, then we are the child returning from * a "fork" or "vfork" system call. In this case, reset * "syst", since our time was reset in fork. */ if (pid != p->p_pid) timerclear(&syst); ticks = ((tv->tv_sec - syst.tv_sec) * 1000 + (tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000); if (ticks) addupc(rp->r_pc, &u.u_prof, ticks); } curpri = p->p_pri; } #endif /* SUNDBE */ /* * Indirect system call. * Used to be handled above, in syscall, but then everyone * was paying a performance penalty for this rarely-used * (and questionable) feature. */ indir() { register unsigned code; register int *sp, *dp; register struct sysent *callp; register int a; code = (unsigned) u.u_ap[0]; if (code == 0 || code >= nsysent) callp = &sysent[63]; else callp = &sysent[code]; u.u_error = 0; /* * Shift the valid args down 1 and copy into u.u_arg array. */ a = MIN(callp->sy_narg, 5); sp = &u.u_ap[1]; dp = &u.u_arg[0]; while (sp <= (int *)&u.u_ap[a]) { *dp++ = *sp++; } /* * Copy in any new args. */ if (callp->sy_narg > 5) { if (copyin((addr_t)u.u_ar0[SP] + MINFRAME, (addr_t)&u.u_arg[5], (u_int)((callp->sy_narg - 5) * sizeof (int)))) { u.u_error = EFAULT; return; } } u.u_ap = u.u_arg; #ifdef SYSCALLTRACE if (syscalltrace & 8) prsct(code, callp->sy_narg, " ...", 0); #endif if (u.u_procp->p_flag & STRCSYS) { int s, save_sigmask; u.u_procp->p_flag &= ~STRCSYS; u.u_arg[7] = code; psignal(u.u_procp, SIGTRAP); s = splhigh(); save_sigmask = u.u_procp->p_sigmask; u.u_procp->p_sigmask = ~sigmask(SIGTRAP); (void) issig(0); u.u_procp->p_sigmask = save_sigmask; (void) splx(s); } #ifdef SUNDBE /* * The below is inline semsys() from os/ipc_sem.c */ if (code == SYS_semsys) { int semctl(), semget(), semop(); static int (*calls[])() = {semctl, semget, semop}; register struct a { uint id; /* function code id */ } *uap = (struct a *)u.u_ap; if (uap->id > 2) { u.u_error = EINVAL; return; } u.u_ap = &u.u_arg[1]; (*calls[uap->id])(); return; } #endif /* SUNDBE */ (*(callp->sy_call))(u.u_ap); } /* * nonexistent system call-- signal process (may want to handle it) * flag error if process won't see signal immediately * Q: should we do that all the time ?? */ nosys() { if (u.u_signal[SIGSYS] == SIG_IGN || u.u_signal[SIGSYS] == SIG_HOLD) u.u_error = EINVAL; psignal(u.u_procp, SIGSYS); } /* * Print out a traceback for kernel traps */ traceback(sp) caddr_t sp; { register u_int tospage; register struct frame *fp; static int done = 0; if (panicstr && done++ > 0) return; if ((int)sp & (STACK_ALIGN-1)) { printf("traceback: misaligned sp = %x\n", sp); return; } flush_windows(); tospage = (u_int)btoc(sp); fp = (struct frame *)sp; printf("Begin traceback... sp = %x\n", sp); while (btoc((u_int)fp) == tospage) { if (fp == fp->fr_savfp) { printf("FP loop at %x", fp); break; } printf("Called from %x, fp=%x, args=%x %x %x %x %x %x\n", fp->fr_savpc, fp->fr_savfp, fp->fr_arg[0], fp->fr_arg[1], fp->fr_arg[2], fp->fr_arg[3], fp->fr_arg[4], fp->fr_arg[5]); #ifdef notdef printf("\tl0-l7: %x, %x, %x, %x, %x, %x, %x, %x\n", fp->fr_local[0], fp->fr_local[1], fp->fr_local[2], fp->fr_local[3], fp->fr_local[4], fp->fr_local[5], fp->fr_local[6], fp->fr_local[7]); #endif fp = fp->fr_savfp; if (fp == 0) break; } printf("End traceback...\n"); #ifndef SAS #ifdef VAC vac_flush((caddr_t)&msgbuf, sizeof (msgbuf)); /* push msgbuf to mem */ #endif VAC DELAY(2000000); #endif SAS } /* * General system stack backtrace */ tracedump() { label_t l; (void) setjmp(&l); traceback((caddr_t)l.val[1]); } #ifdef TRAPWINDOW long trap_window[25]; #endif TRAPWINDOW /* * Print out debugging info. */ showregs(type, rp, addr, mmu_fsr, rw) register unsigned type; register struct regs *rp; addr_t addr; u_int mmu_fsr; enum seg_rw rw; { int s; extern u_int mmu_getctx(); trigger_logan(); s = spl7(); type &= ~USER; if (masterprocp == NULL || peekc(u.u_comm) == -1) printf("(unknown): "); else printf("pid %d, `%s': ", masterprocp->p_pid, u.u_comm); if (type < TRAP_TYPES) printf("%s\n", trap_type[type]); else switch (type) { case T_SYSCALL: printf("syscall trap:\n"); break; case T_BREAKPOINT: printf("breakpoint trap:\n"); break; case T_DIV0: printf("zero divide trap:\n"); break; case T_FLUSH_WINDOWS: printf("flush windows trap:\n"); break; case T_SPURIOUS: printf("spurious interrupt:\n"); break; case T_AST: printf("AST\n"); break; default: if (type >= T_SOFTWARE_TRAP && type <= T_ESOFTWARE_TRAP) printf("software trap 0x%x\n", type - T_SOFTWARE_TRAP); else printf("bad trap = %d\n", type); break; } if (type == T_DATA_FAULT || type == T_TEXT_FAULT) { struct pte pte; mmu_getpte(addr, &pte); printf("%s %s fault at addr=0x%x, pme=0x%x\n", (USERMODE(rp->r_psr)? "user": "kernel"), (rw == S_WRITE? "write": "read"), addr, *(u_int *)&pte); mmu_print_sfsr(mmu_fsr); } else if (addr) { printf("addr=0x%x\n", addr); } printf("rp=0x%x, pc=0x%x, sp=0x%x, psr=0x%x, context=0x%x\n", rp, rp->r_pc, rp->r_sp, rp->r_psr, mmu_getctx()); if (USERMODE(rp->r_psr)) { printf("o0-o7: %x, %x, %x, %x, %x, %x, %x, %x\n", rp->r_o0, rp->r_o1, rp->r_o2, rp->r_o3, rp->r_o4, rp->r_o5, rp->r_o6, rp->r_o7); } printf("g1-g7: %x, %x, %x, %x, %x, %x, %x\n", rp->r_g1, rp->r_g2, rp->r_g3, rp->r_g4, rp->r_g5, rp->r_g6, rp->r_g7); #ifdef TRAPWINDOW printf("trap_window: wim=%x\n", trap_window[24]); printf("o0-o7: %x, %x, %x, %x, %x, %x, %x, %x\n", trap_window[0], trap_window[1], trap_window[2], trap_window[3], trap_window[4], trap_window[5], trap_window[6], trap_window[7]); printf("l0-l7: %x, %x, %x, %x, %x, %x, %x, %x\n", trap_window[8], trap_window[9], trap_window[10], trap_window[11], trap_window[12], trap_window[13], trap_window[14], trap_window[15]); printf("i0-i7: %x, %x, %x, %x, %x, %x, %x, %x\n", trap_window[16], trap_window[17], trap_window[18], trap_window[19], trap_window[20], trap_window[21], trap_window[22], trap_window[23]); #endif TRAPWINDOW #ifdef PROM_PARANOIA mpprom_eprintf("PROM_PARANOIA: inside showregs()\n"); #endif PROM_PARANOIA vac_flush((caddr_t)&msgbuf, sizeof (msgbuf)); /* push msgbuf to mem */ #ifndef SAS if (tudebug > 1 && (boothowto & RB_DEBUG)) { CALL_DEBUG(); } #endif SAS (void) splx(s); } /*ARGSUSED*/ sys_rttchk(p, l7, sp) struct proc *p; caddr_t l7, sp; { if (runrun) { /* * Since we are u.u_procp, clock will normally just change * our priority without moving us from one queue to another * (since the running process is not on a queue.) * If that happened after we setrq ourselves but before we * swtch()'ed, we might not be on the queue indicated by * our priority. */ (void) spl6(); #ifdef MULTIPROCESSOR klock_enter(); #endif setrq(p); u.u_ru.ru_nivcsw++; swtch(); (void) spl0(); } #if 0 /* XXX - need to do something about this */ if (syst_flag && u.u_prof.pr_scale) { register int ticks; struct timeval *tv = &u.u_ru.ru_stime; #ifdef MULTIPROCESSOR klock_enter(); #endif /* * If pid != pp->p_pid, then we are the child returning from * a "fork" or "vfork" system call. In this case, reset * "syst", since our time was reset in fork. */ if (pid != p->p_pid) timerclear(&syst); ticks = ((tv->tv_sec - syst.tv_sec) * 1000 + (tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000); if (ticks) addupc(rp->r_pc, &u.u_prof, ticks); } #endif curpri = p->p_pri; } /* * unimplemented and unaligned instruction simulation support */ static int getreg(rgs, rw, reg, val) u_int *rgs, *rw, reg; u_int *val; { if (reg == 0) *val = 0; else if (reg < 16) *val = rgs[reg]; else { if ((*val = fuword((caddr_t)&rw[reg - 16])) == -1) { if (fubyte((caddr_t)&rw[reg - 16]) == -1) { return (-1); } } } return (0); } static int putreg(data, rgs, rw, reg) u_int data, *rgs, *rw, reg; { if (reg == 0) return (0); if (reg < 16) rgs[reg] = data; else { if (suword((caddr_t)&rw[reg - 16], (int)data) != 0) { return (-1); } } return (0); } #ifndef lint u_int dev_null = 0; /* a place to store junk */ /* * calculate the address of a register that will eventually get * restored for a user so it can be changed. */ u_int * getregaddr(rgs, rw, reg) u_int rgs[], rw[]; u_int reg; { if (reg == 0) return (&dev_null); if (reg < 16) return (&rgs[reg]); else return (&rw[reg - 16]); } #endif /* * For the sake of those who must be compatible with unaligned * architectures, users can link their programs to use a * corrective trap handler that will fix unaligned references * a special trap #6 (T_FIX_ALIGN) enables this 'feature'. */ char *sizestr[] = {"word", "byte", "halfword", "double"}; do_unaligned(rp) register struct regs *rp; { register u_int inst; register u_int rd, rs1, rs2; register u_int *rgs; register u_int *rw; register u_int addr; register int sz; register int floatflg; register int immflg; u_int val; extern void _fp_read_pfreg(); extern void _fp_write_pfreg(); union ud { double d; u_int i[2]; u_short s[4]; u_char c[8]; } data; inst = fuword((caddr_t)rp->r_pc); /* get the instruction */ rd = (inst >> 25) & 0x1f; rs1 = (inst >> 14) & 0x1f; rs2 = inst & 0x1f; floatflg = (inst >> 24) & 1; immflg = (inst >> 13) & 1; switch ((inst >> 19) & 3) { /* map size bits to a number */ case 0: sz = 4; break; case 1: printf("alignment botch\n"); return (0); case 2: sz = 2; break; case 3: sz = 8; break; } if (aligndebug) { printf("unaligned access at 0x%x, instruction: 0x%x\n", rp->r_pc, inst); printf("type %s %s %s\n", (((inst >> 21) & 1) ? "st" : "ld"), (((inst >> 22) & 1) ? "signed" : "unsigned"), sizestr[((inst >> 19) & 3)]); printf("rd = %d, rs1 = %d, rs2 = %d, imm13 = 0x%x\n", rd, rs1, rs2, (inst & 0x1fff)); } /* if not load or store, or to alternate space do nothing */ if (((inst >> 30) != 3) || (immflg == 0 && ((inst >> 5) & 0xff))) return (0); flush_user_windows_to_stack(); /* flush windows into memory */ rgs = (u_int *)&rp->r_y; /* globals and outs */ rw = (u_int *)rp->r_sp; /* ins and locals */ /* calculate address, get first register */ if (getreg(rgs, rw, rs1, &val) != 0) return (SIMU_FAULT); addr = val; /* check immediate bit and use immediate field or reg (rs2) */ if (immflg) { register int imm; imm = inst & 0x1fff; /* mask out immediate field */ imm <<= 19; /* sign extend it */ imm >>= 19; addr += imm; /* compute address */ } else { if (getreg(rgs, rw, rs2, &val) != 0) return (SIMU_FAULT); addr += val; } if (aligndebug) printf("addr = 0x%x\n", addr); /* a single bit differentiates ld and st */ if ((inst >> 21) & 1) { /* store */ if (floatflg) { /* if fp read fpu reg */ _fp_read_pfreg((u_int *)&data.i[0], rd); if (sz == 8) _fp_read_pfreg((u_int *)&data.i[1], rd+1); } else { if (getreg(rgs, rw, rd, &val) != 0) return (SIMU_FAULT); data.i[0] = val; if (sz == 8) { if (getreg(rgs, rw, rd+1, &val) != 0) return (SIMU_FAULT); data.i[1] = val; } } if (aligndebug) { printf("data %x %x %x %x %x %x %x %x\n", data.c[0], data.c[1], data.c[2], data.c[3], data.c[4], data.c[5], data.c[6], data.c[7]); } if (sz == 2) { if (copyout((caddr_t)&data.s[1], (caddr_t)addr, (u_int)sz) == -1) return (SIMU_FAULT); } else { if (copyout((caddr_t)&data.i[0], (caddr_t)addr, (u_int)sz) == -1) return (SIMU_FAULT); } } else { /* load */ if (sz == 2) { if (copyin((caddr_t)addr, (caddr_t)&data.s[1], (u_int)sz) == -1) return (SIMU_FAULT); /* if signed and the sign bit is set extend it */ if (((inst >> 22) & 1) && ((data.s[1] >> 15) & 1)) data.s[0] = -1; /* extend sign bit */ else data.s[0] = 0; /* clear upper 16 bits */ } else if (copyin((caddr_t)addr, (caddr_t)&data.i[0], (u_int)sz) == -1) return (SIMU_FAULT); if (aligndebug) { printf("data %x %x %x %x %x %x %x %x\n", data.c[0], data.c[1], data.c[2], data.c[3], data.c[4], data.c[5], data.c[6], data.c[7]); } if (floatflg) { /* if fp, write fpu reg */ _fp_write_pfreg((u_int *)&data.i[0], rd); if (sz == 8) _fp_write_pfreg((u_int *)&data.i[1], rd+1); } else { if (putreg(data.i[0], rgs, rw, rd) == -1) return (SIMU_FAULT); if (sz == 8) if (putreg(data.i[1], rgs, rw, rd+1) == -1) return (SIMU_FAULT); } } return (SIMU_SUCCESS); } /* * simulate unimplemented instructions (swap, mul, div) */ simulate_unimp(rp) struct regs *rp; { register u_int inst, rv; u_int val, wasmul = 1; if ((inst = fuword((caddr_t)rp->r_pc)) == -1){ /* * -1 is an illegal instruction * or a error in fuword, give up now */ return (SIMU_ILLEGAL); } /* * simulation depends on register windows being stack resident */ flush_user_windows_to_stack(); /* * check for the unimplemented iflush instruction * the iflush support is only for th ROSS CPU. Instead of doing a * NOP, the ROSS does a illegal instruction trap. Just ignore * it here and return * The sun4s/sun4cs do a nop * Vikings implement the iflush instruction */ if ((inst & 0xc1f80000) == 0x81d80000) { return (SIMU_SUCCESS); } /* * for mul/div instruction switch on op3 field of instruction * if the two bit op field is 0x2 */ if ((inst >> 30) == 0x2) { register u_int rs1, rs2, rd; register u_int *rgs; /* pointer to struct regs */ register u_int *rw; /* pointer to frame */ u_int dest[2]; /* destination for simulator */ rd = (inst >> 25) & 0x1f; rgs = (u_int *)&rp->r_y; /* globals and outs */ rw = (u_int *)rp->r_sp; /* ins and locals */ /* generate first operand rs1 */ if (getreg(rgs, rw, (inst >> 14) & 0x1f, &val) != 0) return (SIMU_FAULT); rs1 = val; /* check immediate bit and use immediate field or reg (rs2) */ if ((inst >> 13) & 1) { register int imm; imm = inst & 0x1fff; /* mask out immediate field */ imm <<= 19; /* sign extend it */ imm >>= 19; rs2 = imm; /* compute address */ } else { if (getreg(rgs, rw, inst & 0x1f, &val) != 0) return (SIMU_FAULT); rs2 = val; } switch ((inst & 0x01f80000) >> 19) { case 0xa: rv = _ip_umul(rs1, rs2, dest, &rp->r_y, &rp->r_psr); break; case 0xb: rv = _ip_mul(rs1, rs2, dest, &rp->r_y, &rp->r_psr); break; case 0xe: rv = _ip_udiv(rs1, rs2, dest, &rp->r_y, &rp->r_psr); wasmul = 0; break; case 0xf: rv = _ip_div(rs1, rs2, dest, &rp->r_y, &rp->r_psr); wasmul = 0; break; case 0x1a: rv = _ip_umulcc(rs1, rs2, dest, &rp->r_y, &rp->r_psr); break; case 0x1b: rv = _ip_mulcc(rs1, rs2, dest, &rp->r_y, &rp->r_psr); break; case 0x1e: rv = _ip_udivcc(rs1, rs2, dest, &rp->r_y, &rp->r_psr); wasmul = 0; break; case 0x1f: rv = _ip_divcc(rs1, rs2, dest, &rp->r_y, &rp->r_psr); wasmul = 0; break; default: return (SIMU_ILLEGAL); } if (rv != SIMU_SUCCESS) { return (rv); } if (putreg(dest[0], rgs, rw, rd) != 0) { return (SIMU_FAULT); } if (wasmul) rp->r_y = dest[1]; /* put high mul in y */ return (SIMU_SUCCESS); } /* * Otherwise, we can't simulate instruction, its illegal. */ return (SIMU_ILLEGAL); } /* * fix_addr(): used by viking bug workaround. It is here because of getreg * Picks apart the instruction and computes the effective address used by * the instruction. * Remember fix_addr() can be called User and Kernel PCs as well. * Need to do special case for kernel registers */ addr_t fix_addr (rp, mfsr) struct regs *rp; register u_int mfsr; { register u_int inst; u_int rs1, rs2; register u_int *rgs; /* pointer to struct regs */ register u_int *rw; /* pointer to frame */ register u_int err, addr; int kpc = 0; /* Assume User PC */ /* * If the failing PC is in the kernel, can't use fuword() to access * registers and instruction. So figure out whether the PC is in * the user or kernel area. */ if ((u_int)rp->r_pc > (u_int)KERNELBASE) kpc = 1; /* Our case, fix it */ if (kpc) { inst = *(u_int *)rp->r_pc; flush_windows(); } else { if ((inst = fuword((caddr_t)rp->r_pc)) == -1) return ((addr_t)-1); flush_user_windows_to_stack(); } /* * implement workaround for memory operations (format == 3). * The workaround does not apply to coprocessor instructions * (bits 5:4 == 3) because Viking does not support them. */ if (((inst >> 30) != 0x3) || ((inst >> 23 & 0x3) == 3)) return ((addr_t)-1); rgs = (u_int *)&rp->r_y; /* globals and outs */ rw = (u_int *)rp->r_sp; /* ins and locals */ /* generate first operand rs1 */ if (getkureg(rgs, rw, (inst >> 14) & 0x1f, &rs1, kpc) != 0) return ((addr_t)-1); /* check immediate bit and use immediate field or reg (rs2) */ if ((inst >> 13) & 1) { register int imm; imm = inst & 0x1fff; /* mask out immediate field */ imm <<= 19; /* sign extend it */ imm >>= 19; addr = rs1 + imm; } else { if (getkureg(rgs, rw, inst & 0x1f, &rs2, kpc) != 0) return ((addr_t)-1); addr = rs1 + rs2; } return((addr_t)addr); } #ifdef SUNDBE /* * Called from the trap handler when a system call occurs * before syscall() is called. We are still outside of the kernel * lock. If syscallnolock returns nonzero, the trap handler returns * to user. Otherwise, syscall() is called as usual. * * The intention is to do some system calls without having to acquire * the kernel lock. * * Note - We only use it to accelerate the Sybase aiowait() calls. */ int syscallnolock(rp) register struct regs *rp; { register unsigned code; code = rp->r_g1; if (code != SYS_aiowait || dbe_probeawait((struct timeval *)rp->r_o0)) return 0; /* do a normal system call */ rp->r_psr &= ~PSR_C; /* reset carry bit */ rp->r_o0 = 0; rp->r_pc = rp->r_npc; rp->r_npc += 4; return 1; /* return to user */ } #endif /* SUNDBE */ /* * register read support for fix_addr. * Reads kernel or user registers based on arg: kernelargs. */ static int getkureg(rgs, rw, reg, val, kernelregs) u_int *rgs, *rw, reg; u_int *val; int kernelregs; { if (reg == 0) *val = 0; else if (reg < 16) *val = rgs[reg]; else { if (kernelregs) *val = rw[reg - 16]; else { if ((*val = fuword((caddr_t)&rw[reg - 16])) == -1) { if (fubyte((caddr_t)&rw[reg - 16]) == -1) return (-1); } } } return (0); }