📄 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, Ralph Campbell, Sony Corp. and Kazumasa Utashiro * of Software Research Associates, Inc. * * 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.4 (Berkeley) 9/23/93 */#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 <machine/adrsmap.h>#include <vm/vm.h>#include <vm/vm_kern.h>#include <vm/vm_page.h>#include "lp.h"#include "bm.h"#include "ms.h"#include "en.h"#include <news3400/hbdev/dmac_0448.h>#include <news3400/sio/scc.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;#endif/* * 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 COMPAT_NEWSOS extern int nnewssys; extern struct sysent newssys[];#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; code = locr0[V0];#ifdef COMPAT_NEWSOS if (code >= 1000) { code -= 1000; systab = newssys; numsys = nnewssys; }#endif switch (code) { case SYS_syscall: /* * Code is first argument, followed by actual args. */ code = locr0[A0];#ifdef COMPAT_NEWSOS if (code >= 1000) { code -= 1000; systab = newssys; numsys = nnewssys; }#endif 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];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -