⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 trap.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
#include	"u.h"#include	"tos.h"#include	"../port/lib.h"#include	"mem.h"#include	"dat.h"#include	"fns.h"#include	"io.h"#include	"ureg.h"#include	"../port/error.h"#include	<trace.h>static int trapinited;void	noted(Ureg*, ulong);static void debugbpt(Ureg*, void*);static void fault386(Ureg*, void*);static void doublefault(Ureg*, void*);static void unexpected(Ureg*, void*);static void _dumpstack(Ureg*);static Lock vctllock;static Vctl *vctl[256];enum{	Ntimevec = 20		/* number of time buckets for each intr */};ulong intrtimes[256][Ntimevec];voidintrenable(int irq, void (*f)(Ureg*, void*), void* a, int tbdf, char *name){	int vno;	Vctl *v;	if(f == nil){		print("intrenable: nil handler for %d, tbdf 0x%uX for %s\n",			irq, tbdf, name);		return;	}	v = xalloc(sizeof(Vctl));	v->isintr = 1;	v->irq = irq;	v->tbdf = tbdf;	v->f = f;	v->a = a;	strncpy(v->name, name, KNAMELEN-1);	v->name[KNAMELEN-1] = 0;	ilock(&vctllock);	vno = arch->intrenable(v);	if(vno == -1){		iunlock(&vctllock);		print("intrenable: couldn't enable irq %d, tbdf 0x%uX for %s\n",			irq, tbdf, v->name);		xfree(v);		return;	}	if(vctl[vno]){		if(vctl[vno]->isr != v->isr || vctl[vno]->eoi != v->eoi)			panic("intrenable: handler: %s %s %luX %luX %luX %luX\n",				vctl[vno]->name, v->name,				vctl[vno]->isr, v->isr, vctl[vno]->eoi, v->eoi);		v->next = vctl[vno];	}	vctl[vno] = v;	iunlock(&vctllock);}intintrdisable(int irq, void (*f)(Ureg *, void *), void *a, int tbdf, char *name){	Vctl **pv, *v;	int vno;	/*	 * For now, none of this will work with the APIC code,	 * there is no mapping between irq and vector as the IRQ	 * is pretty meaningless.	 */	if(arch->intrvecno == nil)		return -1;	vno = arch->intrvecno(irq);	ilock(&vctllock);	pv = &vctl[vno];	while (*pv && 		  ((*pv)->irq != irq || (*pv)->tbdf != tbdf || (*pv)->f != f || (*pv)->a != a ||		   strcmp((*pv)->name, name)))		pv = &((*pv)->next);	assert(*pv);	v = *pv;	*pv = (*pv)->next;	/* Link out the entry */		if(vctl[vno] == nil && arch->intrdisable != nil)		arch->intrdisable(irq);	iunlock(&vctllock);	xfree(v);	return 0;}static longirqallocread(Chan*, void *vbuf, long n, vlong offset){	char *buf, *p, str[2*(11+1)+KNAMELEN+1+1];	int m, vno;	long oldn;	Vctl *v;	if(n < 0 || offset < 0)		error(Ebadarg);	oldn = n;	buf = vbuf;	for(vno=0; vno<nelem(vctl); vno++){		for(v=vctl[vno]; v; v=v->next){			m = snprint(str, sizeof str, "%11d %11d %.*s\n", vno, v->irq, KNAMELEN, v->name);			if(m <= offset)	/* if do not want this, skip entry */				offset -= m;			else{				/* skip offset bytes */				m -= offset;				p = str+offset;				offset = 0;				/* write at most max(n,m) bytes */				if(m > n)					m = n;				memmove(buf, p, m);				n -= m;				buf += m;				if(n == 0)					return oldn;			}			}	}	return oldn - n;}voidtrapenable(int vno, void (*f)(Ureg*, void*), void* a, char *name){	Vctl *v;	if(vno < 0 || vno >= VectorPIC)		panic("trapenable: vno %d\n", vno);	v = xalloc(sizeof(Vctl));	v->tbdf = BUSUNKNOWN;	v->f = f;	v->a = a;	strncpy(v->name, name, KNAMELEN);	v->name[KNAMELEN-1] = 0;	ilock(&vctllock);	if(vctl[vno])		v->next = vctl[vno]->next;	vctl[vno] = v;	iunlock(&vctllock);}static voidnmienable(void){	int x;	/*	 * Hack: should be locked with NVRAM access.	 */	outb(0x70, 0x80);		/* NMI latch clear */	outb(0x70, 0);	x = inb(0x61) & 0x07;		/* Enable NMI */	outb(0x61, 0x08|x);	outb(0x61, x);}/* * Minimal trap setup.  Just enough so that we can panic * on traps (bugs) during kernel initialization.   * Called very early - malloc is not yet available. */voidtrapinit0(void){	int d1, v;	ulong vaddr;	Segdesc *idt;	idt = (Segdesc*)IDTADDR;	vaddr = (ulong)vectortable;	for(v = 0; v < 256; v++){		d1 = (vaddr & 0xFFFF0000)|SEGP;		switch(v){		case VectorBPT:			d1 |= SEGPL(3)|SEGIG;			break;		case VectorSYSCALL:			d1 |= SEGPL(3)|SEGIG;			break;		default:			d1 |= SEGPL(0)|SEGIG;			break;		}		idt[v].d0 = (vaddr & 0xFFFF)|(KESEL<<16);		idt[v].d1 = d1;		vaddr += 6;	}}voidtrapinit(void){	/*	 * Special traps.	 * Syscall() is called directly without going through trap().	 */	trapenable(VectorBPT, debugbpt, 0, "debugpt");	trapenable(VectorPF, fault386, 0, "fault386");	trapenable(Vector2F, doublefault, 0, "doublefault");	trapenable(Vector15, unexpected, 0, "unexpected");	nmienable();	addarchfile("irqalloc", 0444, irqallocread, nil);	trapinited = 1;}static char* excname[32] = {	"divide error",	"debug exception",	"nonmaskable interrupt",	"breakpoint",	"overflow",	"bounds check",	"invalid opcode",	"coprocessor not available",	"double fault",	"coprocessor segment overrun",	"invalid TSS",	"segment not present",	"stack exception",	"general protection violation",	"page fault",	"15 (reserved)",	"coprocessor error",	"alignment check",	"machine check",	"19 (reserved)",	"20 (reserved)",	"21 (reserved)",	"22 (reserved)",	"23 (reserved)",	"24 (reserved)",	"25 (reserved)",	"26 (reserved)",	"27 (reserved)",	"28 (reserved)",	"29 (reserved)",	"30 (reserved)",	"31 (reserved)",};/* *  keep histogram of interrupt service times */voidintrtime(Mach*, int vno){	ulong diff;	ulong x;	x = perfticks();	diff = x - m->perf.intrts;	m->perf.intrts = x;	m->perf.inintr += diff;	if(up == nil && m->perf.inidle > diff)		m->perf.inidle -= diff;	diff /= m->cpumhz*100;	// quantum = 100µsec	if(diff >= Ntimevec)		diff = Ntimevec-1;	intrtimes[vno][diff]++;}/* go to user space */voidkexit(Ureg*){	uvlong t;	Tos *tos;	/* precise time accounting, kernel exit */	tos = (Tos*)(USTKTOP-sizeof(Tos));	cycles(&t);	tos->kcycles += t - up->kentry;	tos->pcycles = up->pcycles;	tos->pid = up->pid;}/* *  All traps come here.  It is slower to have all traps call trap() *  rather than directly vectoring the handler.  However, this avoids a *  lot of code duplication and possible bugs.  The only exception is *  VectorSYSCALL. *  Trap is called with interrupts disabled via interrupt-gates. */voidtrap(Ureg* ureg){	int clockintr, i, vno, user;	char buf[ERRMAX];	Vctl *ctl, *v;	Mach *mach;	if(!trapinited){		/* fault386 can give a better error message */		if(ureg->trap == VectorPF)			fault386(ureg, nil);		panic("trap %lud: not ready", ureg->trap);	}	m->perf.intrts = perfticks();	user = (ureg->cs & 0xFFFF) == UESEL;	if(user){		up->dbgreg = ureg;		cycles(&up->kentry);	}	clockintr = 0;	vno = ureg->trap;	if(ctl = vctl[vno]){		if(ctl->isintr){			m->intr++;			if(vno >= VectorPIC && vno != VectorSYSCALL)				m->lastintr = ctl->irq;		}		if(ctl->isr)			ctl->isr(vno);		for(v = ctl; v != nil; v = v->next){			if(v->f)				v->f(ureg, v->a);		}		if(ctl->eoi)			ctl->eoi(vno);		if(ctl->isintr){			intrtime(m, vno);			if(ctl->irq == IrqCLOCK || ctl->irq == IrqTIMER)				clockintr = 1;			if(up && !clockintr)				preempted();		}	}	else if(vno <= nelem(excname) && user){		spllo();		sprint(buf, "sys: trap: %s", excname[vno]);		postnote(up, 1, buf, NDebug);	}	else if(vno >= VectorPIC && vno != VectorSYSCALL){		/*		 * An unknown interrupt.		 * Check for a default IRQ7. This can happen when		 * the IRQ input goes away before the acknowledge.		 * In this case, a 'default IRQ7' is generated, but		 * the corresponding bit in the ISR isn't set.		 * In fact, just ignore all such interrupts.		 */		/* call all interrupt routines, just in case */		for(i = VectorPIC; i <= MaxIrqLAPIC; i++){			ctl = vctl[i];			if(ctl == nil)				continue;			if(!ctl->isintr)				continue;			for(v = ctl; v != nil; v = v->next){				if(v->f)					v->f(ureg, v->a);			}			/* should we do this? */			if(ctl->eoi)				ctl->eoi(i);		}		/* clear the interrupt */		i8259isr(vno);		if(0)print("cpu%d: spurious interrupt %d, last %d\n",			m->machno, vno, m->lastintr);		if(0)if(conf.nmach > 1){			for(i = 0; i < 32; i++){				if(!(active.machs & (1<<i)))					continue;				mach = MACHP(i);				if(m->machno == mach->machno)					continue;				print(" cpu%d: last %d",					mach->machno, mach->lastintr);			}			print("\n");		}		m->spuriousintr++;		if(user)			kexit(ureg);		return;	}	else{		if(vno == VectorNMI){			nmienable();			if(m->machno != 0){				print("cpu%d: PC %8.8luX\n",					m->machno, ureg->pc);				for(;;);			}		}		dumpregs(ureg);		if(!user){			ureg->sp = (ulong)&ureg->sp;			_dumpstack(ureg);		}		if(vno < nelem(excname))			panic("%s", excname[vno]);		panic("unknown trap/intr: %d\n", vno);	}	splhi();	/* delaysched set because we held a lock or because our quantum ended */	if(up && up->delaysched && clockintr){		sched();		splhi();	}	if(user){		if(up->procctl || up->nnote)			notify(ureg);		kexit(ureg);	}}/* *  dump registers */voiddumpregs2(Ureg* ureg){	if(up)		print("cpu%d: registers for %s %lud\n",			m->machno, up->text, up->pid);	else		print("cpu%d: registers for kernel\n", m->machno);	print("FLAGS=%luX TRAP=%luX ECODE=%luX PC=%luX",		ureg->flags, ureg->trap, ureg->ecode, ureg->pc);	print(" SS=%4.4luX USP=%luX\n", ureg->ss & 0xFFFF, ureg->usp);	print("  AX %8.8luX  BX %8.8luX  CX %8.8luX  DX %8.8luX\n",		ureg->ax, ureg->bx, ureg->cx, ureg->dx);	print("  SI %8.8luX  DI %8.8luX  BP %8.8luX\n",		ureg->si, ureg->di, ureg->bp);	print("  CS %4.4luX  DS %4.4luX  ES %4.4luX  FS %4.4luX  GS %4.4luX\n",		ureg->cs & 0xFFFF, ureg->ds & 0xFFFF, ureg->es & 0xFFFF,		ureg->fs & 0xFFFF, ureg->gs & 0xFFFF);}voiddumpregs(Ureg* ureg){	vlong mca, mct;	dumpregs2(ureg);	/*	 * Processor control registers.	 * If machine check exception, time stamp counter, page size extensions	 * or enhanced virtual 8086 mode extensions are supported, there is a	 * CR4. If there is a CR4 and machine check extensions, read the machine	 * check address and machine check type registers if RDMSR supported.	 */	print("  CR0 %8.8lux CR2 %8.8lux CR3 %8.8lux",		getcr0(), getcr2(), getcr3());	if(m->cpuiddx & 0x9A){		print(" CR4 %8.8lux", getcr4());		if((m->cpuiddx & 0xA0) == 0xA0){			rdmsr(0x00, &mca);			rdmsr(0x01, &mct);			print("\n  MCA %8.8llux MCT %8.8llux", mca, mct);		}	}	print("\n  ur %lux up %lux\n", ureg, up);}/* * Fill in enough of Ureg to get a stack trace, and call a function. * Used by debugging interface rdb. */voidcallwithureg(void (*fn)(Ureg*)){	Ureg ureg;	ureg.pc = getcallerpc(&fn);	ureg.sp = (ulong)&fn;	fn(&ureg);}static void_dumpstack(Ureg *ureg)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -