void noted(Ureg*, ulong);
+static void debugexc(Ureg*, void*);
static void debugbpt(Ureg*, void*);
static void fault386(Ureg*, void*);
static void doublefault(Ureg*, void*);
irq, tbdf, name);
return;
}
+ if(tbdf != BUSUNKNOWN && (irq == 0xff || irq == 0)){
+ print("intrenable: got unassigned irq %d, tbdf 0x%uX for %s\n",
+ irq, tbdf, name);
+ irq = -1;
+ }
+
+ /*
+ * IRQ2 doesn't really exist, it's used to gang the interrupt
+ * controllers together. A device set to IRQ2 will appear on
+ * the second interrupt controller as IRQ9.
+ */
+ if(irq == 2)
+ irq = 9;
- v = xalloc(sizeof(Vctl));
+ if((v = xalloc(sizeof(Vctl))) == nil)
+ panic("intrenable: out of memory");
v->isintr = 1;
v->irq = irq;
v->tbdf = tbdf;
iunlock(&vctllock);
}
-int
+void
intrdisable(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);
+ if(irq == 2)
+ irq = 9;
+ if(arch->intrvecno == nil || (tbdf != BUSUNKNOWN && (irq == 0xff || irq == 0))){
+ /*
+ * on APIC machine, irq is pretty meaningless
+ * and disabling a the vector is not implemented.
+ * however, we still want to remove the matching
+ * Vctl entry to prevent calling Vctl.f() with a
+ * stale Vctl.a pointer.
+ */
+ irq = -1;
+ vno = VectorPIC;
+ } else {
+ 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);
+ do {
+ for(pv = &vctl[vno]; (v = *pv) != nil; pv = &v->next){
+ if(v->isintr && (v->irq == irq || irq == -1)
+ && v->tbdf == tbdf && v->f == f && v->a == a
+ && strcmp(v->name, name) == 0)
+ break;
+ }
+ if(v != nil){
+ *pv = v->next;
+ xfree(v);
+
+ if(irq != -1 && vctl[vno] == nil && arch->intrdisable != nil)
+ arch->intrdisable(irq);
+ break;
+ }
+ } while(irq == -1 && ++vno <= MaxVectorAPIC);
iunlock(&vctllock);
- xfree(v);
- return 0;
}
static long
-irqallocread(Chan*, void *vbuf, long n, vlong offset)
+irqallocread(Chan*, void *a, long n, vlong offset)
{
- char *buf, *p, str[2*(11+1)+KNAMELEN+1+1];
- int m, vno;
- long oldn;
+ char buf[2*(11+1)+KNAMELEN+1+1];
+ int vno, m;
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;
- }
+ m = snprint(buf, sizeof(buf), "%11d %11d %.*s\n", vno, v->irq, KNAMELEN, v->name);
+ offset -= m;
+ if(offset >= 0)
+ continue;
+ if(n > -offset)
+ n = -offset;
+ offset += m;
+ memmove(a, buf+offset, n);
+ return n;
}
}
- return oldn - n;
+ return 0;
}
void
if(vno < 0 || vno >= VectorPIC)
panic("trapenable: vno %d", vno);
- v = xalloc(sizeof(Vctl));
+ if((v = xalloc(sizeof(Vctl))) == nil)
+ panic("trapenable: out of memory");
v->tbdf = BUSUNKNOWN;
v->f = f;
v->a = a;
- strncpy(v->name, name, KNAMELEN);
+ strncpy(v->name, name, KNAMELEN-1);
v->name[KNAMELEN-1] = 0;
ilock(&vctllock);
outb(0x70, 0);
x = inb(0x61) & 0x07; /* Enable NMI */
- outb(0x61, 0x08|x);
+ outb(0x61, 0x0C|x);
outb(0x61, x);
}
* Special traps.
* Syscall() is called directly without going through trap().
*/
+ trapenable(VectorDE, debugexc, 0, "debugexc");
trapenable(VectorBPT, debugbpt, 0, "debugpt");
trapenable(VectorPF, fault386, 0, "fault386");
trapenable(Vector2F, doublefault, 0, "doublefault");
"coprocessor error",
"alignment check",
"machine check",
- "19 (reserved)",
+ "simd error",
"20 (reserved)",
"21 (reserved)",
"22 (reserved)",
tos = (Tos*)(USTKTOP-sizeof(Tos));
cycles(&t);
tos->kcycles += t - up->kentry;
- tos->pcycles = up->pcycles;
+ tos->pcycles = t + up->pcycles;
tos->pid = up->pid;
}
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)))
+ for(i = 0; i < MAXMACH; i++){
+ if(active.machs[i] == 0)
continue;
mach = MACHP(i);
if(m->machno == mach->machno)
* Don't re-enable, it confuses the crash dumps.
nmienable();
*/
- iprint("cpu%d: PC %#8.8lux\n", m->machno, ureg->pc);
+ iprint("cpu%d: nmi PC %#8.8lux, status %ux\n",
+ m->machno, ureg->pc, inb(0x61));
while(m->machno != 0)
;
}
- if(vno == VectorGPF || vno == VectorSNP){
- ulong *sp;
- uchar *pc;
+ if(!user){
+ void (*pc)(void);
+ ulong *sp;
+
+ extern void _forkretpopgs(void);
+ extern void _forkretpopfs(void);
+ extern void _forkretpopes(void);
+ extern void _forkretpopds(void);
+ extern void _forkretiret(void);
+ extern void _rdmsrinst(void);
+ extern void _wrmsrinst(void);
+ extern void _peekinst(void);
- /* l.s */
extern void load_fs(ulong);
extern void load_gs(ulong);
- /*
- * CS, SS, DS and ES are initialized by strayintr
- * in l.s. initialize the others too so we dont trap
- * again when restoring the old context.
- */
load_fs(NULLSEL);
load_gs(NULLSEL);
- pc = (uchar*)ureg->pc;
- sp = (ulong*)&ureg->sp;
-
- /*
- * we test for the instructions used by forkret()
- * to load the segments. this needs to be changed
- * if forkret changes!
- */
-
- /* POP */
- if((pc[0] == 0x0f && (pc[1] == 0xa9 /*GS*/ ||
- pc[1] == 0xa1 /*FS*/)) || (pc[0] == 0x07) /*ES*/ ||
- (pc[0] == 0x1f) /*DS*/){
- sp[0] = NULLSEL;
- return;
- }
-
- /* IRET */
- if(pc[0] == 0xcf){
- sp[1] = UESEL; /*CS*/
- sp[4] = UDSEL; /*SS*/
- return;
+ sp = (ulong*)&ureg->sp; /* kernel stack */
+ pc = (void*)ureg->pc;
+
+ if(pc == _forkretpopgs || pc == _forkretpopfs ||
+ pc == _forkretpopes || pc == _forkretpopds){
+ if(vno == VectorGPF || vno == VectorSNP){
+ sp[0] = NULLSEL;
+ return;
+ }
+ } else if(pc == _forkretiret){
+ if(vno == VectorGPF || vno == VectorSNP){
+ sp[1] = UESEL; /* CS */
+ sp[4] = UDSEL; /* SS */
+ return;
+ }
+ } else if(pc == _rdmsrinst || pc == _wrmsrinst){
+ if(vno == VectorGPF){
+ ureg->bp = -1;
+ ureg->pc += 2;
+ return;
+ }
+ } else if(pc == _peekinst){
+ if(vno == VectorGPF){
+ ureg->pc += 2;
+ return;
+ }
}
}
void
dumpregs(Ureg* ureg)
{
- vlong mca, mct;
-
dumpregs2(ureg);
/*
*/
iprint(" CR0 %8.8lux CR2 %8.8lux CR3 %8.8lux",
getcr0(), getcr2(), getcr3());
- if(m->cpuiddx & 0x9A){
- iprint(" CR4 %8.8lux", getcr4());
- if((m->cpuiddx & 0xA0) == 0xA0){
- rdmsr(0x00, &mca);
- rdmsr(0x01, &mct);
- iprint("\n MCA %8.8llux MCT %8.8llux", mca, mct);
- }
+ if(m->cpuiddx & (Mce|Tsc|Pse|Vmex)){
+ iprint(" CR4 %8.8lux\n", getcr4());
+ if(ureg->trap == 18)
+ dumpmcregs();
}
iprint("\n ur %#p up %#p\n", ureg, up);
}
callwithureg(_dumpstack);
}
+static void
+debugexc(Ureg *ureg, void *)
+{
+ u32int dr6, m;
+ char buf[ERRMAX];
+ char *p, *e;
+ int i;
+
+ dr6 = getdr6();
+ if(up == nil)
+ panic("kernel debug exception dr6=%#.8ux", dr6);
+ putdr6(up->dr[6]);
+ if(userureg(ureg))
+ qlock(&up->debug);
+ else if(!canqlock(&up->debug))
+ return;
+ m = up->dr[7];
+ m = (m >> 4 | m >> 3) & 8 | (m >> 3 | m >> 2) & 4 | (m >> 2 | m >> 1) & 2 | (m >> 1 | m) & 1;
+ m &= dr6;
+ if(m == 0){
+ sprint(buf, "sys: debug exception dr6=%#.8ux", dr6);
+ postnote(up, 0, buf, NDebug);
+ }else{
+ p = buf;
+ e = buf + sizeof(buf);
+ p = seprint(p, e, "sys: watchpoint ");
+ for(i = 0; i < 4; i++)
+ if((m & 1<<i) != 0)
+ p = seprint(p, e, "%d%s", i, (m >> i + 1 != 0) ? "," : "");
+ postnote(up, 0, buf, NDebug);
+ }
+ qunlock(&up->debug);
+}
+
static void
debugbpt(Ureg* ureg, void*)
{
if(!user){
if(vmapsync(addr))
return;
+ {
+ extern void _peekinst(void);
+ if((void(*)(void))ureg->pc == _peekinst){
+ ureg->pc += 2;
+ return;
+ }
+ }
if(addr >= USTKTOP)
panic("kernel fault: bad address pc=0x%.8lux addr=0x%.8lux", ureg->pc, addr);
if(up == nil)
insyscall = up->insyscall;
up->insyscall = 1;
- n = fault(addr, read);
+ n = fault(addr, ureg->pc, read);
if(n < 0){
if(!user){
dumpregs(ureg);
scallnr = ureg->ax;
up->scallnr = scallnr;
- if(up->procctl == Proc_tracesyscall){
- /*
- * Redundant validaddr. Do we care?
- * Tracing syscalls is not exactly a fast path...
- * Beware, validaddr currently does a pexit rather
- * than an error if there's a problem; that might
- * change in the future.
- */
- if(sp < (USTKTOP-BY2PG) || sp > (USTKTOP-sizeof(Sargs)-BY2WD))
- validaddr(sp, sizeof(Sargs)+BY2WD, 0);
-
- syscallfmt(scallnr, ureg->pc, (va_list)(sp+BY2WD));
- up->procctl = Proc_stopme;
- procctl(up);
- if(up->syscalltrace)
- free(up->syscalltrace);
- up->syscalltrace = nil;
- startns = todget(nil);
- }
-
- if(scallnr == RFORK && up->fpstate == FPactive){
- fpsave(&up->fpsave);
- up->fpstate = FPinactive;
- }
spllo();
up->nerrlab = 0;
ret = -1;
if(!waserror()){
+ if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)-BY2WD))
+ validaddr(sp, sizeof(Sargs)+BY2WD, 0);
+
+ up->s = *((Sargs*)(sp+BY2WD));
+
+ if(up->procctl == Proc_tracesyscall){
+ syscallfmt(scallnr, ureg->pc, (va_list)up->s.args);
+ s = splhi();
+ up->procctl = Proc_stopme;
+ procctl();
+ splx(s);
+ startns = todget(nil);
+ }
+
if(scallnr >= nsyscall || systab[scallnr] == 0){
pprint("bad sys call number %lud pc %lux\n",
scallnr, ureg->pc);
postnote(up, 1, "sys: bad sys call", NDebug);
error(Ebadarg);
}
-
- if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)-BY2WD))
- validaddr(sp, sizeof(Sargs)+BY2WD, 0);
-
- up->s = *((Sargs*)(sp+BY2WD));
up->psstate = sysctab[scallnr];
-
- ret = systab[scallnr](up->s.args);
+ ret = systab[scallnr]((va_list)up->s.args);
poperror();
}else{
/* failure: save the error buffer for errstr */
if(up->procctl == Proc_tracesyscall){
stopns = todget(nil);
- up->procctl = Proc_stopme;
- sysretfmt(scallnr, (va_list)(sp+BY2WD), ret, startns, stopns);
+ sysretfmt(scallnr, (va_list)up->s.args, ret, startns, stopns);
s = splhi();
- procctl(up);
+ up->procctl = Proc_stopme;
+ procctl();
splx(s);
- if(up->syscalltrace)
- free(up->syscalltrace);
- up->syscalltrace = nil;
}
up->insyscall = 0;
up->psstate = 0;
if(scallnr == NOTED)
- noted(ureg, *(ulong*)(sp+BY2WD));
+ noted(ureg, *((ulong*)up->s.args));
if(scallnr!=RFORK && (up->procctl || up->nnote)){
splhi();
Note *n;
if(up->procctl)
- procctl(up);
+ procctl();
if(up->nnote == 0)
return 0;
if(up->fpstate == FPactive){
- fpsave(&up->fpsave);
+ fpsave(up->fpsave);
up->fpstate = FPinactive;
}
up->fpstate |= FPillegal;
}
if(n->flag!=NUser && (up->notified || up->notify==0)){
+ qunlock(&up->debug);
if(n->flag == NDebug)
pprint("suicide: %s\n", n->msg);
- qunlock(&up->debug);
pexit(n->msg, n->flag!=NDebug);
}
if(0) print("%s %lud: notify %.8lux %.8lux %.8lux %s\n",
up->text, up->pid, ureg->pc, ureg->usp, sp, n->msg);
- if(!okaddr((ulong)up->notify, 1, 0)
+ if(!okaddr((uintptr)up->notify, 1, 0)
|| !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)){
qunlock(&up->debug);
pprint("suicide: bad address in notify\n");
/* sanity clause */
oureg = (ulong)nureg;
- if(!okaddr((ulong)oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
+ if(!okaddr(oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
qunlock(&up->debug);
pprint("bad ureg in noted or call to noted when not notified\n");
pexit("Suicide", 0);
break;
default:
- pprint("unknown noted arg 0x%lux\n", arg0);
up->lastnote.flag = NDebug;
/* fall through */
case NDFLT:
- if(up->lastnote.flag == NDebug){
- qunlock(&up->debug);
+ qunlock(&up->debug);
+ if(up->lastnote.flag == NDebug)
pprint("suicide: %s\n", up->lastnote.msg);
- } else
- qunlock(&up->debug);
pexit(up->lastnote.msg, up->lastnote.flag!=NDebug);
}
}
-long
-execregs(ulong entry, ulong ssize, ulong nargs)
+uintptr
+execregs(uintptr entry, ulong ssize, ulong nargs)
{
ulong *sp;
Ureg *ureg;
- up->fpstate = FPinit;
- fpoff();
-
sp = (ulong*)(USTKTOP - ssize);
*--sp = nargs;
/*
* return the userpc the last exception happened at
*/
-ulong
+uintptr
userpc(void)
{
Ureg *ureg;