📄 trap.c
字号:
/* * Copyright (c) 1988 University of Utah. * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * the Systems Programming Group of the University of Utah Computer * Science Department and Ralph Campbell. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * from: Utah $Hdr: trap.c 1.32 91/04/06$ * * @(#)trap.c 8.5 (Berkeley) 1/11/94 */#include <sys/param.h>#include <sys/systm.h>#include <sys/proc.h>#include <sys/kernel.h>#include <sys/signalvar.h>#include <sys/syscall.h>#include <sys/user.h>#include <sys/buf.h>#ifdef KTRACE#include <sys/ktrace.h>#endif#include <net/netisr.h>#include <machine/trap.h>#include <machine/psl.h>#include <machine/reg.h>#include <machine/cpu.h>#include <machine/pte.h>#include <machine/mips_opcode.h>#include <vm/vm.h>#include <vm/vm_kern.h>#include <vm/vm_page.h>#include <pmax/pmax/clockreg.h>#include <pmax/pmax/kn01.h>#include <pmax/pmax/kn02.h>#include <pmax/pmax/kmin.h>#include <pmax/pmax/maxine.h>#include <pmax/pmax/kn03.h>#include <pmax/pmax/asic.h>#include <pmax/pmax/turbochannel.h>#include <pmax/stand/dec_prom.h>#include <asc.h>#include <sii.h>#include <le.h>#include <dc.h>struct proc *machFPCurProcPtr; /* pointer to last proc to use FP */extern void MachKernGenException();extern void MachUserGenException();extern void MachKernIntr();extern void MachUserIntr();extern void MachTLBModException();extern void MachTLBMissException();extern unsigned MachEmulateBranch();void (*machExceptionTable[])() = {/* * The kernel exception handlers. */ MachKernIntr, /* external interrupt */ MachKernGenException, /* TLB modification */ MachTLBMissException, /* TLB miss (load or instr. fetch) */ MachTLBMissException, /* TLB miss (store) */ MachKernGenException, /* address error (load or I-fetch) */ MachKernGenException, /* address error (store) */ MachKernGenException, /* bus error (I-fetch) */ MachKernGenException, /* bus error (load or store) */ MachKernGenException, /* system call */ MachKernGenException, /* breakpoint */ MachKernGenException, /* reserved instruction */ MachKernGenException, /* coprocessor unusable */ MachKernGenException, /* arithmetic overflow */ MachKernGenException, /* reserved */ MachKernGenException, /* reserved */ MachKernGenException, /* reserved *//* * The user exception handlers. */ MachUserIntr, MachUserGenException, MachUserGenException, MachUserGenException, MachUserGenException, MachUserGenException, MachUserGenException, MachUserGenException, MachUserGenException, MachUserGenException, MachUserGenException, MachUserGenException, MachUserGenException, MachUserGenException, MachUserGenException, MachUserGenException,};char *trap_type[] = { "external interrupt", "TLB modification", "TLB miss (load or instr. fetch)", "TLB miss (store)", "address error (load or I-fetch)", "address error (store)", "bus error (I-fetch)", "bus error (load or store)", "system call", "breakpoint", "reserved instruction", "coprocessor unusable", "arithmetic overflow", "reserved 13", "reserved 14", "reserved 15",};#ifdef DEBUG#define TRAPSIZE 10struct trapdebug { /* trap history buffer for debugging */ u_int status; u_int cause; u_int vadr; u_int pc; u_int ra; u_int code;} trapdebug[TRAPSIZE], *trp = trapdebug;#endifstatic void pmax_errintr();static void kn02_errintr(), kn02ba_errintr();#ifdef DS5000_240static void kn03_errintr();#endifstatic unsigned kn02ba_recover_erradr();extern tc_option_t tc_slot_info[TC_MAX_LOGICAL_SLOTS];extern u_long kmin_tc3_imask, xine_tc3_imask;extern const struct callback *callv;#ifdef DS5000_240extern u_long kn03_tc3_imask;#endifint (*pmax_hardware_intr)() = (int (*)())0;extern volatile struct chiptime *Mach_clock_addr;/* * Handle an exception. * Called from MachKernGenException() or MachUserGenException() * when a processor trap occurs. * In the case of a kernel trap, we return the pc where to resume if * ((struct pcb *)UADDR)->pcb_onfault is set, otherwise, return old pc. */unsignedtrap(statusReg, causeReg, vadr, pc, args) unsigned statusReg; /* status register at time of the exception */ unsigned causeReg; /* cause register at time of exception */ unsigned vadr; /* address (if any) the fault occured on */ unsigned pc; /* program counter where to continue */{ register int type, i; unsigned ucode = 0; register struct proc *p = curproc; u_quad_t sticks; vm_prot_t ftype; extern unsigned onfault_table[];#ifdef DEBUG trp->status = statusReg; trp->cause = causeReg; trp->vadr = vadr; trp->pc = pc; trp->ra = !USERMODE(statusReg) ? ((int *)&args)[19] : p->p_md.md_regs[RA]; trp->code = 0; if (++trp == &trapdebug[TRAPSIZE]) trp = trapdebug;#endif cnt.v_trap++; type = (causeReg & MACH_CR_EXC_CODE) >> MACH_CR_EXC_CODE_SHIFT; if (USERMODE(statusReg)) { type |= T_USER; sticks = p->p_sticks; } /* * Enable hardware interrupts if they were on before. * We only respond to software interrupts when returning to user mode. */ if (statusReg & MACH_SR_INT_ENA_PREV) splx((statusReg & MACH_HARD_INT_MASK) | MACH_SR_INT_ENA_CUR); switch (type) { case T_TLB_MOD: /* check for kernel address */ if ((int)vadr < 0) { register pt_entry_t *pte; register unsigned entry; register vm_offset_t pa; pte = kvtopte(vadr); entry = pte->pt_entry;#ifdef DIAGNOSTIC if (!(entry & PG_V) || (entry & PG_M)) panic("trap: ktlbmod: invalid pte");#endif if (entry & PG_RO) { /* write to read only page in the kernel */ ftype = VM_PROT_WRITE; goto kernel_fault; } entry |= PG_M; pte->pt_entry = entry; vadr &= ~PGOFSET; MachTLBUpdate(vadr, entry); pa = entry & PG_FRAME;#ifdef ATTR pmap_attributes[atop(pa)] |= PMAP_ATTR_MOD;#else if (!IS_VM_PHYSADDR(pa)) panic("trap: ktlbmod: unmanaged page"); PHYS_TO_VM_PAGE(pa)->flags &= ~PG_CLEAN;#endif return (pc); } /* FALLTHROUGH */ case T_TLB_MOD+T_USER: { register pt_entry_t *pte; register unsigned entry; register vm_offset_t pa; pmap_t pmap = &p->p_vmspace->vm_pmap; if (!(pte = pmap_segmap(pmap, vadr))) panic("trap: utlbmod: invalid segmap"); pte += (vadr >> PGSHIFT) & (NPTEPG - 1); entry = pte->pt_entry;#ifdef DIAGNOSTIC if (!(entry & PG_V) || (entry & PG_M)) panic("trap: utlbmod: invalid pte");#endif if (entry & PG_RO) { /* write to read only page */ ftype = VM_PROT_WRITE; goto dofault; } entry |= PG_M; pte->pt_entry = entry; vadr = (vadr & ~PGOFSET) | (pmap->pm_tlbpid << VMMACH_TLB_PID_SHIFT); MachTLBUpdate(vadr, entry); pa = entry & PG_FRAME;#ifdef ATTR pmap_attributes[atop(pa)] |= PMAP_ATTR_MOD;#else if (!IS_VM_PHYSADDR(pa)) panic("trap: utlbmod: unmanaged page"); PHYS_TO_VM_PAGE(pa)->flags &= ~PG_CLEAN;#endif if (!USERMODE(statusReg)) return (pc); goto out; } case T_TLB_LD_MISS: case T_TLB_ST_MISS: ftype = (type == T_TLB_ST_MISS) ? VM_PROT_WRITE : VM_PROT_READ; /* check for kernel address */ if ((int)vadr < 0) { register vm_offset_t va; int rv; kernel_fault: va = trunc_page((vm_offset_t)vadr); rv = vm_fault(kernel_map, va, ftype, FALSE); if (rv == KERN_SUCCESS) return (pc); if (i = ((struct pcb *)UADDR)->pcb_onfault) { ((struct pcb *)UADDR)->pcb_onfault = 0; return (onfault_table[i]); } goto err; } /* * It is an error for the kernel to access user space except * through the copyin/copyout routines. */ if ((i = ((struct pcb *)UADDR)->pcb_onfault) == 0) goto err; /* check for fuswintr() or suswintr() getting a page fault */ if (i == 4) return (onfault_table[i]); goto dofault; case T_TLB_LD_MISS+T_USER: ftype = VM_PROT_READ; goto dofault; case T_TLB_ST_MISS+T_USER: ftype = VM_PROT_WRITE; dofault: { register vm_offset_t va; register struct vmspace *vm; register vm_map_t map; int rv; vm = p->p_vmspace; map = &vm->vm_map; va = trunc_page((vm_offset_t)vadr); rv = vm_fault(map, va, ftype, FALSE); /* * If this was a stack access we keep track of the maximum * accessed stack size. Also, if vm_fault gets a protection * failure it is due to accessing the stack region outside * the current limit and we need to reflect that as an access * error. */ if ((caddr_t)va >= vm->vm_maxsaddr) { if (rv == KERN_SUCCESS) { unsigned nss; nss = clrnd(btoc(USRSTACK-(unsigned)va)); if (nss > vm->vm_ssize) vm->vm_ssize = nss; } else if (rv == KERN_PROTECTION_FAILURE) rv = KERN_INVALID_ADDRESS; } if (rv == KERN_SUCCESS) { if (!USERMODE(statusReg)) return (pc); goto out; } if (!USERMODE(statusReg)) { if (i = ((struct pcb *)UADDR)->pcb_onfault) { ((struct pcb *)UADDR)->pcb_onfault = 0; return (onfault_table[i]); } goto err; } ucode = vadr; i = (rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV; break; } case T_ADDR_ERR_LD+T_USER: /* misaligned or kseg access */ case T_ADDR_ERR_ST+T_USER: /* misaligned or kseg access */ case T_BUS_ERR_IFETCH+T_USER: /* BERR asserted to cpu */ case T_BUS_ERR_LD_ST+T_USER: /* BERR asserted to cpu */ i = SIGSEGV; break; case T_SYSCALL+T_USER: { register int *locr0 = p->p_md.md_regs; register struct sysent *callp; unsigned int code; int numsys; struct args { int i[8]; } args; int rval[2]; struct sysent *systab; extern int nsysent;#ifdef ULTRIXCOMPAT extern struct sysent ultrixsysent[]; extern int ultrixnsysent;#endif cnt.v_syscall++; /* compute next PC after syscall instruction */ if ((int)causeReg < 0) locr0[PC] = MachEmulateBranch(locr0, pc, 0, 0); else locr0[PC] += 4; systab = sysent; numsys = nsysent;#ifdef ULTRIXCOMPAT if (p->p_md.md_flags & MDP_ULTRIX) { systab = ultrixsysent; numsys = ultrixnsysent; }#endif code = locr0[V0]; switch (code) { case SYS_syscall: /* * Code is first argument, followed by actual args. */ code = locr0[A0]; if (code >= numsys) callp = &systab[SYS_syscall]; /* (illegal) */ else callp = &systab[code]; i = callp->sy_narg; args.i[0] = locr0[A1]; args.i[1] = locr0[A2]; args.i[2] = locr0[A3]; if (i > 3) { i = copyin((caddr_t)(locr0[SP] + 4 * sizeof(int)), (caddr_t)&args.i[3], (u_int)(i - 3) * sizeof(int)); if (i) { locr0[V0] = i; locr0[A3] = 1;#ifdef KTRACE if (KTRPOINT(p, KTR_SYSCALL)) ktrsyscall(p->p_tracep, code, callp->sy_narg, args.i);#endif goto done; } } break; case SYS___syscall: /* * Like syscall, but code is a quad, so as to maintain * quad alignment for the rest of the arguments. */ code = locr0[A0 + _QUAD_LOWWORD]; if (code >= numsys) callp = &systab[SYS_syscall]; /* (illegal) */ else callp = &systab[code]; i = callp->sy_narg; args.i[0] = locr0[A2]; args.i[1] = locr0[A3]; if (i > 2) { i = copyin((caddr_t)(locr0[SP] + 4 * sizeof(int)), (caddr_t)&args.i[2], (u_int)(i - 2) * sizeof(int)); if (i) { locr0[V0] = i; locr0[A3] = 1;#ifdef KTRACE if (KTRPOINT(p, KTR_SYSCALL)) ktrsyscall(p->p_tracep, code, callp->sy_narg, args.i);#endif goto done; } } break; default: if (code >= numsys) callp = &systab[SYS_syscall]; /* (illegal) */ else callp = &systab[code]; i = callp->sy_narg; args.i[0] = locr0[A0]; args.i[1] = locr0[A1]; args.i[2] = locr0[A2]; args.i[3] = locr0[A3]; if (i > 4) { i = copyin((caddr_t)(locr0[SP] + 4 * sizeof(int)), (caddr_t)&args.i[4], (u_int)(i - 4) * sizeof(int)); if (i) { locr0[V0] = i; locr0[A3] = 1;#ifdef KTRACE if (KTRPOINT(p, KTR_SYSCALL)) ktrsyscall(p->p_tracep, code, callp->sy_narg, args.i);#endif goto done; } } }#ifdef KTRACE if (KTRPOINT(p, KTR_SYSCALL)) ktrsyscall(p->p_tracep, code, callp->sy_narg, args.i);#endif rval[0] = 0; rval[1] = locr0[V1];#ifdef DEBUG if (trp == trapdebug) trapdebug[TRAPSIZE - 1].code = code; else trp[-1].code = code;#endif i = (*callp->sy_call)(p, &args, rval); /* * Reinitialize proc pointer `p' as it may be different * if this is a child returning from fork syscall. */ p = curproc; locr0 = p->p_md.md_regs;#ifdef DEBUG { int s; s = splhigh(); trp->status = statusReg; trp->cause = causeReg; trp->vadr = locr0[SP]; trp->pc = locr0[PC]; trp->ra = locr0[RA]; trp->code = -code; if (++trp == &trapdebug[TRAPSIZE]) trp = trapdebug; splx(s); }#endif switch (i) { case 0: locr0[V0] = rval[0]; locr0[V1] = rval[1]; locr0[A3] = 0; break; case ERESTART: locr0[PC] = pc; break; case EJUSTRETURN: break; /* nothing to do */ default: locr0[V0] = i; locr0[A3] = 1; } done:#ifdef KTRACE if (KTRPOINT(p, KTR_SYSRET)) ktrsysret(p->p_tracep, code, i, rval[0]);#endif goto out; } case T_BREAK+T_USER: { register unsigned va, instr; /* compute address of break instruction */ va = pc; if ((int)causeReg < 0) va += 4; /* read break instruction */ instr = fuiword((caddr_t)va);#if 0 printf("trap: %s (%d) breakpoint %x at %x: (adr %x ins %x)\n", p->p_comm, p->p_pid, instr, pc, p->p_md.md_ss_addr, p->p_md.md_ss_instr); /* XXX */#endif#ifdef KADB if (instr == MACH_BREAK_BRKPT || instr == MACH_BREAK_SSTEP) goto err;#endif if (p->p_md.md_ss_addr != va || instr != MACH_BREAK_SSTEP) { i = SIGTRAP; break; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -