📄 trap.c
字号:
#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.h"#include "ureg.h"#include "../port/error.h"void noted(Ureg*, ulong);static void debugbpt(Ureg*, void*);static void fault386(Ureg*, void*);static Lock vctllock;static Vctl *vctl[256];voidintrenable(int irq, void (*f)(Ureg*, void*), void* a, int tbdf, char *name){ int vno; Vctl *v, *p; v = xalloc(sizeof(Vctl)); v->isintr = 1; v->irq = irq; v->tbdf = tbdf; v->f = f; v->a = a; strncpy(v->name, name, NAMELEN-1); v->name[NAMELEN-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); if(p=vctl[vno]){ print("intrenable: irq %d is already used by", irq); for(; p; p=p->next) print(" %s", p->name); print("\n"); } 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);}intirqallocread(char *buf, long n, vlong offset){ int vno; Vctl *v; long oldn; char str[11+1+NAMELEN+1], *p; int m; if(n < 0 || offset < 0) error(Ebadarg); oldn = n; 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, NAMELEN, 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, NAMELEN); v->name[NAMELEN-1] = 0; lock(&vctllock); if(vctl[vno]) v->next = vctl[vno]->next; vctl[vno] = v; unlock(&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);}voidtrapinit(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; } /* * Special traps. * Syscall() is called directly without going through trap(). */ trapenable(VectorBPT, debugbpt, 0, "debugpt"); trapenable(VectorPF, fault386, 0, "fault386"); nmienable();}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)",};/* * 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 i, vno, user; char buf[ERRLEN]; Vctl *ctl, *v; Mach *mach; m->intrts = fastticks(nil); user = 0; if((ureg->cs & 0xFFFF) == UESEL){ user = 1; up->dbgreg = ureg; } 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); /* * preemptive scheduling. to limit stack depth, * make sure process has a chance to return from * the current interrupt before being preempted a * second time. */ if(ctl->isintr && ctl->irq != IrqTIMER && ctl->irq != IrqCLOCK) if(up && up->state == Running) if(anyhigher()) if(up->preempted == 0) if(!active.exiting){ up->preempted = 1; sched(); splhi(); up->preempted = 0; return; } } 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. */ print("cpu%d: spurious interrupt %d, last %d", m->machno, vno, m->lastintr); 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++; 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(vno < nelem(excname)) panic("%s", excname[vno]); panic("unknown trap/intr: %d\n", vno); } if(user && (up->procctl || up->nnote)){ splhi(); notify(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){ extern ulong etext; 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){ ulong l, v, i; uchar *p; extern ulong etext; if(up == 0) return; print("ktrace /kernel/path %.8lux %.8lux\n", ureg->pc, ureg->sp); i = 0; for(l=(ulong)&l; l<(ulong)(up->kstack+KSTACK); l+=4){ v = *(ulong*)l; if(KTZERO < v && v < (ulong)&etext){ /* * Pick off general CALL (0xE8) and CALL indirect * through AX (0xFFD0). */ p = (uchar*)v; if(*(p-5) == 0xE8 || (*(p-2) == 0xFF && *(p-1) == 0xD0)){ print("%.8lux=%.8lux ", l, v); i++; } } if(i == 4){ i = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -