📄 trap.c
字号:
u.u_error = copyin(ep[EF_SP]+4*sizeof(int), params, nargs*sizeof(int)); if (u.u_error) goto done; } u.u_r.r_val1 = 0; u.u_r.r_val2 = ep[EF_V1]; if (setjmp(&u.u_qsave)) { if (CURRENT_CPUDATA->cpu_hlock) { while(CURRENT_CPUDATA->cpu_hlock) { mprintf("lock held on syscall exit %x pc %x\n", CURRENT_CPUDATA->cpu_hlock, CURRENT_CPUDATA->cpu_hlock->l_pc); smp_unlock(CURRENT_CPUDATA->cpu_hlock); } } if (u.u_error == 0 && u.u_eosys != RESTARTSYS) u.u_error = EINTR; } else { if ( audswitch == 0) {#ifdef ultrix#ifdef SYS_TRACE /* trace it just before we do it! (only if open) */ if (traceopens) { syscall_trace(code,callp->sy_narg,BEFORE); (*(callp->sy_call))(u.u_arg); syscall_trace(code,callp->sy_narg,AFTER); } else#endif SYS_TRACE#endif ultrix (*(callp->sy_call))(u.u_arg); } else { u.u_narg = callp->sy_narg; u.u_gno_indx = 0; u.u_event = code;#ifdef ultrix#ifdef SYS_TRACE /* trace it just before we do it! (only if open) */ if (traceopens) { syscall_trace(code,callp->sy_narg,BEFORE); (*(callp->sy_call))(u.u_arg); syscall_trace(code,callp->sy_narg,AFTER); } else#endif SYS_TRACE#endif ultrix (*(callp->sy_call))(u.u_arg); if ( aud_param[code][AUD_NPARAM-1] != 'X' ) AUDIT_CALL ( code, u.u_error, u.u_r.r_val1, AUD_GNO|AUD_HDR|AUD_PRM|AUD_RES, (int *)0, 0 ); } }done: /* * a3 is returned to user 0 if indicate no errors on syscall, * non-zero otherwise */ if (u.u_eosys == NORMALRETURN) { if (u.u_error) { ep[EF_V0] = u.u_error; ep[EF_A3] = 1; } else { ep[EF_V0] = u.u_r.r_val1; ep[EF_V1] = u.u_r.r_val2; ep[EF_A3] = 0; } } else if (u.u_eosys == RESTARTSYS) ep[EF_EPC] -= 4; /* else if (u.u_eosys == FULLRESTORE) */ /* returning from sigreturn, force full state restore */ p = u.u_procp; if (p->p_cursig || ISSIG(p,0)) psig(); pcpu = CURRENT_CPUDATA; if (smp) { if (p->p_affinity != ALLCPU) { if (p != pcpu->cpu_fpowner) { p->p_affinity = ALLCPU; } } } pcpu->cpu_syscall++; p->p_pri = p->p_usrpri; if (pcpu->cpu_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) splclock(); smp_lock(&lk_rq,LK_RETRY); setrq(p); u.u_ru.ru_nivcsw++; swtch(); } /* * if single stepping this process, install breakpoints before * returning to user mode. Do this here rather than in procxmt * so single stepping will work when signals are delivered. */ if (u.u_pcb.pcb_sstep) install_bp(); if (u.u_prof.pr_scale > 1) { int ticks = times_to_ticks(&u.u_ru.ru_stime,&syst); if (ticks) addupc(ep[EF_EPC], &u.u_prof, ticks); } /* * if u_eosys == FULLRESTORE, then force full state restore */ return (u.u_eosys == FULLRESTORE);}int iplmask[IPLSIZE]; /* afdfix: this can vary with cpu type */int nstrays;/* * TODO: pending interrupts now come for CAUSE reg which is passed as arg4 */kn01_intr(ep, code, sr, cause)u_int *ep;u_int code, sr, cause;{ register int req; register int prevmask; register int nintr = 0; /* number of interrupts serviced */ extern struct reg_desc cause_desc[], sr_desc[];/* XPRINTF(XPR_INTR, "intr cause=%r sr=%r\n", cause, cause_desc, sr, sr_desc);*/ CURRENT_CPUDATA->cpu_inisr++; prevmask = (sr & SR_IMASK); cause &= prevmask; /* * Should probably direct vector these */ if (req = ffintr(cause)) { nintr++; req--; splx(iplmask[req]);/* XPRINTF(XPR_INTR, "calling intr %d\n", req, 0, 0, 0); */ (*c0vec_tbl[req])(ep); } if (nintr == 0) { nstrays++; } CURRENT_CPUDATA->cpu_intr += nintr; CURRENT_CPUDATA->cpu_inisr--;}/* * Note: stray interrupts cannot happen on the PMAX system */stray_intr(ep)u_int *ep;{ unsigned cause, get_cause(); cause = get_cause(); mprintf("intr: stray interrupt\n"); mprintf("\tPC: 0x%x\n\tCause register: %R\n\tCause register: %R\n\tStatus register: %R\n", ep[EF_EPC], ep[EF_CAUSE], cause_desc, cause, cause_desc, ep[EF_SR], sr_desc);}/* * Interrupt for hard error comes here. * then we call system specific error handling routine. */memintr(ep) u_int *ep; /* exception frame ptr */{ if ((*(cpup->harderr_intr))(ep) < 0) panic("no hard error interrupt routine configured");}buserror(ep)u_int *ep;{ /* * attempt to scrub the error by writing it to zero */ wbadaddr(ep[EF_BADVADDR] &~ (sizeof(int)-1), sizeof(int));}/* * 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);}/* * Masks and constants for the rs field of "coprocessor instructions" (25-21) * which are branch on coprocessor condition instructions. */#define COPz_BC_MASK 0x1a#define COPz_BC 0x08/* * Masks and constants for the rt field of "branch on coprocessor condition * instructions" (20-16). */#define COPz_BC_TF_MASK 0x01#define COPz_BC_TRUE 0x01#define COPz_BC_FALSE 0x00#define PC_JMP_MASK 0xf0000000/* * emulate_branch is used by fpuintr() to calculate the resulting pc of a * branch instruction. It is passed a pointer to the exception frame, * the branch instruction and the floating point control and status register. * The routine returns the resulting pc. This routine will panic() if it * is called with a non-branch instruction or one it does not know how to * emulate. */unsignedemulate_branch(ep, instr, fpc_csr)u_int *ep;unsigned instr;union fpc_csr fpc_csr;{ union mips_instruction cpu_instr; long condition; long rs, rt; cpu_instr.word = instr; /* * The values for the rs and rt registers are taken from the exception * frame and since there is space for the 4 argument save registers and * doesn't save register zero this is accounted for (the +3). */ if(cpu_instr.r_format.rs == 0) rs = 0; else rs = ep[cpu_instr.r_format.rs + 3]; if(cpu_instr.r_format.rt == 0) rt = 0; else rt = ep[cpu_instr.r_format.rt + 3]; switch(cpu_instr.i_format.opcode){ case spec_op: switch(cpu_instr.r_format.func){ case jalr_op: /* r31 has already been updated by the hardware */ case jr_op: return(rs); } break; case jal_op: /* r31 has already been updated by the hardware */ case j_op: return(((ep[EF_EPC] + 4) & PC_JMP_MASK) | (cpu_instr.j_format.target << 2)); case beq_op: condition = rs == rt; goto conditional; case bne_op: condition = rs != rt; goto conditional; case blez_op: condition = rs <= 0; goto conditional; case bgtz_op: condition = rs > 0; goto conditional; case bcond_op: switch(cpu_instr.r_format.rt){ case bltzal_op: /* r31 has already been updated by the hardware */ case bltz_op: condition = rs < 0; goto conditional; case bgezal_op: /* r31 has already been updated by the hardware */ case bgez_op: condition = rs >= 0; goto conditional; } break; case cop1_op: if((cpu_instr.r_format.rs & COPz_BC_MASK) == COPz_BC){ if((cpu_instr.r_format.rt & COPz_BC_TF_MASK) == COPz_BC_TRUE) condition = fpc_csr.fc_struct.condition; else condition = !(fpc_csr.fc_struct.condition); goto conditional; } } /* * For all other instructions (including branch on co-processor 2 & 3) * we panic because this routine is only called when in the branch * delay slot (as indicated by the hardware). */ if (CURRENT_CPUDATA->cpu_noproc) { printf("Unknown branch instruction = 0x%x\n", instr); panic("Unknown branch instruction"); } else { CURRENT_CPUDATA->cpu_fpe_event = u.u_procp; CURRENT_CPUDATA->cpu_fpe_sendsig |= sigmask(SIGILL); setsoftnet(); }conditional: if(condition) return(ep[EF_EPC] + 4 + (cpu_instr.i_format.simmediate << 2)); else return(ep[EF_EPC] + 8);}/* * Fixade() is called to fix unaligned loads and stores. It returns a * zero value if can fix it and a non-zero error code if it can't fix it. * Error codes are: * 1 == its a kernel access from user space. * 2 == we couldn't fixup the alignment. * * Fixade() modifies the destination register (general or * floating-point) for loads or the destination memory location for * stores. Also the epc is advanced past the instruction (possibly to the * target of a branch). */fixade(ep, cause)register u_int *ep;u_int cause;{ union mips_instruction inst, branch_inst; u_int addr, new_epc, word; int error; if(cause & CAUSE_BD){ branch_inst.word = fuiword((caddr_t)ep[EF_EPC]); inst.word = fuiword((caddr_t)(ep[EF_EPC] + 4)); if(branch_inst.i_format.opcode == cop1_op) checkfp(u.u_procp, 0); new_epc = emulate_branch(ep, branch_inst.word, u.u_pcb.pcb_fpc_csr); } else{ inst.word = fuiword((caddr_t)ep[EF_EPC]); new_epc = ep[EF_EPC] + 4; } addr = REGVAL(inst.i_format.rs) + inst.i_format.simmediate; /* * The addresses of both the left and right parts of the reference * have to be checked. If either is a kernel address it is an * illegal reference. */ if(addr >= K0BASE || addr+3 >= K0BASE) return(1); error = 0; switch(inst.i_format.opcode){ case lw_op: error = uload_word(addr, &word); if(inst.i_format.rt == 0) break; else ep[inst.i_format.rt+3] = word; break; case lh_op: error = uload_half(addr, &word); if(inst.i_format.rt == 0) break; else ep[inst.i_format.rt+3] = word; break; case lhu_op: error = uload_uhalf(addr, &word); if(inst.i_format.rt == 0) break; else ep[inst.i_format.rt+3] = word; break; case lwc1_op: checkfp(u.u_procp, 0); error = uload_word(addr, &word); u.u_pcb.pcb_fpregs[inst.i_format.rt] = word; break; case sw_op: error = ustore_word(addr, REGVAL(inst.i_format.rt)); break; case sh_op: error = ustore_half(addr, REGVAL(inst.i_format.rt)); break; case swc1_op: checkfp(u.u_procp, 0); error = ustore_word(addr, u.u_pcb.pcb_fpregs[inst.i_format.rt]); break; default: return(2); } if(error) return(2); ep[EF_EPC] = new_epc; return(0);}/* * Convert a virtual address to a physical address. * The virtual address is NOT guaranteed to be good, so we must continually * check values before referencing pointers. */caddr_tvatophys(va) register caddr_t va; /* the virtual addr to convert to physical */ { caddr_t pa; /* the physical addr */ register struct pte *pte; /* pointer to page table */ register unsigned pf; /* page frame number */ if (IS_KSEG0(va)) pa = (caddr_t)K0_TO_PHYS(va); else if (IS_KSEG1(va)) pa = (caddr_t)K1_TO_PHYS(va); else if (IS_KSEG2(va)) { pte = (struct pte *)(&Sysmap[btop((int)(va) & ~SEG_BITS)]); /* * kseg2 can have a 0 pfnum, but can it be mapped to anything? * if so, don't do the pfnum test here */ if (pte->pg_v && pte->pg_pfnum) pa = (caddr_t)((int)ptob(pte->pg_pfnum) | ((int) (va) & VA_BYTEOFFS)); else pa = (caddr_t)-1; } else if (IS_KUSEG(va)) { if ((pte = vtopte(u.u_procp, btop(va))) == 0) pa = (caddr_t)-1; else if (pte->pg_v && pte->pg_pfnum) pa = (caddr_t)((int)ptob(pte->pg_pfnum) | ((int) (va) & VA_BYTEOFFS)); else pa = (caddr_t)-1; } else pa = (caddr_t)-1; return(pa);}int cpeintvl = CPEINTVL; /* how often to log cache parity err count */int cpecount = 0; /* current cache parity error count */int cpelogcount = 0; /* count at last log *//* * This routine is initially called by startup() (after config), thereafter * it is called by timeout. Its purpose is to log cache parity errors. * The count of cache parity errors is kept by hardclock. */chk_cpe(){ if (cpecount > cpelogcount) { mprintf("Cache parity error count is %d\n", cpecount); cpelogcount = cpecount; } if (cpeintvl > 0) timeout (chk_cpe, (caddr_t) 0, cpeintvl * hz);}/* * Determines what spl we are currently set to. * Returns a define const (see cpu.h) for the integer number corresponding * to the interrupt bits set in the Status Register. * */kn01_whatspl(sr)unsigned sr;{ register int index; /* index into the splm array */ register int imask; /* mask value we are looking for */ register int found = 0; /* Gets us out of the loop */ extern int splm[]; imask = (sr & SR_IMASK); index = (SPLMSIZE); while ((index >= 0) && !found) { index--; switch (index) { case 4: /* not used */ case 3: /* not used */ break; default: if ((splm[index] & SR_IMASK) == imask) { found = 1; } break; } if (found) return(index); } return (0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -