13e12c5d1SDavid du Colombier #include "u.h" 2e288d156SDavid du Colombier #include "tos.h" 33e12c5d1SDavid du Colombier #include "../port/lib.h" 43e12c5d1SDavid du Colombier #include "mem.h" 53e12c5d1SDavid du Colombier #include "dat.h" 63e12c5d1SDavid du Colombier #include "fns.h" 73e12c5d1SDavid du Colombier #include "io.h" 83e12c5d1SDavid du Colombier #include "ureg.h" 93e12c5d1SDavid du Colombier #include "../port/error.h" 10179dd269SDavid du Colombier #include <trace.h> 113e12c5d1SDavid du Colombier 124de34a7eSDavid du Colombier static int trapinited; 134de34a7eSDavid du Colombier 143e12c5d1SDavid du Colombier void noted(Ureg*, ulong); 153e12c5d1SDavid du Colombier 167dd7cddfSDavid du Colombier static void debugbpt(Ureg*, void*); 177dd7cddfSDavid du Colombier static void fault386(Ureg*, void*); 18e288d156SDavid du Colombier static void doublefault(Ureg*, void*); 19fe853e23SDavid du Colombier static void unexpected(Ureg*, void*); 20fe853e23SDavid du Colombier static void _dumpstack(Ureg*); 213e12c5d1SDavid du Colombier 227dd7cddfSDavid du Colombier static Lock vctllock; 237dd7cddfSDavid du Colombier static Vctl *vctl[256]; 243ff48bf5SDavid du Colombier 253ff48bf5SDavid du Colombier enum 263ff48bf5SDavid du Colombier { 270701b922SDavid du Colombier Ntimevec = 20 /* number of time buckets for each intr */ 283ff48bf5SDavid du Colombier }; 29e288d156SDavid du Colombier ulong intrtimes[256][Ntimevec]; 303e12c5d1SDavid du Colombier 313e12c5d1SDavid du Colombier void 327dd7cddfSDavid du Colombier intrenable(int irq, void (*f)(Ureg*, void*), void* a, int tbdf, char *name) 333e12c5d1SDavid du Colombier { 347dd7cddfSDavid du Colombier int vno; 3559cc4ca5SDavid du Colombier Vctl *v; 367dd7cddfSDavid du Colombier 379a747e4fSDavid du Colombier if(f == nil){ 389a747e4fSDavid du Colombier print("intrenable: nil handler for %d, tbdf 0x%uX for %s\n", 399a747e4fSDavid du Colombier irq, tbdf, name); 409a747e4fSDavid du Colombier return; 419a747e4fSDavid du Colombier } 429a747e4fSDavid du Colombier 437dd7cddfSDavid du Colombier v = xalloc(sizeof(Vctl)); 447dd7cddfSDavid du Colombier v->isintr = 1; 457dd7cddfSDavid du Colombier v->irq = irq; 467dd7cddfSDavid du Colombier v->tbdf = tbdf; 477dd7cddfSDavid du Colombier v->f = f; 487dd7cddfSDavid du Colombier v->a = a; 499a747e4fSDavid du Colombier strncpy(v->name, name, KNAMELEN-1); 509a747e4fSDavid du Colombier v->name[KNAMELEN-1] = 0; 517dd7cddfSDavid du Colombier 527dd7cddfSDavid du Colombier ilock(&vctllock); 537dd7cddfSDavid du Colombier vno = arch->intrenable(v); 547dd7cddfSDavid du Colombier if(vno == -1){ 557dd7cddfSDavid du Colombier iunlock(&vctllock); 567dd7cddfSDavid du Colombier print("intrenable: couldn't enable irq %d, tbdf 0x%uX for %s\n", 577dd7cddfSDavid du Colombier irq, tbdf, v->name); 587dd7cddfSDavid du Colombier xfree(v); 597dd7cddfSDavid du Colombier return; 607dd7cddfSDavid du Colombier } 617dd7cddfSDavid du Colombier if(vctl[vno]){ 627dd7cddfSDavid du Colombier if(vctl[vno]->isr != v->isr || vctl[vno]->eoi != v->eoi) 637dd7cddfSDavid du Colombier panic("intrenable: handler: %s %s %luX %luX %luX %luX\n", 647dd7cddfSDavid du Colombier vctl[vno]->name, v->name, 657dd7cddfSDavid du Colombier vctl[vno]->isr, v->isr, vctl[vno]->eoi, v->eoi); 667dd7cddfSDavid du Colombier v->next = vctl[vno]; 677dd7cddfSDavid du Colombier } 687dd7cddfSDavid du Colombier vctl[vno] = v; 697dd7cddfSDavid du Colombier iunlock(&vctllock); 707dd7cddfSDavid du Colombier } 717dd7cddfSDavid du Colombier 7207a38badSDavid du Colombier int 739a747e4fSDavid du Colombier intrdisable(int irq, void (*f)(Ureg *, void *), void *a, int tbdf, char *name) 749a747e4fSDavid du Colombier { 759a747e4fSDavid du Colombier Vctl **pv, *v; 769a747e4fSDavid du Colombier int vno; 779a747e4fSDavid du Colombier 789a747e4fSDavid du Colombier /* 799a747e4fSDavid du Colombier * For now, none of this will work with the APIC code, 809a747e4fSDavid du Colombier * there is no mapping between irq and vector as the IRQ 819a747e4fSDavid du Colombier * is pretty meaningless. 829a747e4fSDavid du Colombier */ 839a747e4fSDavid du Colombier if(arch->intrvecno == nil) 8407a38badSDavid du Colombier return -1; 859a747e4fSDavid du Colombier vno = arch->intrvecno(irq); 869a747e4fSDavid du Colombier ilock(&vctllock); 879a747e4fSDavid du Colombier pv = &vctl[vno]; 889a747e4fSDavid du Colombier while (*pv && 899a747e4fSDavid du Colombier ((*pv)->irq != irq || (*pv)->tbdf != tbdf || (*pv)->f != f || (*pv)->a != a || 909a747e4fSDavid du Colombier strcmp((*pv)->name, name))) 919a747e4fSDavid du Colombier pv = &((*pv)->next); 929a747e4fSDavid du Colombier assert(*pv); 939a747e4fSDavid du Colombier 949a747e4fSDavid du Colombier v = *pv; 959a747e4fSDavid du Colombier *pv = (*pv)->next; /* Link out the entry */ 969a747e4fSDavid du Colombier 979a747e4fSDavid du Colombier if(vctl[vno] == nil && arch->intrdisable != nil) 989a747e4fSDavid du Colombier arch->intrdisable(irq); 999a747e4fSDavid du Colombier iunlock(&vctllock); 1009a747e4fSDavid du Colombier xfree(v); 10107a38badSDavid du Colombier return 0; 1029a747e4fSDavid du Colombier } 1039a747e4fSDavid du Colombier 10480ee5cbfSDavid du Colombier static long 10580ee5cbfSDavid du Colombier irqallocread(Chan*, void *vbuf, long n, vlong offset) 1067dd7cddfSDavid du Colombier { 1073ff48bf5SDavid du Colombier char *buf, *p, str[2*(11+1)+KNAMELEN+1+1]; 10880ee5cbfSDavid du Colombier int m, vno; 1097dd7cddfSDavid du Colombier long oldn; 11080ee5cbfSDavid du Colombier Vctl *v; 1117dd7cddfSDavid du Colombier 1127dd7cddfSDavid du Colombier if(n < 0 || offset < 0) 1137dd7cddfSDavid du Colombier error(Ebadarg); 1147dd7cddfSDavid du Colombier 1157dd7cddfSDavid du Colombier oldn = n; 11680ee5cbfSDavid du Colombier buf = vbuf; 1177dd7cddfSDavid du Colombier for(vno=0; vno<nelem(vctl); vno++){ 1187dd7cddfSDavid du Colombier for(v=vctl[vno]; v; v=v->next){ 1199a747e4fSDavid du Colombier m = snprint(str, sizeof str, "%11d %11d %.*s\n", vno, v->irq, KNAMELEN, v->name); 1207dd7cddfSDavid du Colombier if(m <= offset) /* if do not want this, skip entry */ 1217dd7cddfSDavid du Colombier offset -= m; 1227dd7cddfSDavid du Colombier else{ 1237dd7cddfSDavid du Colombier /* skip offset bytes */ 1247dd7cddfSDavid du Colombier m -= offset; 1257dd7cddfSDavid du Colombier p = str+offset; 1267dd7cddfSDavid du Colombier offset = 0; 1277dd7cddfSDavid du Colombier 1287dd7cddfSDavid du Colombier /* write at most max(n,m) bytes */ 1297dd7cddfSDavid du Colombier if(m > n) 1307dd7cddfSDavid du Colombier m = n; 1317dd7cddfSDavid du Colombier memmove(buf, p, m); 1327dd7cddfSDavid du Colombier n -= m; 1337dd7cddfSDavid du Colombier buf += m; 1347dd7cddfSDavid du Colombier 1357dd7cddfSDavid du Colombier if(n == 0) 1367dd7cddfSDavid du Colombier return oldn; 1377dd7cddfSDavid du Colombier } 1387dd7cddfSDavid du Colombier } 1397dd7cddfSDavid du Colombier } 1407dd7cddfSDavid du Colombier return oldn - n; 1413e12c5d1SDavid du Colombier } 1423e12c5d1SDavid du Colombier 1433e12c5d1SDavid du Colombier void 1447dd7cddfSDavid du Colombier trapenable(int vno, void (*f)(Ureg*, void*), void* a, char *name) 1453e12c5d1SDavid du Colombier { 1467dd7cddfSDavid du Colombier Vctl *v; 147219b2ee8SDavid du Colombier 1487dd7cddfSDavid du Colombier if(vno < 0 || vno >= VectorPIC) 1497dd7cddfSDavid du Colombier panic("trapenable: vno %d\n", vno); 1507dd7cddfSDavid du Colombier v = xalloc(sizeof(Vctl)); 1517dd7cddfSDavid du Colombier v->tbdf = BUSUNKNOWN; 1527dd7cddfSDavid du Colombier v->f = f; 1537dd7cddfSDavid du Colombier v->a = a; 1549a747e4fSDavid du Colombier strncpy(v->name, name, KNAMELEN); 1559a747e4fSDavid du Colombier v->name[KNAMELEN-1] = 0; 1567dd7cddfSDavid du Colombier 157061a3f44SDavid du Colombier ilock(&vctllock); 1587dd7cddfSDavid du Colombier if(vctl[vno]) 1597dd7cddfSDavid du Colombier v->next = vctl[vno]->next; 1607dd7cddfSDavid du Colombier vctl[vno] = v; 161061a3f44SDavid du Colombier iunlock(&vctllock); 1627dd7cddfSDavid du Colombier } 1637dd7cddfSDavid du Colombier 1647dd7cddfSDavid du Colombier static void 1657dd7cddfSDavid du Colombier nmienable(void) 1667dd7cddfSDavid du Colombier { 1677dd7cddfSDavid du Colombier int x; 1683e12c5d1SDavid du Colombier 1693e12c5d1SDavid du Colombier /* 1707dd7cddfSDavid du Colombier * Hack: should be locked with NVRAM access. 1713e12c5d1SDavid du Colombier */ 1727dd7cddfSDavid du Colombier outb(0x70, 0x80); /* NMI latch clear */ 1737dd7cddfSDavid du Colombier outb(0x70, 0); 1747dd7cddfSDavid du Colombier 1757dd7cddfSDavid du Colombier x = inb(0x61) & 0x07; /* Enable NMI */ 1767dd7cddfSDavid du Colombier outb(0x61, 0x08|x); 1777dd7cddfSDavid du Colombier outb(0x61, x); 1783e12c5d1SDavid du Colombier } 1793e12c5d1SDavid du Colombier 1804de34a7eSDavid du Colombier /* 1814de34a7eSDavid du Colombier * Minimal trap setup. Just enough so that we can panic 1824de34a7eSDavid du Colombier * on traps (bugs) during kernel initialization. 1834de34a7eSDavid du Colombier * Called very early - malloc is not yet available. 1844de34a7eSDavid du Colombier */ 1853e12c5d1SDavid du Colombier void 1864de34a7eSDavid du Colombier trapinit0(void) 1873e12c5d1SDavid du Colombier { 1887dd7cddfSDavid du Colombier int d1, v; 1897dd7cddfSDavid du Colombier ulong vaddr; 1907dd7cddfSDavid du Colombier Segdesc *idt; 1913e12c5d1SDavid du Colombier 1927dd7cddfSDavid du Colombier idt = (Segdesc*)IDTADDR; 1937dd7cddfSDavid du Colombier vaddr = (ulong)vectortable; 1947dd7cddfSDavid du Colombier for(v = 0; v < 256; v++){ 1957dd7cddfSDavid du Colombier d1 = (vaddr & 0xFFFF0000)|SEGP; 1967dd7cddfSDavid du Colombier switch(v){ 1973e12c5d1SDavid du Colombier 1987dd7cddfSDavid du Colombier case VectorBPT: 1997dd7cddfSDavid du Colombier d1 |= SEGPL(3)|SEGIG; 2007dd7cddfSDavid du Colombier break; 2013e12c5d1SDavid du Colombier 2027dd7cddfSDavid du Colombier case VectorSYSCALL: 2037dd7cddfSDavid du Colombier d1 |= SEGPL(3)|SEGIG; 2047dd7cddfSDavid du Colombier break; 2053e12c5d1SDavid du Colombier 2067dd7cddfSDavid du Colombier default: 2077dd7cddfSDavid du Colombier d1 |= SEGPL(0)|SEGIG; 2087dd7cddfSDavid du Colombier break; 2097dd7cddfSDavid du Colombier } 2107dd7cddfSDavid du Colombier idt[v].d0 = (vaddr & 0xFFFF)|(KESEL<<16); 2117dd7cddfSDavid du Colombier idt[v].d1 = d1; 2127dd7cddfSDavid du Colombier vaddr += 6; 2133e12c5d1SDavid du Colombier } 2144de34a7eSDavid du Colombier } 2153e12c5d1SDavid du Colombier 2164de34a7eSDavid du Colombier void 2174de34a7eSDavid du Colombier trapinit(void) 2184de34a7eSDavid du Colombier { 2197dd7cddfSDavid du Colombier /* 2207dd7cddfSDavid du Colombier * Special traps. 2217dd7cddfSDavid du Colombier * Syscall() is called directly without going through trap(). 2227dd7cddfSDavid du Colombier */ 2237dd7cddfSDavid du Colombier trapenable(VectorBPT, debugbpt, 0, "debugpt"); 2247dd7cddfSDavid du Colombier trapenable(VectorPF, fault386, 0, "fault386"); 225e288d156SDavid du Colombier trapenable(Vector2F, doublefault, 0, "doublefault"); 226fe853e23SDavid du Colombier trapenable(Vector15, unexpected, 0, "unexpected"); 2277dd7cddfSDavid du Colombier nmienable(); 22880ee5cbfSDavid du Colombier 22980ee5cbfSDavid du Colombier addarchfile("irqalloc", 0444, irqallocread, nil); 2304de34a7eSDavid du Colombier trapinited = 1; 2317dd7cddfSDavid du Colombier } 2327dd7cddfSDavid du Colombier 2337dd7cddfSDavid du Colombier static char* excname[32] = { 2347dd7cddfSDavid du Colombier "divide error", 2357dd7cddfSDavid du Colombier "debug exception", 2367dd7cddfSDavid du Colombier "nonmaskable interrupt", 2377dd7cddfSDavid du Colombier "breakpoint", 2387dd7cddfSDavid du Colombier "overflow", 2397dd7cddfSDavid du Colombier "bounds check", 2407dd7cddfSDavid du Colombier "invalid opcode", 2417dd7cddfSDavid du Colombier "coprocessor not available", 2427dd7cddfSDavid du Colombier "double fault", 2437dd7cddfSDavid du Colombier "coprocessor segment overrun", 2447dd7cddfSDavid du Colombier "invalid TSS", 2457dd7cddfSDavid du Colombier "segment not present", 2467dd7cddfSDavid du Colombier "stack exception", 2477dd7cddfSDavid du Colombier "general protection violation", 2487dd7cddfSDavid du Colombier "page fault", 2497dd7cddfSDavid du Colombier "15 (reserved)", 2507dd7cddfSDavid du Colombier "coprocessor error", 2517dd7cddfSDavid du Colombier "alignment check", 2527dd7cddfSDavid du Colombier "machine check", 2537dd7cddfSDavid du Colombier "19 (reserved)", 2547dd7cddfSDavid du Colombier "20 (reserved)", 2557dd7cddfSDavid du Colombier "21 (reserved)", 2567dd7cddfSDavid du Colombier "22 (reserved)", 2577dd7cddfSDavid du Colombier "23 (reserved)", 2587dd7cddfSDavid du Colombier "24 (reserved)", 2597dd7cddfSDavid du Colombier "25 (reserved)", 2607dd7cddfSDavid du Colombier "26 (reserved)", 2617dd7cddfSDavid du Colombier "27 (reserved)", 2627dd7cddfSDavid du Colombier "28 (reserved)", 2637dd7cddfSDavid du Colombier "29 (reserved)", 2647dd7cddfSDavid du Colombier "30 (reserved)", 2657dd7cddfSDavid du Colombier "31 (reserved)", 2663e12c5d1SDavid du Colombier }; 2673e12c5d1SDavid du Colombier 2683e12c5d1SDavid du Colombier /* 2693ff48bf5SDavid du Colombier * keep histogram of interrupt service times 2703ff48bf5SDavid du Colombier */ 2713ff48bf5SDavid du Colombier void 2723ff48bf5SDavid du Colombier intrtime(Mach*, int vno) 2733ff48bf5SDavid du Colombier { 2743ff48bf5SDavid du Colombier ulong diff; 275e288d156SDavid du Colombier ulong x; 2763ff48bf5SDavid du Colombier 277e288d156SDavid du Colombier x = perfticks(); 2783ff48bf5SDavid du Colombier diff = x - m->perf.intrts; 2793ff48bf5SDavid du Colombier m->perf.intrts = x; 2803ff48bf5SDavid du Colombier 2813ff48bf5SDavid du Colombier m->perf.inintr += diff; 2823ff48bf5SDavid du Colombier if(up == nil && m->perf.inidle > diff) 2833ff48bf5SDavid du Colombier m->perf.inidle -= diff; 2843ff48bf5SDavid du Colombier 28541dd6b47SDavid du Colombier diff /= m->cpumhz*100; /* quantum = 100µsec */ 286e288d156SDavid du Colombier if(diff >= Ntimevec) 2873ff48bf5SDavid du Colombier diff = Ntimevec-1; 2883ff48bf5SDavid du Colombier intrtimes[vno][diff]++; 2893ff48bf5SDavid du Colombier } 2903ff48bf5SDavid du Colombier 291e288d156SDavid du Colombier /* go to user space */ 292e288d156SDavid du Colombier void 293e288d156SDavid du Colombier kexit(Ureg*) 294e288d156SDavid du Colombier { 295e288d156SDavid du Colombier uvlong t; 296e288d156SDavid du Colombier Tos *tos; 297e288d156SDavid du Colombier 298e288d156SDavid du Colombier /* precise time accounting, kernel exit */ 299e288d156SDavid du Colombier tos = (Tos*)(USTKTOP-sizeof(Tos)); 300e288d156SDavid du Colombier cycles(&t); 301e288d156SDavid du Colombier tos->kcycles += t - up->kentry; 302e288d156SDavid du Colombier tos->pcycles = up->pcycles; 303e288d156SDavid du Colombier tos->pid = up->pid; 304e288d156SDavid du Colombier } 305e288d156SDavid du Colombier 3063ff48bf5SDavid du Colombier /* 3077dd7cddfSDavid du Colombier * All traps come here. It is slower to have all traps call trap() 3087dd7cddfSDavid du Colombier * rather than directly vectoring the handler. However, this avoids a 3097dd7cddfSDavid du Colombier * lot of code duplication and possible bugs. The only exception is 3107dd7cddfSDavid du Colombier * VectorSYSCALL. 3117dd7cddfSDavid du Colombier * Trap is called with interrupts disabled via interrupt-gates. 3123e12c5d1SDavid du Colombier */ 3133e12c5d1SDavid du Colombier void 3147dd7cddfSDavid du Colombier trap(Ureg* ureg) 3153e12c5d1SDavid du Colombier { 3162009dc88SDavid du Colombier int clockintr, i, vno, user; 3179a747e4fSDavid du Colombier char buf[ERRMAX]; 3187dd7cddfSDavid du Colombier Vctl *ctl, *v; 3197dd7cddfSDavid du Colombier Mach *mach; 3203e12c5d1SDavid du Colombier 3214de34a7eSDavid du Colombier if(!trapinited){ 3224de34a7eSDavid du Colombier /* fault386 can give a better error message */ 3234de34a7eSDavid du Colombier if(ureg->trap == VectorPF) 3244de34a7eSDavid du Colombier fault386(ureg, nil); 3254de34a7eSDavid du Colombier panic("trap %lud: not ready", ureg->trap); 3264de34a7eSDavid du Colombier } 3274de34a7eSDavid du Colombier 3283ff48bf5SDavid du Colombier m->perf.intrts = perfticks(); 329e288d156SDavid du Colombier user = (ureg->cs & 0xFFFF) == UESEL; 330e288d156SDavid du Colombier if(user){ 3317dd7cddfSDavid du Colombier up->dbgreg = ureg; 332e288d156SDavid du Colombier cycles(&up->kentry); 333219b2ee8SDavid du Colombier } 3347dd7cddfSDavid du Colombier 3353cf081f0SDavid du Colombier clockintr = 0; 3363cf081f0SDavid du Colombier 3377dd7cddfSDavid du Colombier vno = ureg->trap; 3387dd7cddfSDavid du Colombier if(ctl = vctl[vno]){ 3397dd7cddfSDavid du Colombier if(ctl->isintr){ 3407dd7cddfSDavid du Colombier m->intr++; 3417dd7cddfSDavid du Colombier if(vno >= VectorPIC && vno != VectorSYSCALL) 3427dd7cddfSDavid du Colombier m->lastintr = ctl->irq; 3437dd7cddfSDavid du Colombier } 3447dd7cddfSDavid du Colombier 3457dd7cddfSDavid du Colombier if(ctl->isr) 3467dd7cddfSDavid du Colombier ctl->isr(vno); 3477dd7cddfSDavid du Colombier for(v = ctl; v != nil; v = v->next){ 3480701b922SDavid du Colombier if(v->f) 3497dd7cddfSDavid du Colombier v->f(ureg, v->a); 3507dd7cddfSDavid du Colombier } 3517dd7cddfSDavid du Colombier if(ctl->eoi) 3527dd7cddfSDavid du Colombier ctl->eoi(vno); 3533e12c5d1SDavid du Colombier 354a6a9e072SDavid du Colombier if(ctl->isintr){ 3553ff48bf5SDavid du Colombier intrtime(m, vno); 356179dd269SDavid du Colombier 3572009dc88SDavid du Colombier if(ctl->irq == IrqCLOCK || ctl->irq == IrqTIMER) 3582009dc88SDavid du Colombier clockintr = 1; 3592009dc88SDavid du Colombier 3602009dc88SDavid du Colombier if(up && !clockintr) 361a6a9e072SDavid du Colombier preempted(); 3623e12c5d1SDavid du Colombier } 3633e12c5d1SDavid du Colombier } 3647dd7cddfSDavid du Colombier else if(vno <= nelem(excname) && user){ 3657dd7cddfSDavid du Colombier spllo(); 3667dd7cddfSDavid du Colombier sprint(buf, "sys: trap: %s", excname[vno]); 3677dd7cddfSDavid du Colombier postnote(up, 1, buf, NDebug); 3687dd7cddfSDavid du Colombier } 3697dd7cddfSDavid du Colombier else if(vno >= VectorPIC && vno != VectorSYSCALL){ 370219b2ee8SDavid du Colombier /* 3717dd7cddfSDavid du Colombier * An unknown interrupt. 372219b2ee8SDavid du Colombier * Check for a default IRQ7. This can happen when 373219b2ee8SDavid du Colombier * the IRQ input goes away before the acknowledge. 374219b2ee8SDavid du Colombier * In this case, a 'default IRQ7' is generated, but 375219b2ee8SDavid du Colombier * the corresponding bit in the ISR isn't set. 376219b2ee8SDavid du Colombier * In fact, just ignore all such interrupts. 377219b2ee8SDavid du Colombier */ 3789a747e4fSDavid du Colombier 3799a747e4fSDavid du Colombier /* call all interrupt routines, just in case */ 3809a747e4fSDavid du Colombier for(i = VectorPIC; i <= MaxIrqLAPIC; i++){ 3819a747e4fSDavid du Colombier ctl = vctl[i]; 3829a747e4fSDavid du Colombier if(ctl == nil) 3839a747e4fSDavid du Colombier continue; 3849a747e4fSDavid du Colombier if(!ctl->isintr) 3859a747e4fSDavid du Colombier continue; 3869a747e4fSDavid du Colombier for(v = ctl; v != nil; v = v->next){ 3879a747e4fSDavid du Colombier if(v->f) 3889a747e4fSDavid du Colombier v->f(ureg, v->a); 3899a747e4fSDavid du Colombier } 3909a747e4fSDavid du Colombier /* should we do this? */ 3919a747e4fSDavid du Colombier if(ctl->eoi) 3929a747e4fSDavid du Colombier ctl->eoi(i); 3939a747e4fSDavid du Colombier } 3949a747e4fSDavid du Colombier 3959a747e4fSDavid du Colombier /* clear the interrupt */ 3969a747e4fSDavid du Colombier i8259isr(vno); 3979a747e4fSDavid du Colombier 398da51d93aSDavid du Colombier if(0)print("cpu%d: spurious interrupt %d, last %d\n", 3997dd7cddfSDavid du Colombier m->machno, vno, m->lastintr); 400da51d93aSDavid du Colombier if(0)if(conf.nmach > 1){ 4019a747e4fSDavid du Colombier for(i = 0; i < 32; i++){ 4027dd7cddfSDavid du Colombier if(!(active.machs & (1<<i))) 4037dd7cddfSDavid du Colombier continue; 4047dd7cddfSDavid du Colombier mach = MACHP(i); 4057dd7cddfSDavid du Colombier if(m->machno == mach->machno) 4067dd7cddfSDavid du Colombier continue; 407da51d93aSDavid du Colombier print(" cpu%d: last %d", 408da51d93aSDavid du Colombier mach->machno, mach->lastintr); 409219b2ee8SDavid du Colombier } 4107dd7cddfSDavid du Colombier print("\n"); 411e288d156SDavid du Colombier } 412da51d93aSDavid du Colombier m->spuriousintr++; 413da51d93aSDavid du Colombier if(user) 414da51d93aSDavid du Colombier kexit(ureg); 4153e12c5d1SDavid du Colombier return; 4163e12c5d1SDavid du Colombier } 4177dd7cddfSDavid du Colombier else{ 4187dd7cddfSDavid du Colombier if(vno == VectorNMI){ 419208510e1SDavid du Colombier /* 420208510e1SDavid du Colombier * Don't re-enable, it confuses the crash dumps. 4217dd7cddfSDavid du Colombier nmienable(); 422208510e1SDavid du Colombier */ 423208510e1SDavid du Colombier iprint("cpu%d: PC %#8.8lux\n", m->machno, ureg->pc); 424208510e1SDavid du Colombier while(m->machno != 0) 425208510e1SDavid du Colombier ; 4267dd7cddfSDavid du Colombier } 4277dd7cddfSDavid du Colombier dumpregs(ureg); 428fe853e23SDavid du Colombier if(!user){ 429fe853e23SDavid du Colombier ureg->sp = (ulong)&ureg->sp; 430fe853e23SDavid du Colombier _dumpstack(ureg); 431fe853e23SDavid du Colombier } 4327dd7cddfSDavid du Colombier if(vno < nelem(excname)) 4337dd7cddfSDavid du Colombier panic("%s", excname[vno]); 4347dd7cddfSDavid du Colombier panic("unknown trap/intr: %d\n", vno); 4357dd7cddfSDavid du Colombier } 436da51d93aSDavid du Colombier splhi(); 437da51d93aSDavid du Colombier 438da51d93aSDavid du Colombier /* delaysched set because we held a lock or because our quantum ended */ 4392009dc88SDavid du Colombier if(up && up->delaysched && clockintr){ 440da51d93aSDavid du Colombier sched(); 441da51d93aSDavid du Colombier splhi(); 442da51d93aSDavid du Colombier } 4433e12c5d1SDavid du Colombier 444e288d156SDavid du Colombier if(user){ 445da51d93aSDavid du Colombier if(up->procctl || up->nnote) 4467dd7cddfSDavid du Colombier notify(ureg); 447e288d156SDavid du Colombier kexit(ureg); 448e288d156SDavid du Colombier } 4493e12c5d1SDavid du Colombier } 4503e12c5d1SDavid du Colombier 4513e12c5d1SDavid du Colombier /* 4523e12c5d1SDavid du Colombier * dump registers 4533e12c5d1SDavid du Colombier */ 4543e12c5d1SDavid du Colombier void 4557dd7cddfSDavid du Colombier dumpregs2(Ureg* ureg) 4563e12c5d1SDavid du Colombier { 4577dd7cddfSDavid du Colombier if(up) 458208510e1SDavid du Colombier iprint("cpu%d: registers for %s %lud\n", 4597dd7cddfSDavid du Colombier m->machno, up->text, up->pid); 4603e12c5d1SDavid du Colombier else 461208510e1SDavid du Colombier iprint("cpu%d: registers for kernel\n", m->machno); 462208510e1SDavid du Colombier iprint("FLAGS=%luX TRAP=%luX ECODE=%luX PC=%luX", 4637dd7cddfSDavid du Colombier ureg->flags, ureg->trap, ureg->ecode, ureg->pc); 464208510e1SDavid du Colombier iprint(" SS=%4.4luX USP=%luX\n", ureg->ss & 0xFFFF, ureg->usp); 465208510e1SDavid du Colombier iprint(" AX %8.8luX BX %8.8luX CX %8.8luX DX %8.8luX\n", 4667dd7cddfSDavid du Colombier ureg->ax, ureg->bx, ureg->cx, ureg->dx); 467208510e1SDavid du Colombier iprint(" SI %8.8luX DI %8.8luX BP %8.8luX\n", 4687dd7cddfSDavid du Colombier ureg->si, ureg->di, ureg->bp); 469208510e1SDavid du Colombier iprint(" CS %4.4luX DS %4.4luX ES %4.4luX FS %4.4luX GS %4.4luX\n", 4707dd7cddfSDavid du Colombier ureg->cs & 0xFFFF, ureg->ds & 0xFFFF, ureg->es & 0xFFFF, 4717dd7cddfSDavid du Colombier ureg->fs & 0xFFFF, ureg->gs & 0xFFFF); 472219b2ee8SDavid du Colombier } 473219b2ee8SDavid du Colombier 474219b2ee8SDavid du Colombier void 4757dd7cddfSDavid du Colombier dumpregs(Ureg* ureg) 476219b2ee8SDavid du Colombier { 4777dd7cddfSDavid du Colombier vlong mca, mct; 4787dd7cddfSDavid du Colombier 4797dd7cddfSDavid du Colombier dumpregs2(ureg); 4807dd7cddfSDavid du Colombier 4817dd7cddfSDavid du Colombier /* 4827dd7cddfSDavid du Colombier * Processor control registers. 4837dd7cddfSDavid du Colombier * If machine check exception, time stamp counter, page size extensions 4847dd7cddfSDavid du Colombier * or enhanced virtual 8086 mode extensions are supported, there is a 4857dd7cddfSDavid du Colombier * CR4. If there is a CR4 and machine check extensions, read the machine 4867dd7cddfSDavid du Colombier * check address and machine check type registers if RDMSR supported. 4877dd7cddfSDavid du Colombier */ 488208510e1SDavid du Colombier iprint(" CR0 %8.8lux CR2 %8.8lux CR3 %8.8lux", 4897dd7cddfSDavid du Colombier getcr0(), getcr2(), getcr3()); 4907dd7cddfSDavid du Colombier if(m->cpuiddx & 0x9A){ 491208510e1SDavid du Colombier iprint(" CR4 %8.8lux", getcr4()); 4927dd7cddfSDavid du Colombier if((m->cpuiddx & 0xA0) == 0xA0){ 4937dd7cddfSDavid du Colombier rdmsr(0x00, &mca); 4947dd7cddfSDavid du Colombier rdmsr(0x01, &mct); 495208510e1SDavid du Colombier iprint("\n MCA %8.8llux MCT %8.8llux", mca, mct); 4967dd7cddfSDavid du Colombier } 4977dd7cddfSDavid du Colombier } 498208510e1SDavid du Colombier iprint("\n ur %lux up %lux\n", ureg, up); 4993e12c5d1SDavid du Colombier } 5003e12c5d1SDavid du Colombier 5017dd7cddfSDavid du Colombier 5027dd7cddfSDavid du Colombier /* 5037dd7cddfSDavid du Colombier * Fill in enough of Ureg to get a stack trace, and call a function. 5047dd7cddfSDavid du Colombier * Used by debugging interface rdb. 5057dd7cddfSDavid du Colombier */ 5063e12c5d1SDavid du Colombier void 5077dd7cddfSDavid du Colombier callwithureg(void (*fn)(Ureg*)) 5087dd7cddfSDavid du Colombier { 5097dd7cddfSDavid du Colombier Ureg ureg; 5107dd7cddfSDavid du Colombier ureg.pc = getcallerpc(&fn); 5117dd7cddfSDavid du Colombier ureg.sp = (ulong)&fn; 5127dd7cddfSDavid du Colombier fn(&ureg); 5137dd7cddfSDavid du Colombier } 5147dd7cddfSDavid du Colombier 5157dd7cddfSDavid du Colombier static void 5167dd7cddfSDavid du Colombier _dumpstack(Ureg *ureg) 5173e12c5d1SDavid du Colombier { 518208510e1SDavid du Colombier uintptr l, v, i, estack; 5193e12c5d1SDavid du Colombier extern ulong etext; 520fe853e23SDavid du Colombier int x; 521*edc15dd6SDavid du Colombier char *s; 5223e12c5d1SDavid du Colombier 523*edc15dd6SDavid du Colombier if((s = getconf("*nodumpstack")) != nil && strcmp(s, "0") != 0){ 52482cf11d1SDavid du Colombier iprint("dumpstack disabled\n"); 52582cf11d1SDavid du Colombier return; 52682cf11d1SDavid du Colombier } 527fe853e23SDavid du Colombier iprint("dumpstack\n"); 52882cf11d1SDavid du Colombier 529fe853e23SDavid du Colombier x = 0; 530208510e1SDavid du Colombier x += iprint("ktrace /kernel/path %.8lux %.8lux <<EOF\n", ureg->pc, ureg->sp); 5313e12c5d1SDavid du Colombier i = 0; 5329a747e4fSDavid du Colombier if(up 533208510e1SDavid du Colombier && (uintptr)&l >= (uintptr)up->kstack 534208510e1SDavid du Colombier && (uintptr)&l <= (uintptr)up->kstack+KSTACK) 535208510e1SDavid du Colombier estack = (uintptr)up->kstack+KSTACK; 536208510e1SDavid du Colombier else if((uintptr)&l >= (uintptr)m->stack 537208510e1SDavid du Colombier && (uintptr)&l <= (uintptr)m+MACHSIZE) 538208510e1SDavid du Colombier estack = (uintptr)m+MACHSIZE; 5399a747e4fSDavid du Colombier else 5409a747e4fSDavid du Colombier return; 541208510e1SDavid du Colombier x += iprint("estackx %p\n", estack); 5429a747e4fSDavid du Colombier 543208510e1SDavid du Colombier for(l = (uintptr)&l; l < estack; l += sizeof(uintptr)){ 544208510e1SDavid du Colombier v = *(uintptr*)l; 545208510e1SDavid du Colombier if((KTZERO < v && v < (uintptr)&etext) || estack-l < 32){ 5467dd7cddfSDavid du Colombier /* 547208510e1SDavid du Colombier * Could Pick off general CALL (((uchar*)v)[-5] == 0xE8) 548208510e1SDavid du Colombier * and CALL indirect through AX 549208510e1SDavid du Colombier * (((uchar*)v)[-2] == 0xFF && ((uchar*)v)[-2] == 0xD0), 5509a747e4fSDavid du Colombier * but this is too clever and misses faulting address. 5517dd7cddfSDavid du Colombier */ 552208510e1SDavid du Colombier x += iprint("%.8p=%.8p ", l, v); 5533e12c5d1SDavid du Colombier i++; 5543e12c5d1SDavid du Colombier } 5553e12c5d1SDavid du Colombier if(i == 4){ 5563e12c5d1SDavid du Colombier i = 0; 557208510e1SDavid du Colombier x += iprint("\n"); 5583e12c5d1SDavid du Colombier } 5593e12c5d1SDavid du Colombier } 5607dd7cddfSDavid du Colombier if(i) 561208510e1SDavid du Colombier iprint("\n"); 562208510e1SDavid du Colombier iprint("EOF\n"); 563208510e1SDavid du Colombier 564208510e1SDavid du Colombier if(ureg->trap != VectorNMI) 565208510e1SDavid du Colombier return; 566208510e1SDavid du Colombier 567208510e1SDavid du Colombier i = 0; 568208510e1SDavid du Colombier for(l = (uintptr)&l; l < estack; l += sizeof(uintptr)){ 569208510e1SDavid du Colombier iprint("%.8p ", *(uintptr*)l); 570208510e1SDavid du Colombier if(++i == 8){ 571208510e1SDavid du Colombier i = 0; 572208510e1SDavid du Colombier iprint("\n"); 573208510e1SDavid du Colombier } 574208510e1SDavid du Colombier } 575208510e1SDavid du Colombier if(i) 576208510e1SDavid du Colombier iprint("\n"); 5773e12c5d1SDavid du Colombier } 5783e12c5d1SDavid du Colombier 5797dd7cddfSDavid du Colombier void 5807dd7cddfSDavid du Colombier dumpstack(void) 5813e12c5d1SDavid du Colombier { 5827dd7cddfSDavid du Colombier callwithureg(_dumpstack); 5833e12c5d1SDavid du Colombier } 5843e12c5d1SDavid du Colombier 5857dd7cddfSDavid du Colombier static void 5867dd7cddfSDavid du Colombier debugbpt(Ureg* ureg, void*) 5873e12c5d1SDavid du Colombier { 5889a747e4fSDavid du Colombier char buf[ERRMAX]; 5897dd7cddfSDavid du Colombier 5907dd7cddfSDavid du Colombier if(up == 0) 5917dd7cddfSDavid du Colombier panic("kernel bpt"); 5927dd7cddfSDavid du Colombier /* restore pc to instruction that caused the trap */ 5937dd7cddfSDavid du Colombier ureg->pc--; 5947dd7cddfSDavid du Colombier sprint(buf, "sys: breakpoint"); 5957dd7cddfSDavid du Colombier postnote(up, 1, buf, NDebug); 5967dd7cddfSDavid du Colombier } 5977dd7cddfSDavid du Colombier 5987dd7cddfSDavid du Colombier static void 599e288d156SDavid du Colombier doublefault(Ureg*, void*) 600e288d156SDavid du Colombier { 601e288d156SDavid du Colombier panic("double fault"); 602e288d156SDavid du Colombier } 603e288d156SDavid du Colombier 604fe853e23SDavid du Colombier static void 605fe853e23SDavid du Colombier unexpected(Ureg* ureg, void*) 606fe853e23SDavid du Colombier { 607fe853e23SDavid du Colombier print("unexpected trap %lud; ignoring\n", ureg->trap); 608fe853e23SDavid du Colombier } 609e288d156SDavid du Colombier 610e862f8a5SDavid du Colombier extern void checkpages(void); 611be704722SDavid du Colombier extern void checkfault(ulong, ulong); 612e288d156SDavid du Colombier static void 6137dd7cddfSDavid du Colombier fault386(Ureg* ureg, void*) 6147dd7cddfSDavid du Colombier { 6157dd7cddfSDavid du Colombier ulong addr; 6167dd7cddfSDavid du Colombier int read, user, n, insyscall; 6179a747e4fSDavid du Colombier char buf[ERRMAX]; 6187dd7cddfSDavid du Colombier 6197dd7cddfSDavid du Colombier addr = getcr2(); 6207dd7cddfSDavid du Colombier read = !(ureg->ecode & 2); 6214de34a7eSDavid du Colombier 6224de34a7eSDavid du Colombier user = (ureg->cs & 0xFFFF) == UESEL; 6234de34a7eSDavid du Colombier if(!user){ 6244de34a7eSDavid du Colombier if(vmapsync(addr)) 6254de34a7eSDavid du Colombier return; 6264de34a7eSDavid du Colombier if(addr >= USTKTOP) 6274de34a7eSDavid du Colombier panic("kernel fault: bad address pc=0x%.8lux addr=0x%.8lux", ureg->pc, addr); 6289a747e4fSDavid du Colombier if(up == nil) 6294de34a7eSDavid du Colombier panic("kernel fault: no user process pc=0x%.8lux addr=0x%.8lux", ureg->pc, addr); 6304de34a7eSDavid du Colombier } 6314de34a7eSDavid du Colombier if(up == nil) 6324de34a7eSDavid du Colombier panic("user fault: up=0 pc=0x%.8lux addr=0x%.8lux", ureg->pc, addr); 6334de34a7eSDavid du Colombier 6347dd7cddfSDavid du Colombier insyscall = up->insyscall; 6357dd7cddfSDavid du Colombier up->insyscall = 1; 6367dd7cddfSDavid du Colombier n = fault(addr, read); 6377dd7cddfSDavid du Colombier if(n < 0){ 6387dd7cddfSDavid du Colombier if(!user){ 6397dd7cddfSDavid du Colombier dumpregs(ureg); 6407dd7cddfSDavid du Colombier panic("fault: 0x%lux\n", addr); 6417dd7cddfSDavid du Colombier } 642d717568cSDavid du Colombier checkpages(); 643be704722SDavid du Colombier checkfault(addr, ureg->pc); 6447dd7cddfSDavid du Colombier sprint(buf, "sys: trap: fault %s addr=0x%lux", 6457dd7cddfSDavid du Colombier read ? "read" : "write", addr); 6467dd7cddfSDavid du Colombier postnote(up, 1, buf, NDebug); 6477dd7cddfSDavid du Colombier } 6487dd7cddfSDavid du Colombier up->insyscall = insyscall; 6493e12c5d1SDavid du Colombier } 6503e12c5d1SDavid du Colombier 6513e12c5d1SDavid du Colombier /* 6523e12c5d1SDavid du Colombier * system calls 6533e12c5d1SDavid du Colombier */ 6543e12c5d1SDavid du Colombier #include "../port/systab.h" 6553e12c5d1SDavid du Colombier 6563e12c5d1SDavid du Colombier /* 6577dd7cddfSDavid du Colombier * Syscall is called directly from assembler without going through trap(). 6583e12c5d1SDavid du Colombier */ 6597dd7cddfSDavid du Colombier void 6607dd7cddfSDavid du Colombier syscall(Ureg* ureg) 6613e12c5d1SDavid du Colombier { 6629a747e4fSDavid du Colombier char *e; 6633e12c5d1SDavid du Colombier ulong sp; 6643e12c5d1SDavid du Colombier long ret; 665e288d156SDavid du Colombier int i, s; 6669a747e4fSDavid du Colombier ulong scallnr; 6673e12c5d1SDavid du Colombier 6687dd7cddfSDavid du Colombier if((ureg->cs & 0xFFFF) != UESEL) 6699a747e4fSDavid du Colombier panic("syscall: cs 0x%4.4luX\n", ureg->cs); 670219b2ee8SDavid du Colombier 671e288d156SDavid du Colombier cycles(&up->kentry); 672e288d156SDavid du Colombier 6737dd7cddfSDavid du Colombier m->syscall++; 6747dd7cddfSDavid du Colombier up->insyscall = 1; 6757dd7cddfSDavid du Colombier up->pc = ureg->pc; 6767dd7cddfSDavid du Colombier up->dbgreg = ureg; 6773e12c5d1SDavid du Colombier 678e288d156SDavid du Colombier if(up->procctl == Proc_tracesyscall){ 679e288d156SDavid du Colombier up->procctl = Proc_stopme; 680e288d156SDavid du Colombier procctl(up); 681e288d156SDavid du Colombier } 682e288d156SDavid du Colombier 6837dd7cddfSDavid du Colombier scallnr = ureg->ax; 6847dd7cddfSDavid du Colombier up->scallnr = scallnr; 6857dd7cddfSDavid du Colombier if(scallnr == RFORK && up->fpstate == FPactive){ 6867dd7cddfSDavid du Colombier fpsave(&up->fpsave); 6877dd7cddfSDavid du Colombier up->fpstate = FPinactive; 6883e12c5d1SDavid du Colombier } 6893e12c5d1SDavid du Colombier spllo(); 6907dd7cddfSDavid du Colombier 6917dd7cddfSDavid du Colombier sp = ureg->usp; 6927dd7cddfSDavid du Colombier up->nerrlab = 0; 6933e12c5d1SDavid du Colombier ret = -1; 6943e12c5d1SDavid du Colombier if(!waserror()){ 6959a747e4fSDavid du Colombier if(scallnr >= nsyscall || systab[scallnr] == 0){ 6967dd7cddfSDavid du Colombier pprint("bad sys call number %d pc %lux\n", 6977dd7cddfSDavid du Colombier scallnr, ureg->pc); 6987dd7cddfSDavid du Colombier postnote(up, 1, "sys: bad sys call", NDebug); 6993e12c5d1SDavid du Colombier error(Ebadarg); 7003e12c5d1SDavid du Colombier } 7013e12c5d1SDavid du Colombier 7027dd7cddfSDavid du Colombier if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)-BY2WD)) 7037dd7cddfSDavid du Colombier validaddr(sp, sizeof(Sargs)+BY2WD, 0); 7043e12c5d1SDavid du Colombier 7057dd7cddfSDavid du Colombier up->s = *((Sargs*)(sp+BY2WD)); 7067dd7cddfSDavid du Colombier up->psstate = sysctab[scallnr]; 7073e12c5d1SDavid du Colombier 7087dd7cddfSDavid du Colombier ret = systab[scallnr](up->s.args); 7093e12c5d1SDavid du Colombier poperror(); 7109a747e4fSDavid du Colombier }else{ 7119a747e4fSDavid du Colombier /* failure: save the error buffer for errstr */ 7129a747e4fSDavid du Colombier e = up->syserrstr; 7139a747e4fSDavid du Colombier up->syserrstr = up->errstr; 7149a747e4fSDavid du Colombier up->errstr = e; 71503172982SDavid du Colombier if(0 && up->pid == 1) 71603172982SDavid du Colombier print("syscall %lud error %s\n", scallnr, up->syserrstr); 7173e12c5d1SDavid du Colombier } 7187dd7cddfSDavid du Colombier if(up->nerrlab){ 719e288d156SDavid du Colombier print("bad errstack [%lud]: %d extra\n", scallnr, up->nerrlab); 7203e12c5d1SDavid du Colombier for(i = 0; i < NERR; i++) 7217dd7cddfSDavid du Colombier print("sp=%lux pc=%lux\n", 7227dd7cddfSDavid du Colombier up->errlab[i].sp, up->errlab[i].pc); 7233e12c5d1SDavid du Colombier panic("error stack"); 7243e12c5d1SDavid du Colombier } 7253e12c5d1SDavid du Colombier 7263e12c5d1SDavid du Colombier /* 7277dd7cddfSDavid du Colombier * Put return value in frame. On the x86 the syscall is 7283e12c5d1SDavid du Colombier * just another trap and the return value from syscall is 7293e12c5d1SDavid du Colombier * ignored. On other machines the return value is put into 7303e12c5d1SDavid du Colombier * the results register by caller of syscall. 7313e12c5d1SDavid du Colombier */ 7327dd7cddfSDavid du Colombier ureg->ax = ret; 7333e12c5d1SDavid du Colombier 734e288d156SDavid du Colombier if(up->procctl == Proc_tracesyscall){ 735e288d156SDavid du Colombier up->procctl = Proc_stopme; 736e288d156SDavid du Colombier s = splhi(); 737e288d156SDavid du Colombier procctl(up); 738e288d156SDavid du Colombier splx(s); 739e288d156SDavid du Colombier } 740e288d156SDavid du Colombier 741e288d156SDavid du Colombier up->insyscall = 0; 742e288d156SDavid du Colombier up->psstate = 0; 743e288d156SDavid du Colombier 7447dd7cddfSDavid du Colombier if(scallnr == NOTED) 7457dd7cddfSDavid du Colombier noted(ureg, *(ulong*)(sp+BY2WD)); 7463e12c5d1SDavid du Colombier 7477dd7cddfSDavid du Colombier if(scallnr!=RFORK && (up->procctl || up->nnote)){ 7487dd7cddfSDavid du Colombier splhi(); 7497dd7cddfSDavid du Colombier notify(ureg); 7507dd7cddfSDavid du Colombier } 751e288d156SDavid du Colombier /* if we delayed sched because we held a lock, sched now */ 752e288d156SDavid du Colombier if(up->delaysched) 753e288d156SDavid du Colombier sched(); 754e288d156SDavid du Colombier kexit(ureg); 7553e12c5d1SDavid du Colombier } 7563e12c5d1SDavid du Colombier 7573e12c5d1SDavid du Colombier /* 7583e12c5d1SDavid du Colombier * Call user, if necessary, with note. 7593e12c5d1SDavid du Colombier * Pass user the Ureg struct and the note on his stack. 7603e12c5d1SDavid du Colombier */ 7613e12c5d1SDavid du Colombier int 7627dd7cddfSDavid du Colombier notify(Ureg* ureg) 7633e12c5d1SDavid du Colombier { 764219b2ee8SDavid du Colombier int l; 7653e12c5d1SDavid du Colombier ulong s, sp; 7663e12c5d1SDavid du Colombier Note *n; 7673e12c5d1SDavid du Colombier 7687dd7cddfSDavid du Colombier if(up->procctl) 7697dd7cddfSDavid du Colombier procctl(up); 7707dd7cddfSDavid du Colombier if(up->nnote == 0) 7713e12c5d1SDavid du Colombier return 0; 7723e12c5d1SDavid du Colombier 7733ff48bf5SDavid du Colombier if(up->fpstate == FPactive){ 7743ff48bf5SDavid du Colombier fpsave(&up->fpsave); 7753ff48bf5SDavid du Colombier up->fpstate = FPinactive; 7763ff48bf5SDavid du Colombier } 7773ff48bf5SDavid du Colombier up->fpstate |= FPillegal; 7783ff48bf5SDavid du Colombier 7793e12c5d1SDavid du Colombier s = spllo(); 7807dd7cddfSDavid du Colombier qlock(&up->debug); 7817dd7cddfSDavid du Colombier up->notepending = 0; 7827dd7cddfSDavid du Colombier n = &up->note[0]; 7833e12c5d1SDavid du Colombier if(strncmp(n->msg, "sys:", 4) == 0){ 7843e12c5d1SDavid du Colombier l = strlen(n->msg); 7859a747e4fSDavid du Colombier if(l > ERRMAX-15) /* " pc=0x12345678\0" */ 7869a747e4fSDavid du Colombier l = ERRMAX-15; 7877dd7cddfSDavid du Colombier sprint(n->msg+l, " pc=0x%.8lux", ureg->pc); 7883e12c5d1SDavid du Colombier } 789219b2ee8SDavid du Colombier 7907dd7cddfSDavid du Colombier if(n->flag!=NUser && (up->notified || up->notify==0)){ 7917dd7cddfSDavid du Colombier if(n->flag == NDebug) 7923e12c5d1SDavid du Colombier pprint("suicide: %s\n", n->msg); 7937dd7cddfSDavid du Colombier qunlock(&up->debug); 7943e12c5d1SDavid du Colombier pexit(n->msg, n->flag!=NDebug); 7953e12c5d1SDavid du Colombier } 796219b2ee8SDavid du Colombier 7977dd7cddfSDavid du Colombier if(up->notified){ 7987dd7cddfSDavid du Colombier qunlock(&up->debug); 799219b2ee8SDavid du Colombier splhi(); 800219b2ee8SDavid du Colombier return 0; 801219b2ee8SDavid du Colombier } 802219b2ee8SDavid du Colombier 8037dd7cddfSDavid du Colombier if(!up->notify){ 8047dd7cddfSDavid du Colombier qunlock(&up->debug); 805bd389b36SDavid du Colombier pexit(n->msg, n->flag!=NDebug); 806bd389b36SDavid du Colombier } 8077dd7cddfSDavid du Colombier sp = ureg->usp; 808208510e1SDavid du Colombier sp -= 256; /* debugging: preserve context causing problem */ 8093e12c5d1SDavid du Colombier sp -= sizeof(Ureg); 810208510e1SDavid du Colombier if(0) print("%s %lud: notify %.8lux %.8lux %.8lux %s\n", 811208510e1SDavid du Colombier up->text, up->pid, ureg->pc, ureg->usp, sp, n->msg); 812219b2ee8SDavid du Colombier 8137dd7cddfSDavid du Colombier if(!okaddr((ulong)up->notify, 1, 0) 8149a747e4fSDavid du Colombier || !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)){ 815219b2ee8SDavid du Colombier pprint("suicide: bad address in notify\n"); 8167dd7cddfSDavid du Colombier qunlock(&up->debug); 8173e12c5d1SDavid du Colombier pexit("Suicide", 0); 8183e12c5d1SDavid du Colombier } 819219b2ee8SDavid du Colombier 8207dd7cddfSDavid du Colombier up->ureg = (void*)sp; 8217dd7cddfSDavid du Colombier memmove((Ureg*)sp, ureg, sizeof(Ureg)); 8227dd7cddfSDavid du Colombier *(Ureg**)(sp-BY2WD) = up->ureg; /* word under Ureg is old up->ureg */ 8237dd7cddfSDavid du Colombier up->ureg = (void*)sp; 8249a747e4fSDavid du Colombier sp -= BY2WD+ERRMAX; 8259a747e4fSDavid du Colombier memmove((char*)sp, up->note[0].msg, ERRMAX); 8263e12c5d1SDavid du Colombier sp -= 3*BY2WD; 8273e12c5d1SDavid du Colombier *(ulong*)(sp+2*BY2WD) = sp+3*BY2WD; /* arg 2 is string */ 8287dd7cddfSDavid du Colombier *(ulong*)(sp+1*BY2WD) = (ulong)up->ureg; /* arg 1 is ureg* */ 8293e12c5d1SDavid du Colombier *(ulong*)(sp+0*BY2WD) = 0; /* arg 0 is pc */ 8307dd7cddfSDavid du Colombier ureg->usp = sp; 8317dd7cddfSDavid du Colombier ureg->pc = (ulong)up->notify; 8327dd7cddfSDavid du Colombier up->notified = 1; 8337dd7cddfSDavid du Colombier up->nnote--; 8347dd7cddfSDavid du Colombier memmove(&up->lastnote, &up->note[0], sizeof(Note)); 8357dd7cddfSDavid du Colombier memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note)); 836219b2ee8SDavid du Colombier 8377dd7cddfSDavid du Colombier qunlock(&up->debug); 8383e12c5d1SDavid du Colombier splx(s); 839219b2ee8SDavid du Colombier return 1; 8403e12c5d1SDavid du Colombier } 8413e12c5d1SDavid du Colombier 8423e12c5d1SDavid du Colombier /* 8433e12c5d1SDavid du Colombier * Return user to state before notify() 8443e12c5d1SDavid du Colombier */ 8453e12c5d1SDavid du Colombier void 8467dd7cddfSDavid du Colombier noted(Ureg* ureg, ulong arg0) 8473e12c5d1SDavid du Colombier { 8487dd7cddfSDavid du Colombier Ureg *nureg; 849219b2ee8SDavid du Colombier ulong oureg, sp; 8503e12c5d1SDavid du Colombier 8517dd7cddfSDavid du Colombier qlock(&up->debug); 8527dd7cddfSDavid du Colombier if(arg0!=NRSTR && !up->notified) { 8537dd7cddfSDavid du Colombier qunlock(&up->debug); 854219b2ee8SDavid du Colombier pprint("call to noted() when not notified\n"); 8553e12c5d1SDavid du Colombier pexit("Suicide", 0); 8563e12c5d1SDavid du Colombier } 8577dd7cddfSDavid du Colombier up->notified = 0; 858219b2ee8SDavid du Colombier 8597dd7cddfSDavid du Colombier nureg = up->ureg; /* pointer to user returned Ureg struct */ 860219b2ee8SDavid du Colombier 8613ff48bf5SDavid du Colombier up->fpstate &= ~FPillegal; 8623ff48bf5SDavid du Colombier 863219b2ee8SDavid du Colombier /* sanity clause */ 8647dd7cddfSDavid du Colombier oureg = (ulong)nureg; 865219b2ee8SDavid du Colombier if(!okaddr((ulong)oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){ 8667dd7cddfSDavid du Colombier pprint("bad ureg in noted or call to noted when not notified\n"); 8677dd7cddfSDavid du Colombier qunlock(&up->debug); 868219b2ee8SDavid du Colombier pexit("Suicide", 0); 869219b2ee8SDavid du Colombier } 870219b2ee8SDavid du Colombier 8717dd7cddfSDavid du Colombier /* 8727dd7cddfSDavid du Colombier * Check the segment selectors are all valid, otherwise 8737dd7cddfSDavid du Colombier * a fault will be taken on attempting to return to the 8747dd7cddfSDavid du Colombier * user process. 8757dd7cddfSDavid du Colombier * Take care with the comparisons as different processor 8767dd7cddfSDavid du Colombier * generations push segment descriptors in different ways. 8777dd7cddfSDavid du Colombier */ 8787dd7cddfSDavid du Colombier if((nureg->cs & 0xFFFF) != UESEL || (nureg->ss & 0xFFFF) != UDSEL 8797dd7cddfSDavid du Colombier || (nureg->ds & 0xFFFF) != UDSEL || (nureg->es & 0xFFFF) != UDSEL 8807dd7cddfSDavid du Colombier || (nureg->fs & 0xFFFF) != UDSEL || (nureg->gs & 0xFFFF) != UDSEL){ 8817dd7cddfSDavid du Colombier pprint("bad segment selector in noted\n"); 8827dd7cddfSDavid du Colombier qunlock(&up->debug); 8837dd7cddfSDavid du Colombier pexit("Suicide", 0); 8847dd7cddfSDavid du Colombier } 885219b2ee8SDavid du Colombier 886219b2ee8SDavid du Colombier /* don't let user change system flags */ 8877dd7cddfSDavid du Colombier nureg->flags = (ureg->flags & ~0xCD5) | (nureg->flags & 0xCD5); 888219b2ee8SDavid du Colombier 8897dd7cddfSDavid du Colombier memmove(ureg, nureg, sizeof(Ureg)); 890219b2ee8SDavid du Colombier 8913e12c5d1SDavid du Colombier switch(arg0){ 8923e12c5d1SDavid du Colombier case NCONT: 893219b2ee8SDavid du Colombier case NRSTR: 894208510e1SDavid du Colombier if(0) print("%s %lud: noted %.8lux %.8lux\n", 895208510e1SDavid du Colombier up->text, up->pid, nureg->pc, nureg->usp); 8967dd7cddfSDavid du Colombier if(!okaddr(nureg->pc, 1, 0) || !okaddr(nureg->usp, BY2WD, 0)){ 8977dd7cddfSDavid du Colombier qunlock(&up->debug); 898219b2ee8SDavid du Colombier pprint("suicide: trap in noted\n"); 899219b2ee8SDavid du Colombier pexit("Suicide", 0); 900219b2ee8SDavid du Colombier } 9017dd7cddfSDavid du Colombier up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD)); 9027dd7cddfSDavid du Colombier qunlock(&up->debug); 903219b2ee8SDavid du Colombier break; 904219b2ee8SDavid du Colombier 905219b2ee8SDavid du Colombier case NSAVE: 9067dd7cddfSDavid du Colombier if(!okaddr(nureg->pc, BY2WD, 0) 9077dd7cddfSDavid du Colombier || !okaddr(nureg->usp, BY2WD, 0)){ 9087dd7cddfSDavid du Colombier qunlock(&up->debug); 909219b2ee8SDavid du Colombier pprint("suicide: trap in noted\n"); 910219b2ee8SDavid du Colombier pexit("Suicide", 0); 9113e12c5d1SDavid du Colombier } 9127dd7cddfSDavid du Colombier qunlock(&up->debug); 9139a747e4fSDavid du Colombier sp = oureg-4*BY2WD-ERRMAX; 914219b2ee8SDavid du Colombier splhi(); 9157dd7cddfSDavid du Colombier ureg->sp = sp; 916219b2ee8SDavid du Colombier ((ulong*)sp)[1] = oureg; /* arg 1 0(FP) is ureg* */ 917219b2ee8SDavid du Colombier ((ulong*)sp)[0] = 0; /* arg 0 is pc */ 918219b2ee8SDavid du Colombier break; 9193e12c5d1SDavid du Colombier 9203e12c5d1SDavid du Colombier default: 921219b2ee8SDavid du Colombier pprint("unknown noted arg 0x%lux\n", arg0); 9227dd7cddfSDavid du Colombier up->lastnote.flag = NDebug; 9237dd7cddfSDavid du Colombier /* fall through */ 9243e12c5d1SDavid du Colombier 9253e12c5d1SDavid du Colombier case NDFLT: 9267dd7cddfSDavid du Colombier if(up->lastnote.flag == NDebug){ 9277dd7cddfSDavid du Colombier qunlock(&up->debug); 9287dd7cddfSDavid du Colombier pprint("suicide: %s\n", up->lastnote.msg); 929219b2ee8SDavid du Colombier } else 9307dd7cddfSDavid du Colombier qunlock(&up->debug); 9317dd7cddfSDavid du Colombier pexit(up->lastnote.msg, up->lastnote.flag!=NDebug); 9323e12c5d1SDavid du Colombier } 9333e12c5d1SDavid du Colombier } 9343e12c5d1SDavid du Colombier 9357dd7cddfSDavid du Colombier long 9367dd7cddfSDavid du Colombier execregs(ulong entry, ulong ssize, ulong nargs) 9377dd7cddfSDavid du Colombier { 9387dd7cddfSDavid du Colombier ulong *sp; 9397dd7cddfSDavid du Colombier Ureg *ureg; 9407dd7cddfSDavid du Colombier 9414de34a7eSDavid du Colombier up->fpstate = FPinit; 9424de34a7eSDavid du Colombier fpoff(); 9434de34a7eSDavid du Colombier 9447dd7cddfSDavid du Colombier sp = (ulong*)(USTKTOP - ssize); 9457dd7cddfSDavid du Colombier *--sp = nargs; 9467dd7cddfSDavid du Colombier 9477dd7cddfSDavid du Colombier ureg = up->dbgreg; 9487dd7cddfSDavid du Colombier ureg->usp = (ulong)sp; 9497dd7cddfSDavid du Colombier ureg->pc = entry; 950e288d156SDavid du Colombier return USTKTOP-sizeof(Tos); /* address of kernel/user shared data */ 9517dd7cddfSDavid du Colombier } 9527dd7cddfSDavid du Colombier 95359cc4ca5SDavid du Colombier /* 95459cc4ca5SDavid du Colombier * return the userpc the last exception happened at 95559cc4ca5SDavid du Colombier */ 9567dd7cddfSDavid du Colombier ulong 9577dd7cddfSDavid du Colombier userpc(void) 9587dd7cddfSDavid du Colombier { 9597dd7cddfSDavid du Colombier Ureg *ureg; 9607dd7cddfSDavid du Colombier 9617dd7cddfSDavid du Colombier ureg = (Ureg*)up->dbgreg; 9627dd7cddfSDavid du Colombier return ureg->pc; 9637dd7cddfSDavid du Colombier } 9647dd7cddfSDavid du Colombier 9657dd7cddfSDavid du Colombier /* This routine must save the values of registers the user is not permitted 9667dd7cddfSDavid du Colombier * to write from devproc and then restore the saved values before returning. 9673e12c5d1SDavid du Colombier */ 9683e12c5d1SDavid du Colombier void 9697dd7cddfSDavid du Colombier setregisters(Ureg* ureg, char* pureg, char* uva, int n) 9703e12c5d1SDavid du Colombier { 9713e12c5d1SDavid du Colombier ulong flags; 9723e12c5d1SDavid du Colombier ulong cs; 9733e12c5d1SDavid du Colombier ulong ss; 9743e12c5d1SDavid du Colombier 9757dd7cddfSDavid du Colombier flags = ureg->flags; 9767dd7cddfSDavid du Colombier cs = ureg->cs; 9777dd7cddfSDavid du Colombier ss = ureg->ss; 9783e12c5d1SDavid du Colombier memmove(pureg, uva, n); 9797dd7cddfSDavid du Colombier ureg->flags = (ureg->flags & 0x00FF) | (flags & 0xFF00); 9807dd7cddfSDavid du Colombier ureg->cs = cs; 9817dd7cddfSDavid du Colombier ureg->ss = ss; 9827dd7cddfSDavid du Colombier } 9837dd7cddfSDavid du Colombier 9847dd7cddfSDavid du Colombier static void 9857dd7cddfSDavid du Colombier linkproc(void) 9867dd7cddfSDavid du Colombier { 9877dd7cddfSDavid du Colombier spllo(); 9887dd7cddfSDavid du Colombier up->kpfun(up->kparg); 9893ff48bf5SDavid du Colombier pexit("kproc dying", 0); 9907dd7cddfSDavid du Colombier } 9917dd7cddfSDavid du Colombier 9927dd7cddfSDavid du Colombier void 9937dd7cddfSDavid du Colombier kprocchild(Proc* p, void (*func)(void*), void* arg) 9947dd7cddfSDavid du Colombier { 9957dd7cddfSDavid du Colombier /* 9967dd7cddfSDavid du Colombier * gotolabel() needs a word on the stack in 9977dd7cddfSDavid du Colombier * which to place the return PC used to jump 9987dd7cddfSDavid du Colombier * to linkproc(). 9997dd7cddfSDavid du Colombier */ 10007dd7cddfSDavid du Colombier p->sched.pc = (ulong)linkproc; 10017dd7cddfSDavid du Colombier p->sched.sp = (ulong)p->kstack+KSTACK-BY2WD; 10027dd7cddfSDavid du Colombier 10037dd7cddfSDavid du Colombier p->kpfun = func; 10047dd7cddfSDavid du Colombier p->kparg = arg; 10057dd7cddfSDavid du Colombier } 10067dd7cddfSDavid du Colombier 10077dd7cddfSDavid du Colombier void 10087dd7cddfSDavid du Colombier forkchild(Proc *p, Ureg *ureg) 10097dd7cddfSDavid du Colombier { 10107dd7cddfSDavid du Colombier Ureg *cureg; 10117dd7cddfSDavid du Colombier 10127dd7cddfSDavid du Colombier /* 10137dd7cddfSDavid du Colombier * Add 2*BY2WD to the stack to account for 10147dd7cddfSDavid du Colombier * - the return PC 10157dd7cddfSDavid du Colombier * - trap's argument (ur) 10167dd7cddfSDavid du Colombier */ 10177dd7cddfSDavid du Colombier p->sched.sp = (ulong)p->kstack+KSTACK-(sizeof(Ureg)+2*BY2WD); 10187dd7cddfSDavid du Colombier p->sched.pc = (ulong)forkret; 10197dd7cddfSDavid du Colombier 10207dd7cddfSDavid du Colombier cureg = (Ureg*)(p->sched.sp+2*BY2WD); 10217dd7cddfSDavid du Colombier memmove(cureg, ureg, sizeof(Ureg)); 10227dd7cddfSDavid du Colombier /* return value of syscall in child */ 10237dd7cddfSDavid du Colombier cureg->ax = 0; 10247dd7cddfSDavid du Colombier 10257dd7cddfSDavid du Colombier /* Things from bottom of syscall which were never executed */ 10267dd7cddfSDavid du Colombier p->psstate = 0; 10277dd7cddfSDavid du Colombier p->insyscall = 0; 10287dd7cddfSDavid du Colombier } 10297dd7cddfSDavid du Colombier 10307dd7cddfSDavid du Colombier /* Give enough context in the ureg to produce a kernel stack for 10317dd7cddfSDavid du Colombier * a sleeping process 10327dd7cddfSDavid du Colombier */ 10337dd7cddfSDavid du Colombier void 10347dd7cddfSDavid du Colombier setkernur(Ureg* ureg, Proc* p) 10357dd7cddfSDavid du Colombier { 10367dd7cddfSDavid du Colombier ureg->pc = p->sched.pc; 10377dd7cddfSDavid du Colombier ureg->sp = p->sched.sp+4; 10387dd7cddfSDavid du Colombier } 10397dd7cddfSDavid du Colombier 10407dd7cddfSDavid du Colombier ulong 10417dd7cddfSDavid du Colombier dbgpc(Proc *p) 10427dd7cddfSDavid du Colombier { 10437dd7cddfSDavid du Colombier Ureg *ureg; 10447dd7cddfSDavid du Colombier 10457dd7cddfSDavid du Colombier ureg = p->dbgreg; 10467dd7cddfSDavid du Colombier if(ureg == 0) 10477dd7cddfSDavid du Colombier return 0; 10487dd7cddfSDavid du Colombier 10497dd7cddfSDavid du Colombier return ureg->pc; 10503e12c5d1SDavid du Colombier } 1051