1103 lines · 22.7 KB · C
RawDownload
#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];uvlong intrtimetot[256];uvlong intrcountx[256]; int (*traplapiceoi)(int); intintrenable(int irq, void (*f)(Ureg*, void*), void* a, int tbdf, char *name){	Vctl *v; 	if(f == nil){		print("intrenable: nil handler for %d, tbdf %#ux for %s\n",			irq, tbdf, name);		return -1;	} 	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);	v->vno = arch->intrenable(v);	if(v->vno == -1){		iunlock(&vctllock);		print("intrenable: couldn't enable irq %d, tbdf %#ux for %s\n",			irq, tbdf, v->name);		xfree(v);		return -1;	}	if(vctl[v->vno]){		if(vctl[v->vno]->isr != v->isr || vctl[v->vno]->eoi != v->eoi)			panic("intrenable: handler: %s %s %#p %#p %#p %#p",				vctl[v->vno]->name, v->name,				vctl[v->vno]->isr, v->isr, vctl[v->vno]->eoi, v->eoi);		v->next = vctl[v->vno];	}	vctl[v->vno] = v; 	if(v->mask)		v->mask(v, 0); 	iunlock(&vctllock);	return 0;} intintrdisable(int irq, void (*f)(Ureg *, void *), void *a, int tbdf, char *name){	Vctl **pv, *v;	int vno; 	ilock(&vctllock);	for(vno = 0; vno < 256; vno++)		for(pv = vctl + vno; v = *pv; pv = &v->next)			if(v->irq == irq)			if(v->f == f)			if(v->tbdf == tbdf)			if(v->a == a)			if(strcmp(name, v->name) == 0)				goto found;	print("bad intrdisable: %d %s\n", irq, name);	iunlock(&vctllock);	return -1;found:	*pv = v->next; 	if(v->mask)		v->mask(v, 1);	if(vctl[vno] == nil && arch->intrdisable != nil)		arch->intrdisable(v);	iunlock(&vctllock);	xfree(v);	return 0;} static longirqallocread(Chan*, void *vbuf, long n, vlong offset){	char *buf, *p, str[2*(11+1)+2*(20+1)+(KNAMELEN+1)+(8+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 %20llud %20llud %-*.*s %.*s\n",				vno, v->irq, intrcountx[vno], intrtimetot[vno], 8, 8, v->type, 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", vno);	v = xalloc(sizeof(Vctl));	v->type = "trap";	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",	"SIMD exception",	"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;	intrtimetot[vno] += diff;//	diff /= m->cpumhz*100;		/* quantum = 100µsec *///	if(diff >= Ntimevec)//		diff = Ntimevec-1;//	intrtimes[vno][diff]++;	intrcountx[vno]++;} /* 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];	Proc *uprock;	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]){		uprock = nil;		if(ctl->irq == IrqCLOCK || ctl->irq == IrqTIMER){			clockintr = 1;			m->intr++;		}else if(ctl->isintr){			uprock = up;			up = nil;			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 != nil)				v->f(ureg, v->a);		}		if(ctl->eoi)			ctl->eoi(vno); 		intrtime(m, vno);		if(uprock != nil){			up = uprock;			preempted();		}	}	else if(vno < nelem(excname) && user){		spllo();		snprint(buf, sizeof 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(vno < VectorAPIC)			if(ctl->eoi)				ctl->eoi(i);		} 		/* clear the interrupt */		if(vno >= VectorAPIC){			if(traplapiceoi != nil)				traplapiceoi(0);		}else			i8259isr(vno); 		if(1)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++;		intrtime(m, vno);		if(user)			kexit(ureg);		return;	}	else{		if(vno == VectorNMI){			/*			 * Don't re-enable, it confuses the crash dumps.			nmienable();			 */			iprint("cpu%d: NMI PC %#p\n", m->machno, ureg->pc);			while(m->machno != 0)				;		}		dumpregs(ureg);		if(!user){			ureg->sp = (ulong)&ureg->sp;			_dumpstack(ureg);		}		if(vno < nelem(excname))			panic("%s", excname[vno]);		panic("unknown trap/intr: %d", 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)		iprint("cpu%d: registers for %s %lud\n",			m->machno, up->text, up->pid);	else		iprint("cpu%d: registers for kernel\n", m->machno);	iprint("FLAGS=%luX TRAP=%luX ECODE=%luX PC=%luX",		ureg->flags, ureg->trap, ureg->ecode, ureg->pc);	iprint(" SS=%4.4luX USP=%luX\n", ureg->ss & 0xFFFF, ureg->usp);	iprint("  AX %8.8luX  BX %8.8luX  CX %8.8luX  DX %8.8luX\n",		ureg->ax, ureg->bx, ureg->cx, ureg->dx);	iprint("  SI %8.8luX  DI %8.8luX  BP %8.8luX\n",		ureg->si, ureg->di, ureg->bp);	iprint("  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.

Lines 1–500 of 1103.