📄 trap.c
字号:
#ifndef lintstatic char *sccsid = "@(#)trap.c 4.9 ULTRIX 3/6/91";#endif lint/************************************************************************ * * * Copyright (c) 1988 by * * Digital Equipment Corporation, Maynard, MA * * All rights reserved. * * * * This software is furnished under a license and may be used and * * copied only in accordance with the terms of such license and * * with the inclusion of the above copyright notice. This * * software or any other copies thereof may not be provided or * * otherwise made available to any other person. No title to and * * ownership of the software is hereby transferred. * * * * This software is derived from software received from the * * University of California, Berkeley, and from Bell * * Laboratories. Use, duplication, or disclosure is subject to * * restrictions under license agreements with University of * * California and with AT&T. * * * * The information in this software is subject to change without * * notice and should not be construed as a commitment by Digital * * Equipment Corporation. * * * * Digital assumes no responsibility for the use or reliability * * of its software on equipment which is not supplied by Digital. * * * ************************************************************************//* ------------------------------------------------------------------ *//* | Copyright Unpublished, MIPS Computer Systems, Inc. All Rights | *//* | Reserved. This software contains proprietary and confidential | *//* | information of MIPS and its suppliers. Use, disclosure or | *//* | reproduction is prohibited without the prior express written | *//* | consent of MIPS. | *//* ------------------------------------------------------------------ *//************************************************************************ * * Modification History: trap.c * * 06-Mar-91 -- jaw * optimize 3min spl changes. * * 20-Feb-91 -- jaw * allow for secondary cpus to run softnet code. * * 19-Dec-90 -- jaw * fix up affinity on syscall exit... takes care of any longjmps * that might not have restored the affinity... * * 10-Aug-90 -- sekhar * cleaned up softnet interrupt handler by removing duplication * of code. also changed softnet to call log_errinfo on a write * timeout. * * 05-Jul-90 -- sekhar * modified softnet interrupt handler for write buffer timeouts * on memory mapped accessed devices. * * 30-Apr-90 Randall Brown * Renamed intr() to kn01_intr() and whatspl() to kn01_whatspl(). This * allows other systems to have different routines to handle the same * thing. These routines are now called through the cpu switch. * * 16-Apr-90 -- jaw * performance fixes for single cpu. * * 29-Mar-90 -- gmm/jaw * Call psignal() in softnet() if the process needs a signal. Result * of changing splhigh() and spl6() to be same as splclock(). * * 14-Feb-90 -- gmm * replace pcpu with CURRENT_CPUDATA in trap() where the process could * context switched and come back on a different processor. * * 30-Dec-89 -- bp * Replaced useage of atintr_level with CPU specific in an interrupt * service routine evaluation. * * 14-Nov-89 -- sekhar * Fixes to turn profiling off when scale set to 1. * * 13-Nov-89 -- afd * Don't panic if we return from cpu specific bus error handler * * 19-Oct-89 -- jmartin * Add TLBMISS_STUCK code to panic if retrying a page fault endlessly. * * 13-Oct-89 gmm * smp changes. Access nofault, nofault_cause etc through cpudata. * Changes for per processor tlbpids. Handle affinity correctly for * system calls. * * 04-Oct-89 jaw * release all locks held when "longjmp" out of a syscall occurs. This * is a tempory fix until code in "soclose" is fixed to handle * interrupted system calls. * * 09-Jun-89 -- scott * added audit support * * 09-Jun-89 -- gmm * Update cpudata structure for number of interrupts. * * 02-May-89 -- jaw, jmartin * fix forkutl to work on mips. * * 07-Apr-89 -- afd * Moved all pmax specific code out to kn01.c. * System specific routines now called thru the cpu switch. * Cleaned out some old unused code. * * 10-Feb-89 -- Randall Brown * Added the global variable 'atintr_level' that get incremented on * every entrance to intr(). This is used by printf() during config * to determine if we are at interrupt level. * * 19-Jan-89 -- Kong * Made routines more generic so that they work for multiple * machines. * * 29-Dec-88 -- Randall Brown * In the 'pmaxconsprint' routine, changed the state of the variable * printstate so that printf (and cprintf) will use the prom * putchar. (only if console is graphic device) * * 15-Dec-1988 afd * Clear MEMERR bit in memintr() routine. * Also fix address calculation in trap() & memintr(); * when we compare a physical address to physmem the physical * address must be converted to pages (btop(pa)). * * 18-Nov-1988 afd (for rr) * Added system call trace hooks. * * 17-Nov-1988 depp * Added addition memory page protection to tlbmiss(), and tlbmod(). * * 09-Nov-1988 jaa * allow process to turn on/off unaligned access messages * * 09-Aug-1988 afd * Added error logging support for PMAX: * - Added error log routines: pmaxlogesrpkt(), pmaxlogmempkt(), * pmaxconsprint(), chk_cpe(). * - Added fault isolation for memory parity error (don't call buserror) * - Call the error log routines from trap() and memintr(). * - Changed fixade() routine to give back failure status. * - Added whatspl() routine to give the current IPL level. * *************************************************************************/#define CNT_TLBMISS_HACK 0#include "../machine/cpu.h"#include "../h/param.h"#include "../h/systm.h"#include "../h/dir.h"#include "../h/user.h"#include "../h/kernel.h"#include "../h/proc.h"#include "../h/conf.h"#include "../h/vm.h"#include "../h/buf.h"#include "../h/syslog.h"#include "../h/ptrace.h"#include "../h/cpudata.h"#include "../h/systrace.h"#include "../h/errlog.h"#include "../h/cmap.h"#include "../net/net/netisr.h"#include "../../machine/common/cpuconf.h"#include "../machine/reg.h"#include "../machine/pte.h"#include "../machine/inst.h"#include "../machine/fpu.h"/* * Exception handling dispatch table. */extern VEC_syscall(), VEC_cpfault(), VEC_trap(), VEC_int(), VEC_tlbmod();extern VEC_tlbmiss(), VEC_breakpoint(), VEC_addrerr(), VEC_ibe(), VEC_dbe();extern VEC_unexp();int (*causevec[16])() = { /* 0: EXC_INT */ VEC_int, /* 1: EXC_MOD */ VEC_tlbmod, /* 2: EXC_RMISS */ VEC_tlbmiss, /* 3: EXC_WMISS */ VEC_tlbmiss, /* 4: EXC_RADE */ VEC_addrerr, /* 5: EXC_WADE */ VEC_addrerr, /* 6: EXC_IBE */ VEC_ibe, /* 7: EXC_DBE */ VEC_dbe, /* 8: EXC_SYSCALL */ VEC_syscall, /* 9: EXC_BREAK */ VEC_breakpoint, /* 10: EXC_II */ VEC_trap, /* 11: EXC_CPU */ VEC_cpfault, /* 12: EXC_OV */ VEC_trap, /* 13: undefined */ VEC_unexp, /* 14: undefined */ VEC_unexp, /* 15: undefined */ VEC_unexp};/* * Interrupt dispatch table */extern softclock(), softnet(), biointr(), netintr(), ttyintr(); extern hardclock(), fpuintr(), memintr();extern struct cpusw *cpup; /* Pointer to cpusw entry for this machine*/extern int mmap_debug;int (*c0vec_tbl[8])();int c0vec_tblsize = {sizeof(c0vec_tbl)}; /* Size in bytes */biointr(){ /* this should be enhanced to determine which SII interrupted and dispatch accordingly. */ sii_intr(0);}netintr(){ /* this should be enhanced to determine which LANCE interrupted and dispatch accordingly. */ lnintr(0);}/* * nofault dispatch table */extern baerror(), cerror(), adderr(), uerror(), uaerror(), softfp_adderr();extern reviderror(), cstrerror(), softfp_insterr(), fixade_error();extern rdnf_error();int (*nofault_pc[NF_NENTRIES])() = { /* unused */ 0, /* NF_BADADDR */ baerror, /* NF_COPYIO */ cerror, /* NF_ADDUPC */ adderr, /* NF_FSUMEM */ uerror, /* NF_USERACC */ uaerror, /* NF_SOFTFP */ softfp_adderr, /* NF_REVID */ reviderror, /* NF_COPYSTR */ cstrerror, /* NF_SOFTFPI */ softfp_insterr, /* NF_FIXADE */ fixade_error, /* NF_INTR */ rdnf_error};/* * Used for decoding break instructions. There is an old standing bug in the * assembler which encoded the break code right justified to bit 16 not to * bit 6 (that's why the BRK_SHIFT is 16 not 6 as would be obvious). */#define BRK_MASK 0xfc00003f#define BRK_SHIFT 16#define BRK_SUBCODE(x) (((x) & ~BRK_MASK) >> BRK_SHIFT)/* * This must be declared as an int array to keep the assembler from * making it gp relative. */extern int sstepbp[];extern struct sysent sysent[];int nsysent;/* * The following two pointer are used in the exception handler as * a pointer to the data that needs to be saved on the exception frame * in the system specific entries. If a particular processor does not * need to use these they must be set to values that can be read * and written. *//* * rpbfix: put in comment */u_int sr_usermask = (SR_IMASK0|SR_IEP|SR_KUP); /* disable IEc, enable IEp, prev umode *//* * TODO: Get parameters in agreement with locore.s */#define USERFAULT 1extern int runrun;extern int k_puac;/* * Called from locore.s (VEC_trap) to handle exception conditions */trap(ep, code, sr, cause) register u_int *ep; /* exception frame ptr */ register u_int code; /* trap code (trap type) */ u_int sr, cause; /* status and cause regs */{ register struct proc *p; register int i, vaddr; struct timeval syst; struct pte *pte; int nofault_save; u_int inst; int signo; struct cpudata *pcpu; pcpu = CURRENT_CPUDATA; syst = u.u_ru.ru_stime; p = u.u_procp; signo = 0; if (USERMODE(sr)) { code |= USERFAULT; } XPRINTF(XPR_TRAP, "trap %R cause %R\n", code, exccode_desc, cause, cause_desc); XPRINTF(XPR_TRAP, "trap sr %r\n", sr, sr_desc, 0, 0); nofault_save = pcpu->cpu_nofault; pcpu->cpu_nofault = 0; switch(code) { case SEXC_PAGEIN: case SEXC_PAGEIN|USERFAULT: /* pagein. */ i = u.u_error; /* ??? the VAX does this ??? */ vaddr = ep[EF_BADVADDR]; pagein(vaddr, 0); u.u_error = i; pte = vtopte(p, btop(vaddr)); tlbdropin(p->p_tlbpid, vaddr, *(int *)pte); if (code == SEXC_PAGEIN) goto done; break; case EXC_RMISS|USERFAULT: /* from softfp nofault code */ case EXC_WMISS|USERFAULT: /* from softfp nofault code */ code = SEXC_SEGV|USERFAULT; /* fall through */ case SEXC_SEGV|USERFAULT: XPRINTF(XPR_TRAP, "trap USER SEGV badva 0x%x", ep[EF_BADVADDR], 0, 0, 0); if (grow(ep[EF_BADVADDR])) break; XPRINTF(XPR_TRAP, "trap SEGV grow failed", 0, 0, 0, 0); u.u_code = code & ~USERFAULT; XPRINTF(XPR_SM,"SIGSEGV: faulting addr 0x%x",ep[EF_BADVADDR], 0,0,0); signo = SIGSEGV; break; case SEXC_RESCHED|USERFAULT: astoff(); if ((u.u_oweupc&SOWEUPC) && (u.u_prof.pr_scale > 1)) { addupc(ep[EF_EPC], &u.u_prof, 1); u.u_oweupc &= ~SOWEUPC; } break; case EXC_II|USERFAULT: case SEXC_CPU|USERFAULT: u.u_code = code & ~USERFAULT; signo = SIGILL; break; case EXC_OV|USERFAULT: u.u_code = code & ~USERFAULT; signo = SIGFPE; break; case EXC_DBE|USERFAULT: /* * interpret instruction to calculate faulting address */ ep[EF_BADVADDR] = ldst_addr(ep); /* fall through */ case EXC_IBE|USERFAULT: u.u_code = code & ~USERFAULT; /* * Call processor specific routine to handle trap error. * "signo" is passed as a return parameter: it gets set to * SIGBUS if we want to terminate the user process. * If the system needs to panic, it does so in the processor * specific routine. */ if ((*(cpup->machcheck))(ep, code, sr, cause, &signo) < 0) panic("no trap error routine configured"); break; case EXC_RADE|USERFAULT: case EXC_WADE|USERFAULT: if(u.u_procp->p_mips_flag & SFIXADE) { if((i = fixade(ep, cause)) == 0) { /* success */ if( k_puac && p->p_puac) { mprintf("Fixed up unaligned data access for pid %d (%s) at pc 0x%x\n", p->p_pid, u.u_comm, ep[EF_EPC]); uprintf("Fixed up unaligned data access for pid %d (%s) at pc 0x%x\n", p->p_pid, u.u_comm, ep[EF_EPC]); } break; } uprintf("pid %d (%s) was killed on %s access, at pc 0x%x \n", p->p_pid, u.u_comm, (i == 1 ? "a kernel" : "an unaligned"), ep[EF_EPC]); } u.u_code = code & ~USERFAULT; signo = SIGBUS; break; case EXC_BREAK|USERFAULT: signo = SIGTRAP; vaddr = ep[EF_EPC]; if (ep[EF_CAUSE] & CAUSE_BD) vaddr += 4; inst = fuiword((caddr_t)vaddr); u.u_trapcause = (inst == *sstepbp) ? CAUSESINGLE : CAUSEBREAK; u.u_code = BRK_SUBCODE(inst); break; case SEXC_SEGV: if (nofault_save && grow(ep[EF_BADVADDR])) goto done; goto chk_nofault; case EXC_DBE: /* * interpret instruction to calculate faulting address */ ep[EF_BADVADDR] = ldst_addr(ep); /* fall through */ case EXC_CPU: case EXC_IBE: case EXC_RADE: case EXC_WADE:chk_nofault: /* nofault handler */ if (nofault_save) { extern (*nofault_pc[])(); CURRENT_CPUDATA->cpu_nofault_cause = cause; CURRENT_CPUDATA->cpu_nofault_badvaddr = ep[EF_BADVADDR]; i = nofault_save; nofault_save = 0; if (i < 1 || i >= NF_NENTRIES) panic("bad nofault"); ep[EF_EPC] = (u_int)nofault_pc[i]; goto done; } /* fall through to default */ default: /* * Kernel mode errors. * They all panic, its just a matter of what we log * and what panic message we issue. * Call processor specific routine to log and panic. * If we return to here then continue (this will happen * when doing a memory dump and we get a cpu read ECC * error on the dump). */ if ((*(cpup->machcheck))(ep, code, sr, cause, &signo) < 0) panic("no trap error routine configured"); break; } CURRENT_CPUDATA->cpu_trap++; if (signo) { XPRINTF(XPR_TRAP, "trap sending signal %N", signo, sig_values, 0, 0); psignal(p, signo); if (u.u_pcb.pcb_bd_ra) { ep[EF_EPC] = u.u_pcb.pcb_bd_epc; ep[EF_CAUSE] = u.u_pcb.pcb_bd_cause; u.u_pcb.pcb_bd_ra = 0; } } if (p->p_cursig || ISSIG(p,0)) psig(); p->p_pri = p->p_usrpri; if (CURRENT_CPUDATA->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. */ pcpu = CURRENT_CPUDATA; pcpu->cpu_proc->p_hlock = pcpu->cpu_hlock; pcpu->cpu_hlock=0; (void) splclock(); smp_lock(&lk_rq,LK_RETRY); setrq(p); u.u_ru.ru_nivcsw++; swtch(); pcpu = CURRENT_CPUDATA; pcpu->cpu_hlock = pcpu->cpu_proc->p_hlock; pcpu->cpu_proc->p_hlock = 0; } /* * 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 && USERMODE(sr)) 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); }done: CURRENT_CPUDATA->cpu_nofault = nofault_save;}static char *p_on = "\033[5i";static char *p_off = "\033[4i";turnon_printer(){ cprintf("%s",p_on);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -