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
intrenable(int irq,void (* f)(Ureg *,void *),void * a,int tbdf,char * name)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)
63c9b6d007SDavid du Colombier panic("intrenable: handler: %s %s %#p %#p %#p %#p",
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
intrdisable(int irq,void (* f)(Ureg *,void *),void * a,int tbdf,char * name)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
irqallocread(Chan *,void * vbuf,long n,vlong offset)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
trapenable(int vno,void (* f)(Ureg *,void *),void * a,char * name)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)
149c9b6d007SDavid du Colombier panic("trapenable: vno %d", 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);
15876a51bbfSDavid du Colombier v->next = vctl[vno];
1597dd7cddfSDavid du Colombier vctl[vno] = v;
160061a3f44SDavid du Colombier iunlock(&vctllock);
1617dd7cddfSDavid du Colombier }
1627dd7cddfSDavid du Colombier
1637dd7cddfSDavid du Colombier static void
nmienable(void)1647dd7cddfSDavid du Colombier nmienable(void)
1657dd7cddfSDavid du Colombier {
1667dd7cddfSDavid du Colombier int x;
1673e12c5d1SDavid du Colombier
1683e12c5d1SDavid du Colombier /*
1697dd7cddfSDavid du Colombier * Hack: should be locked with NVRAM access.
1703e12c5d1SDavid du Colombier */
1717dd7cddfSDavid du Colombier outb(0x70, 0x80); /* NMI latch clear */
1727dd7cddfSDavid du Colombier outb(0x70, 0);
1737dd7cddfSDavid du Colombier
1747dd7cddfSDavid du Colombier x = inb(0x61) & 0x07; /* Enable NMI */
1757dd7cddfSDavid du Colombier outb(0x61, 0x08|x);
1767dd7cddfSDavid du Colombier outb(0x61, x);
1773e12c5d1SDavid du Colombier }
1783e12c5d1SDavid du Colombier
1794de34a7eSDavid du Colombier /*
1804de34a7eSDavid du Colombier * Minimal trap setup. Just enough so that we can panic
1814de34a7eSDavid du Colombier * on traps (bugs) during kernel initialization.
1824de34a7eSDavid du Colombier * Called very early - malloc is not yet available.
1834de34a7eSDavid du Colombier */
1843e12c5d1SDavid du Colombier void
trapinit0(void)1854de34a7eSDavid du Colombier trapinit0(void)
1863e12c5d1SDavid du Colombier {
1877dd7cddfSDavid du Colombier int d1, v;
1887dd7cddfSDavid du Colombier ulong vaddr;
1897dd7cddfSDavid du Colombier Segdesc *idt;
1903e12c5d1SDavid du Colombier
1917dd7cddfSDavid du Colombier idt = (Segdesc*)IDTADDR;
1927dd7cddfSDavid du Colombier vaddr = (ulong)vectortable;
1937dd7cddfSDavid du Colombier for(v = 0; v < 256; v++){
1947dd7cddfSDavid du Colombier d1 = (vaddr & 0xFFFF0000)|SEGP;
1957dd7cddfSDavid du Colombier switch(v){
1963e12c5d1SDavid du Colombier
1977dd7cddfSDavid du Colombier case VectorBPT:
1987dd7cddfSDavid du Colombier d1 |= SEGPL(3)|SEGIG;
1997dd7cddfSDavid du Colombier break;
2003e12c5d1SDavid du Colombier
2017dd7cddfSDavid du Colombier case VectorSYSCALL:
2027dd7cddfSDavid du Colombier d1 |= SEGPL(3)|SEGIG;
2037dd7cddfSDavid du Colombier break;
2043e12c5d1SDavid du Colombier
2057dd7cddfSDavid du Colombier default:
2067dd7cddfSDavid du Colombier d1 |= SEGPL(0)|SEGIG;
2077dd7cddfSDavid du Colombier break;
2087dd7cddfSDavid du Colombier }
2097dd7cddfSDavid du Colombier idt[v].d0 = (vaddr & 0xFFFF)|(KESEL<<16);
2107dd7cddfSDavid du Colombier idt[v].d1 = d1;
2117dd7cddfSDavid du Colombier vaddr += 6;
2123e12c5d1SDavid du Colombier }
2134de34a7eSDavid du Colombier }
2143e12c5d1SDavid du Colombier
2154de34a7eSDavid du Colombier void
trapinit(void)2164de34a7eSDavid du Colombier trapinit(void)
2174de34a7eSDavid du Colombier {
2187dd7cddfSDavid du Colombier /*
2197dd7cddfSDavid du Colombier * Special traps.
2207dd7cddfSDavid du Colombier * Syscall() is called directly without going through trap().
2217dd7cddfSDavid du Colombier */
2227dd7cddfSDavid du Colombier trapenable(VectorBPT, debugbpt, 0, "debugpt");
2237dd7cddfSDavid du Colombier trapenable(VectorPF, fault386, 0, "fault386");
224e288d156SDavid du Colombier trapenable(Vector2F, doublefault, 0, "doublefault");
225fe853e23SDavid du Colombier trapenable(Vector15, unexpected, 0, "unexpected");
2267dd7cddfSDavid du Colombier nmienable();
22780ee5cbfSDavid du Colombier
22880ee5cbfSDavid du Colombier addarchfile("irqalloc", 0444, irqallocread, nil);
2294de34a7eSDavid du Colombier trapinited = 1;
2307dd7cddfSDavid du Colombier }
2317dd7cddfSDavid du Colombier
2327dd7cddfSDavid du Colombier static char* excname[32] = {
2337dd7cddfSDavid du Colombier "divide error",
2347dd7cddfSDavid du Colombier "debug exception",
2357dd7cddfSDavid du Colombier "nonmaskable interrupt",
2367dd7cddfSDavid du Colombier "breakpoint",
2377dd7cddfSDavid du Colombier "overflow",
2387dd7cddfSDavid du Colombier "bounds check",
2397dd7cddfSDavid du Colombier "invalid opcode",
2407dd7cddfSDavid du Colombier "coprocessor not available",
2417dd7cddfSDavid du Colombier "double fault",
2427dd7cddfSDavid du Colombier "coprocessor segment overrun",
2437dd7cddfSDavid du Colombier "invalid TSS",
2447dd7cddfSDavid du Colombier "segment not present",
2457dd7cddfSDavid du Colombier "stack exception",
2467dd7cddfSDavid du Colombier "general protection violation",
2477dd7cddfSDavid du Colombier "page fault",
2487dd7cddfSDavid du Colombier "15 (reserved)",
2497dd7cddfSDavid du Colombier "coprocessor error",
2507dd7cddfSDavid du Colombier "alignment check",
2517dd7cddfSDavid du Colombier "machine check",
2527dd7cddfSDavid du Colombier "19 (reserved)",
2537dd7cddfSDavid du Colombier "20 (reserved)",
2547dd7cddfSDavid du Colombier "21 (reserved)",
2557dd7cddfSDavid du Colombier "22 (reserved)",
2567dd7cddfSDavid du Colombier "23 (reserved)",
2577dd7cddfSDavid du Colombier "24 (reserved)",
2587dd7cddfSDavid du Colombier "25 (reserved)",
2597dd7cddfSDavid du Colombier "26 (reserved)",
2607dd7cddfSDavid du Colombier "27 (reserved)",
2617dd7cddfSDavid du Colombier "28 (reserved)",
2627dd7cddfSDavid du Colombier "29 (reserved)",
2637dd7cddfSDavid du Colombier "30 (reserved)",
2647dd7cddfSDavid du Colombier "31 (reserved)",
2653e12c5d1SDavid du Colombier };
2663e12c5d1SDavid du Colombier
2673e12c5d1SDavid du Colombier /*
2683ff48bf5SDavid du Colombier * keep histogram of interrupt service times
2693ff48bf5SDavid du Colombier */
2703ff48bf5SDavid du Colombier void
intrtime(Mach *,int vno)2713ff48bf5SDavid du Colombier intrtime(Mach*, int vno)
2723ff48bf5SDavid du Colombier {
2733ff48bf5SDavid du Colombier ulong diff;
274e288d156SDavid du Colombier ulong x;
2753ff48bf5SDavid du Colombier
276e288d156SDavid du Colombier x = perfticks();
2773ff48bf5SDavid du Colombier diff = x - m->perf.intrts;
2783ff48bf5SDavid du Colombier m->perf.intrts = x;
2793ff48bf5SDavid du Colombier
2803ff48bf5SDavid du Colombier m->perf.inintr += diff;
2813ff48bf5SDavid du Colombier if(up == nil && m->perf.inidle > diff)
2823ff48bf5SDavid du Colombier m->perf.inidle -= diff;
2833ff48bf5SDavid du Colombier
28441dd6b47SDavid du Colombier diff /= m->cpumhz*100; /* quantum = 100µsec */
285e288d156SDavid du Colombier if(diff >= Ntimevec)
2863ff48bf5SDavid du Colombier diff = Ntimevec-1;
2873ff48bf5SDavid du Colombier intrtimes[vno][diff]++;
2883ff48bf5SDavid du Colombier }
2893ff48bf5SDavid du Colombier
290e288d156SDavid du Colombier /* go to user space */
291e288d156SDavid du Colombier void
kexit(Ureg *)292e288d156SDavid du Colombier kexit(Ureg*)
293e288d156SDavid du Colombier {
294e288d156SDavid du Colombier uvlong t;
295e288d156SDavid du Colombier Tos *tos;
296e288d156SDavid du Colombier
297e288d156SDavid du Colombier /* precise time accounting, kernel exit */
298e288d156SDavid du Colombier tos = (Tos*)(USTKTOP-sizeof(Tos));
299e288d156SDavid du Colombier cycles(&t);
300e288d156SDavid du Colombier tos->kcycles += t - up->kentry;
301e288d156SDavid du Colombier tos->pcycles = up->pcycles;
302e288d156SDavid du Colombier tos->pid = up->pid;
303e288d156SDavid du Colombier }
304e288d156SDavid du Colombier
3053ff48bf5SDavid du Colombier /*
3067dd7cddfSDavid du Colombier * All traps come here. It is slower to have all traps call trap()
3077dd7cddfSDavid du Colombier * rather than directly vectoring the handler. However, this avoids a
3087dd7cddfSDavid du Colombier * lot of code duplication and possible bugs. The only exception is
3097dd7cddfSDavid du Colombier * VectorSYSCALL.
3107dd7cddfSDavid du Colombier * Trap is called with interrupts disabled via interrupt-gates.
3113e12c5d1SDavid du Colombier */
3123e12c5d1SDavid du Colombier void
trap(Ureg * ureg)3137dd7cddfSDavid du Colombier trap(Ureg* ureg)
3143e12c5d1SDavid du Colombier {
3152009dc88SDavid du Colombier int clockintr, i, vno, user;
3169a747e4fSDavid du Colombier char buf[ERRMAX];
3177dd7cddfSDavid du Colombier Vctl *ctl, *v;
3187dd7cddfSDavid du Colombier Mach *mach;
3193e12c5d1SDavid du Colombier
3204de34a7eSDavid du Colombier if(!trapinited){
3214de34a7eSDavid du Colombier /* fault386 can give a better error message */
3224de34a7eSDavid du Colombier if(ureg->trap == VectorPF)
3234de34a7eSDavid du Colombier fault386(ureg, nil);
3244de34a7eSDavid du Colombier panic("trap %lud: not ready", ureg->trap);
3254de34a7eSDavid du Colombier }
3264de34a7eSDavid du Colombier
3273ff48bf5SDavid du Colombier m->perf.intrts = perfticks();
328e288d156SDavid du Colombier user = (ureg->cs & 0xFFFF) == UESEL;
329e288d156SDavid du Colombier if(user){
3307dd7cddfSDavid du Colombier up->dbgreg = ureg;
331e288d156SDavid du Colombier cycles(&up->kentry);
332219b2ee8SDavid du Colombier }
3337dd7cddfSDavid du Colombier
3343cf081f0SDavid du Colombier clockintr = 0;
3353cf081f0SDavid du Colombier
3367dd7cddfSDavid du Colombier vno = ureg->trap;
3377dd7cddfSDavid du Colombier if(ctl = vctl[vno]){
3387dd7cddfSDavid du Colombier if(ctl->isintr){
3397dd7cddfSDavid du Colombier m->intr++;
3407dd7cddfSDavid du Colombier if(vno >= VectorPIC && vno != VectorSYSCALL)
3417dd7cddfSDavid du Colombier m->lastintr = ctl->irq;
3427dd7cddfSDavid du Colombier }
3437dd7cddfSDavid du Colombier
3447dd7cddfSDavid du Colombier if(ctl->isr)
3457dd7cddfSDavid du Colombier ctl->isr(vno);
3467dd7cddfSDavid du Colombier for(v = ctl; v != nil; v = v->next){
3470701b922SDavid du Colombier if(v->f)
3487dd7cddfSDavid du Colombier v->f(ureg, v->a);
3497dd7cddfSDavid du Colombier }
3507dd7cddfSDavid du Colombier if(ctl->eoi)
3517dd7cddfSDavid du Colombier ctl->eoi(vno);
3523e12c5d1SDavid du Colombier
353a6a9e072SDavid du Colombier if(ctl->isintr){
3543ff48bf5SDavid du Colombier intrtime(m, vno);
355179dd269SDavid du Colombier
3562009dc88SDavid du Colombier if(ctl->irq == IrqCLOCK || ctl->irq == IrqTIMER)
3572009dc88SDavid du Colombier clockintr = 1;
3582009dc88SDavid du Colombier
3592009dc88SDavid du Colombier if(up && !clockintr)
360a6a9e072SDavid du Colombier preempted();
3613e12c5d1SDavid du Colombier }
3623e12c5d1SDavid du Colombier }
3632615514eSDavid du Colombier else if(vno < nelem(excname) && user){
3647dd7cddfSDavid du Colombier spllo();
3654e3613abSDavid du Colombier snprint(buf, sizeof buf, "sys: trap: %s", excname[vno]);
3667dd7cddfSDavid du Colombier postnote(up, 1, buf, NDebug);
3677dd7cddfSDavid du Colombier }
3687dd7cddfSDavid du Colombier else if(vno >= VectorPIC && vno != VectorSYSCALL){
369219b2ee8SDavid du Colombier /*
3707dd7cddfSDavid du Colombier * An unknown interrupt.
371219b2ee8SDavid du Colombier * Check for a default IRQ7. This can happen when
372219b2ee8SDavid du Colombier * the IRQ input goes away before the acknowledge.
373219b2ee8SDavid du Colombier * In this case, a 'default IRQ7' is generated, but
374219b2ee8SDavid du Colombier * the corresponding bit in the ISR isn't set.
375219b2ee8SDavid du Colombier * In fact, just ignore all such interrupts.
376219b2ee8SDavid du Colombier */
3779a747e4fSDavid du Colombier
3789a747e4fSDavid du Colombier /* call all interrupt routines, just in case */
3799a747e4fSDavid du Colombier for(i = VectorPIC; i <= MaxIrqLAPIC; i++){
3809a747e4fSDavid du Colombier ctl = vctl[i];
3819a747e4fSDavid du Colombier if(ctl == nil)
3829a747e4fSDavid du Colombier continue;
3839a747e4fSDavid du Colombier if(!ctl->isintr)
3849a747e4fSDavid du Colombier continue;
3859a747e4fSDavid du Colombier for(v = ctl; v != nil; v = v->next){
3869a747e4fSDavid du Colombier if(v->f)
3879a747e4fSDavid du Colombier v->f(ureg, v->a);
3889a747e4fSDavid du Colombier }
3899a747e4fSDavid du Colombier /* should we do this? */
3909a747e4fSDavid du Colombier if(ctl->eoi)
3919a747e4fSDavid du Colombier ctl->eoi(i);
3929a747e4fSDavid du Colombier }
3939a747e4fSDavid du Colombier
3949a747e4fSDavid du Colombier /* clear the interrupt */
3959a747e4fSDavid du Colombier i8259isr(vno);
3969a747e4fSDavid du Colombier
397da51d93aSDavid du Colombier if(0)print("cpu%d: spurious interrupt %d, last %d\n",
3987dd7cddfSDavid du Colombier m->machno, vno, m->lastintr);
399da51d93aSDavid du Colombier if(0)if(conf.nmach > 1){
4009a747e4fSDavid du Colombier for(i = 0; i < 32; i++){
4017dd7cddfSDavid du Colombier if(!(active.machs & (1<<i)))
4027dd7cddfSDavid du Colombier continue;
4037dd7cddfSDavid du Colombier mach = MACHP(i);
4047dd7cddfSDavid du Colombier if(m->machno == mach->machno)
4057dd7cddfSDavid du Colombier continue;
406da51d93aSDavid du Colombier print(" cpu%d: last %d",
407da51d93aSDavid du Colombier mach->machno, mach->lastintr);
408219b2ee8SDavid du Colombier }
4097dd7cddfSDavid du Colombier print("\n");
410e288d156SDavid du Colombier }
411da51d93aSDavid du Colombier m->spuriousintr++;
412da51d93aSDavid du Colombier if(user)
413da51d93aSDavid du Colombier kexit(ureg);
4143e12c5d1SDavid du Colombier return;
4153e12c5d1SDavid du Colombier }
4167dd7cddfSDavid du Colombier else{
4177dd7cddfSDavid du Colombier if(vno == VectorNMI){
418208510e1SDavid du Colombier /*
419208510e1SDavid du Colombier * Don't re-enable, it confuses the crash dumps.
4207dd7cddfSDavid du Colombier nmienable();
421208510e1SDavid du Colombier */
4229a3e0102SDavid du Colombier iprint("cpu%d: NMI PC %#8.8lux\n", m->machno, ureg->pc);
423208510e1SDavid du Colombier while(m->machno != 0)
424208510e1SDavid du Colombier ;
4257dd7cddfSDavid du Colombier }
4267dd7cddfSDavid du Colombier dumpregs(ureg);
427fe853e23SDavid du Colombier if(!user){
428fe853e23SDavid du Colombier ureg->sp = (ulong)&ureg->sp;
429fe853e23SDavid du Colombier _dumpstack(ureg);
430fe853e23SDavid du Colombier }
4317dd7cddfSDavid du Colombier if(vno < nelem(excname))
4327dd7cddfSDavid du Colombier panic("%s", excname[vno]);
433c9b6d007SDavid du Colombier panic("unknown trap/intr: %d", vno);
4347dd7cddfSDavid du Colombier }
435da51d93aSDavid du Colombier splhi();
436da51d93aSDavid du Colombier
437da51d93aSDavid du Colombier /* delaysched set because we held a lock or because our quantum ended */
4382009dc88SDavid du Colombier if(up && up->delaysched && clockintr){
439da51d93aSDavid du Colombier sched();
440da51d93aSDavid du Colombier splhi();
441da51d93aSDavid du Colombier }
4423e12c5d1SDavid du Colombier
443e288d156SDavid du Colombier if(user){
444da51d93aSDavid du Colombier if(up->procctl || up->nnote)
4457dd7cddfSDavid du Colombier notify(ureg);
446e288d156SDavid du Colombier kexit(ureg);
447e288d156SDavid du Colombier }
4483e12c5d1SDavid du Colombier }
4493e12c5d1SDavid du Colombier
4503e12c5d1SDavid du Colombier /*
4513e12c5d1SDavid du Colombier * dump registers
4523e12c5d1SDavid du Colombier */
4533e12c5d1SDavid du Colombier void
dumpregs2(Ureg * ureg)4547dd7cddfSDavid du Colombier dumpregs2(Ureg* ureg)
4553e12c5d1SDavid du Colombier {
4567dd7cddfSDavid du Colombier if(up)
457208510e1SDavid du Colombier iprint("cpu%d: registers for %s %lud\n",
4587dd7cddfSDavid du Colombier m->machno, up->text, up->pid);
4593e12c5d1SDavid du Colombier else
460208510e1SDavid du Colombier iprint("cpu%d: registers for kernel\n", m->machno);
461208510e1SDavid du Colombier iprint("FLAGS=%luX TRAP=%luX ECODE=%luX PC=%luX",
4627dd7cddfSDavid du Colombier ureg->flags, ureg->trap, ureg->ecode, ureg->pc);
463208510e1SDavid du Colombier iprint(" SS=%4.4luX USP=%luX\n", ureg->ss & 0xFFFF, ureg->usp);
464208510e1SDavid du Colombier iprint(" AX %8.8luX BX %8.8luX CX %8.8luX DX %8.8luX\n",
4657dd7cddfSDavid du Colombier ureg->ax, ureg->bx, ureg->cx, ureg->dx);
466208510e1SDavid du Colombier iprint(" SI %8.8luX DI %8.8luX BP %8.8luX\n",
4677dd7cddfSDavid du Colombier ureg->si, ureg->di, ureg->bp);
468208510e1SDavid du Colombier iprint(" CS %4.4luX DS %4.4luX ES %4.4luX FS %4.4luX GS %4.4luX\n",
4697dd7cddfSDavid du Colombier ureg->cs & 0xFFFF, ureg->ds & 0xFFFF, ureg->es & 0xFFFF,
4707dd7cddfSDavid du Colombier ureg->fs & 0xFFFF, ureg->gs & 0xFFFF);
471219b2ee8SDavid du Colombier }
472219b2ee8SDavid du Colombier
473219b2ee8SDavid du Colombier void
dumpregs(Ureg * ureg)4747dd7cddfSDavid du Colombier dumpregs(Ureg* ureg)
475219b2ee8SDavid du Colombier {
4767dd7cddfSDavid du Colombier vlong mca, mct;
4777dd7cddfSDavid du Colombier
4787dd7cddfSDavid du Colombier dumpregs2(ureg);
4797dd7cddfSDavid du Colombier
4807dd7cddfSDavid du Colombier /*
4817dd7cddfSDavid du Colombier * Processor control registers.
4827dd7cddfSDavid du Colombier * If machine check exception, time stamp counter, page size extensions
4837dd7cddfSDavid du Colombier * or enhanced virtual 8086 mode extensions are supported, there is a
4847dd7cddfSDavid du Colombier * CR4. If there is a CR4 and machine check extensions, read the machine
4857dd7cddfSDavid du Colombier * check address and machine check type registers if RDMSR supported.
4867dd7cddfSDavid du Colombier */
487208510e1SDavid du Colombier iprint(" CR0 %8.8lux CR2 %8.8lux CR3 %8.8lux",
4887dd7cddfSDavid du Colombier getcr0(), getcr2(), getcr3());
48961fd6f66SDavid du Colombier if(m->cpuiddx & (Mce|Tsc|Pse|Vmex)){
490208510e1SDavid du Colombier iprint(" CR4 %8.8lux", getcr4());
49161fd6f66SDavid du Colombier if((m->cpuiddx & (Mce|Cpumsr)) == (Mce|Cpumsr)){
4927dd7cddfSDavid du Colombier rdmsr(0x00, &mca);
4937dd7cddfSDavid du Colombier rdmsr(0x01, &mct);
494208510e1SDavid du Colombier iprint("\n MCA %8.8llux MCT %8.8llux", mca, mct);
4957dd7cddfSDavid du Colombier }
4967dd7cddfSDavid du Colombier }
497567483c8SDavid du Colombier iprint("\n ur %#p up %#p\n", ureg, up);
4983e12c5d1SDavid du Colombier }
4993e12c5d1SDavid du Colombier
5007dd7cddfSDavid du Colombier
5017dd7cddfSDavid du Colombier /*
5027dd7cddfSDavid du Colombier * Fill in enough of Ureg to get a stack trace, and call a function.
5037dd7cddfSDavid du Colombier * Used by debugging interface rdb.
5047dd7cddfSDavid du Colombier */
5053e12c5d1SDavid du Colombier void
callwithureg(void (* fn)(Ureg *))5067dd7cddfSDavid du Colombier callwithureg(void (*fn)(Ureg*))
5077dd7cddfSDavid du Colombier {
5087dd7cddfSDavid du Colombier Ureg ureg;
5097dd7cddfSDavid du Colombier ureg.pc = getcallerpc(&fn);
5107dd7cddfSDavid du Colombier ureg.sp = (ulong)&fn;
5117dd7cddfSDavid du Colombier fn(&ureg);
5127dd7cddfSDavid du Colombier }
5137dd7cddfSDavid du Colombier
5147dd7cddfSDavid du Colombier static void
_dumpstack(Ureg * ureg)5157dd7cddfSDavid du Colombier _dumpstack(Ureg *ureg)
5163e12c5d1SDavid du Colombier {
517208510e1SDavid du Colombier uintptr l, v, i, estack;
5183e12c5d1SDavid du Colombier extern ulong etext;
519fe853e23SDavid du Colombier int x;
520edc15dd6SDavid du Colombier char *s;
5213e12c5d1SDavid du Colombier
522edc15dd6SDavid du Colombier if((s = getconf("*nodumpstack")) != nil && strcmp(s, "0") != 0){
52382cf11d1SDavid du Colombier iprint("dumpstack disabled\n");
52482cf11d1SDavid du Colombier return;
52582cf11d1SDavid du Colombier }
526fe853e23SDavid du Colombier iprint("dumpstack\n");
52782cf11d1SDavid du Colombier
528fe853e23SDavid du Colombier x = 0;
529208510e1SDavid du Colombier x += iprint("ktrace /kernel/path %.8lux %.8lux <<EOF\n", ureg->pc, ureg->sp);
5303e12c5d1SDavid du Colombier i = 0;
5319a747e4fSDavid du Colombier if(up
532208510e1SDavid du Colombier && (uintptr)&l >= (uintptr)up->kstack
533208510e1SDavid du Colombier && (uintptr)&l <= (uintptr)up->kstack+KSTACK)
534208510e1SDavid du Colombier estack = (uintptr)up->kstack+KSTACK;
535208510e1SDavid du Colombier else if((uintptr)&l >= (uintptr)m->stack
536208510e1SDavid du Colombier && (uintptr)&l <= (uintptr)m+MACHSIZE)
537208510e1SDavid du Colombier estack = (uintptr)m+MACHSIZE;
5389a747e4fSDavid du Colombier else
5399a747e4fSDavid du Colombier return;
540208510e1SDavid du Colombier x += iprint("estackx %p\n", estack);
5419a747e4fSDavid du Colombier
542208510e1SDavid du Colombier for(l = (uintptr)&l; l < estack; l += sizeof(uintptr)){
543208510e1SDavid du Colombier v = *(uintptr*)l;
544208510e1SDavid du Colombier if((KTZERO < v && v < (uintptr)&etext) || estack-l < 32){
5457dd7cddfSDavid du Colombier /*
546208510e1SDavid du Colombier * Could Pick off general CALL (((uchar*)v)[-5] == 0xE8)
547208510e1SDavid du Colombier * and CALL indirect through AX
548208510e1SDavid du Colombier * (((uchar*)v)[-2] == 0xFF && ((uchar*)v)[-2] == 0xD0),
5499a747e4fSDavid du Colombier * but this is too clever and misses faulting address.
5507dd7cddfSDavid du Colombier */
551208510e1SDavid du Colombier x += iprint("%.8p=%.8p ", l, v);
5523e12c5d1SDavid du Colombier i++;
5533e12c5d1SDavid du Colombier }
5543e12c5d1SDavid du Colombier if(i == 4){
5553e12c5d1SDavid du Colombier i = 0;
556208510e1SDavid du Colombier x += iprint("\n");
5573e12c5d1SDavid du Colombier }
5583e12c5d1SDavid du Colombier }
5597dd7cddfSDavid du Colombier if(i)
560208510e1SDavid du Colombier iprint("\n");
561208510e1SDavid du Colombier iprint("EOF\n");
562208510e1SDavid du Colombier
563208510e1SDavid du Colombier if(ureg->trap != VectorNMI)
564208510e1SDavid du Colombier return;
565208510e1SDavid du Colombier
566208510e1SDavid du Colombier i = 0;
567208510e1SDavid du Colombier for(l = (uintptr)&l; l < estack; l += sizeof(uintptr)){
568208510e1SDavid du Colombier iprint("%.8p ", *(uintptr*)l);
569208510e1SDavid du Colombier if(++i == 8){
570208510e1SDavid du Colombier i = 0;
571208510e1SDavid du Colombier iprint("\n");
572208510e1SDavid du Colombier }
573208510e1SDavid du Colombier }
574208510e1SDavid du Colombier if(i)
575208510e1SDavid du Colombier iprint("\n");
5763e12c5d1SDavid du Colombier }
5773e12c5d1SDavid du Colombier
5787dd7cddfSDavid du Colombier void
dumpstack(void)5797dd7cddfSDavid du Colombier dumpstack(void)
5803e12c5d1SDavid du Colombier {
5817dd7cddfSDavid du Colombier callwithureg(_dumpstack);
5823e12c5d1SDavid du Colombier }
5833e12c5d1SDavid du Colombier
5847dd7cddfSDavid du Colombier static void
debugbpt(Ureg * ureg,void *)5857dd7cddfSDavid du Colombier debugbpt(Ureg* ureg, void*)
5863e12c5d1SDavid du Colombier {
5879a747e4fSDavid du Colombier char buf[ERRMAX];
5887dd7cddfSDavid du Colombier
5897dd7cddfSDavid du Colombier if(up == 0)
5907dd7cddfSDavid du Colombier panic("kernel bpt");
5917dd7cddfSDavid du Colombier /* restore pc to instruction that caused the trap */
5927dd7cddfSDavid du Colombier ureg->pc--;
5934e3613abSDavid du Colombier snprint(buf, sizeof buf, "sys: breakpoint");
5947dd7cddfSDavid du Colombier postnote(up, 1, buf, NDebug);
5957dd7cddfSDavid du Colombier }
5967dd7cddfSDavid du Colombier
5977dd7cddfSDavid du Colombier static void
doublefault(Ureg *,void *)598e288d156SDavid du Colombier doublefault(Ureg*, void*)
599e288d156SDavid du Colombier {
600e288d156SDavid du Colombier panic("double fault");
601e288d156SDavid du Colombier }
602e288d156SDavid du Colombier
603fe853e23SDavid du Colombier static void
unexpected(Ureg * ureg,void *)604fe853e23SDavid du Colombier unexpected(Ureg* ureg, void*)
605fe853e23SDavid du Colombier {
606fe853e23SDavid du Colombier print("unexpected trap %lud; ignoring\n", ureg->trap);
607fe853e23SDavid du Colombier }
608e288d156SDavid du Colombier
609e862f8a5SDavid du Colombier extern void checkpages(void);
610be704722SDavid du Colombier extern void checkfault(ulong, ulong);
611e288d156SDavid du Colombier static void
fault386(Ureg * ureg,void *)6127dd7cddfSDavid du Colombier fault386(Ureg* ureg, void*)
6137dd7cddfSDavid du Colombier {
6147dd7cddfSDavid du Colombier ulong addr;
6157dd7cddfSDavid du Colombier int read, user, n, insyscall;
6169a747e4fSDavid du Colombier char buf[ERRMAX];
6177dd7cddfSDavid du Colombier
6187dd7cddfSDavid du Colombier addr = getcr2();
6197dd7cddfSDavid du Colombier read = !(ureg->ecode & 2);
6204de34a7eSDavid du Colombier
6214de34a7eSDavid du Colombier user = (ureg->cs & 0xFFFF) == UESEL;
6224de34a7eSDavid du Colombier if(!user){
6234de34a7eSDavid du Colombier if(vmapsync(addr))
6244de34a7eSDavid du Colombier return;
6254de34a7eSDavid du Colombier if(addr >= USTKTOP)
6264de34a7eSDavid du Colombier panic("kernel fault: bad address pc=0x%.8lux addr=0x%.8lux", ureg->pc, addr);
6279a747e4fSDavid du Colombier if(up == nil)
6284de34a7eSDavid du Colombier panic("kernel fault: no user process pc=0x%.8lux addr=0x%.8lux", ureg->pc, addr);
6294de34a7eSDavid du Colombier }
6304de34a7eSDavid du Colombier if(up == nil)
6314de34a7eSDavid du Colombier panic("user fault: up=0 pc=0x%.8lux addr=0x%.8lux", ureg->pc, addr);
6324de34a7eSDavid du Colombier
6337dd7cddfSDavid du Colombier insyscall = up->insyscall;
6347dd7cddfSDavid du Colombier up->insyscall = 1;
6357dd7cddfSDavid du Colombier n = fault(addr, read);
6367dd7cddfSDavid du Colombier if(n < 0){
6377dd7cddfSDavid du Colombier if(!user){
6387dd7cddfSDavid du Colombier dumpregs(ureg);
639c9b6d007SDavid du Colombier panic("fault: 0x%lux", addr);
6407dd7cddfSDavid du Colombier }
641d717568cSDavid du Colombier checkpages();
642be704722SDavid du Colombier checkfault(addr, ureg->pc);
6434e3613abSDavid du Colombier snprint(buf, sizeof buf, "sys: trap: fault %s addr=0x%lux",
6447dd7cddfSDavid du Colombier read ? "read" : "write", addr);
6457dd7cddfSDavid du Colombier postnote(up, 1, buf, NDebug);
6467dd7cddfSDavid du Colombier }
6477dd7cddfSDavid du Colombier up->insyscall = insyscall;
6483e12c5d1SDavid du Colombier }
6493e12c5d1SDavid du Colombier
6503e12c5d1SDavid du Colombier /*
6513e12c5d1SDavid du Colombier * system calls
6523e12c5d1SDavid du Colombier */
6533e12c5d1SDavid du Colombier #include "../port/systab.h"
6543e12c5d1SDavid du Colombier
6553e12c5d1SDavid du Colombier /*
6567dd7cddfSDavid du Colombier * Syscall is called directly from assembler without going through trap().
6573e12c5d1SDavid du Colombier */
6587dd7cddfSDavid du Colombier void
syscall(Ureg * ureg)6597dd7cddfSDavid du Colombier syscall(Ureg* ureg)
6603e12c5d1SDavid du Colombier {
6619a747e4fSDavid du Colombier char *e;
6623e12c5d1SDavid du Colombier ulong sp;
6633e12c5d1SDavid du Colombier long ret;
664e288d156SDavid du Colombier int i, s;
6659a747e4fSDavid du Colombier ulong scallnr;
666fcbb35d1SDavid du Colombier vlong startns, stopns;
6673e12c5d1SDavid du Colombier
6687dd7cddfSDavid du Colombier if((ureg->cs & 0xFFFF) != UESEL)
669c9b6d007SDavid du Colombier panic("syscall: cs 0x%4.4luX", 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
678fcbb35d1SDavid du Colombier sp = ureg->usp;
679fcbb35d1SDavid du Colombier scallnr = ureg->ax;
680fcbb35d1SDavid du Colombier up->scallnr = scallnr;
681fcbb35d1SDavid du Colombier
682e288d156SDavid du Colombier if(up->procctl == Proc_tracesyscall){
683fcbb35d1SDavid du Colombier /*
684fcbb35d1SDavid du Colombier * Redundant validaddr. Do we care?
685fcbb35d1SDavid du Colombier * Tracing syscalls is not exactly a fast path...
686fcbb35d1SDavid du Colombier * Beware, validaddr currently does a pexit rather
687fcbb35d1SDavid du Colombier * than an error if there's a problem; that might
688fcbb35d1SDavid du Colombier * change in the future.
689fcbb35d1SDavid du Colombier */
690fcbb35d1SDavid du Colombier if(sp < (USTKTOP-BY2PG) || sp > (USTKTOP-sizeof(Sargs)-BY2WD))
691fcbb35d1SDavid du Colombier validaddr(sp, sizeof(Sargs)+BY2WD, 0);
692fcbb35d1SDavid du Colombier
693fcbb35d1SDavid du Colombier syscallfmt(scallnr, ureg->pc, (va_list)(sp+BY2WD));
694e288d156SDavid du Colombier up->procctl = Proc_stopme;
695e288d156SDavid du Colombier procctl(up);
696d1be6b08SDavid du Colombier if(up->syscalltrace)
697d1be6b08SDavid du Colombier free(up->syscalltrace);
698d1be6b08SDavid du Colombier up->syscalltrace = nil;
699fcbb35d1SDavid du Colombier startns = todget(nil);
700e288d156SDavid du Colombier }
701e288d156SDavid du Colombier
7027dd7cddfSDavid du Colombier if(scallnr == RFORK && up->fpstate == FPactive){
7037dd7cddfSDavid du Colombier fpsave(&up->fpsave);
7047dd7cddfSDavid du Colombier up->fpstate = FPinactive;
7053e12c5d1SDavid du Colombier }
7063e12c5d1SDavid du Colombier spllo();
7077dd7cddfSDavid du Colombier
7087dd7cddfSDavid du Colombier up->nerrlab = 0;
7093e12c5d1SDavid du Colombier ret = -1;
7103e12c5d1SDavid du Colombier if(!waserror()){
7119a747e4fSDavid du Colombier if(scallnr >= nsyscall || systab[scallnr] == 0){
712e464ed1aSDavid du Colombier pprint("bad sys call number %lud pc %lux\n",
7137dd7cddfSDavid du Colombier scallnr, ureg->pc);
7147dd7cddfSDavid du Colombier postnote(up, 1, "sys: bad sys call", NDebug);
7153e12c5d1SDavid du Colombier error(Ebadarg);
7163e12c5d1SDavid du Colombier }
7173e12c5d1SDavid du Colombier
7187dd7cddfSDavid du Colombier if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)-BY2WD))
7197dd7cddfSDavid du Colombier validaddr(sp, sizeof(Sargs)+BY2WD, 0);
7203e12c5d1SDavid du Colombier
7217dd7cddfSDavid du Colombier up->s = *((Sargs*)(sp+BY2WD));
7227dd7cddfSDavid du Colombier up->psstate = sysctab[scallnr];
7233e12c5d1SDavid du Colombier
7247dd7cddfSDavid du Colombier ret = systab[scallnr](up->s.args);
7253e12c5d1SDavid du Colombier poperror();
7269a747e4fSDavid du Colombier }else{
7279a747e4fSDavid du Colombier /* failure: save the error buffer for errstr */
7289a747e4fSDavid du Colombier e = up->syserrstr;
7299a747e4fSDavid du Colombier up->syserrstr = up->errstr;
7309a747e4fSDavid du Colombier up->errstr = e;
73103172982SDavid du Colombier if(0 && up->pid == 1)
73203172982SDavid du Colombier print("syscall %lud error %s\n", scallnr, up->syserrstr);
7333e12c5d1SDavid du Colombier }
7347dd7cddfSDavid du Colombier if(up->nerrlab){
735e288d156SDavid du Colombier print("bad errstack [%lud]: %d extra\n", scallnr, up->nerrlab);
7363e12c5d1SDavid du Colombier for(i = 0; i < NERR; i++)
7377dd7cddfSDavid du Colombier print("sp=%lux pc=%lux\n",
7387dd7cddfSDavid du Colombier up->errlab[i].sp, up->errlab[i].pc);
7393e12c5d1SDavid du Colombier panic("error stack");
7403e12c5d1SDavid du Colombier }
7413e12c5d1SDavid du Colombier
7423e12c5d1SDavid du Colombier /*
7437dd7cddfSDavid du Colombier * Put return value in frame. On the x86 the syscall is
7443e12c5d1SDavid du Colombier * just another trap and the return value from syscall is
7453e12c5d1SDavid du Colombier * ignored. On other machines the return value is put into
7463e12c5d1SDavid du Colombier * the results register by caller of syscall.
7473e12c5d1SDavid du Colombier */
7487dd7cddfSDavid du Colombier ureg->ax = ret;
7493e12c5d1SDavid du Colombier
750e288d156SDavid du Colombier if(up->procctl == Proc_tracesyscall){
751fcbb35d1SDavid du Colombier stopns = todget(nil);
752e288d156SDavid du Colombier up->procctl = Proc_stopme;
753fcbb35d1SDavid du Colombier sysretfmt(scallnr, (va_list)(sp+BY2WD), ret, startns, stopns);
754e288d156SDavid du Colombier s = splhi();
755e288d156SDavid du Colombier procctl(up);
756e288d156SDavid du Colombier splx(s);
757d1be6b08SDavid du Colombier if(up->syscalltrace)
758d1be6b08SDavid du Colombier free(up->syscalltrace);
759d1be6b08SDavid du Colombier up->syscalltrace = nil;
760e288d156SDavid du Colombier }
761e288d156SDavid du Colombier
762e288d156SDavid du Colombier up->insyscall = 0;
763e288d156SDavid du Colombier up->psstate = 0;
764e288d156SDavid du Colombier
7657dd7cddfSDavid du Colombier if(scallnr == NOTED)
7667dd7cddfSDavid du Colombier noted(ureg, *(ulong*)(sp+BY2WD));
7673e12c5d1SDavid du Colombier
7687dd7cddfSDavid du Colombier if(scallnr!=RFORK && (up->procctl || up->nnote)){
7697dd7cddfSDavid du Colombier splhi();
7707dd7cddfSDavid du Colombier notify(ureg);
7717dd7cddfSDavid du Colombier }
772e288d156SDavid du Colombier /* if we delayed sched because we held a lock, sched now */
773e288d156SDavid du Colombier if(up->delaysched)
774e288d156SDavid du Colombier sched();
775e288d156SDavid du Colombier kexit(ureg);
7763e12c5d1SDavid du Colombier }
7773e12c5d1SDavid du Colombier
7783e12c5d1SDavid du Colombier /*
7793e12c5d1SDavid du Colombier * Call user, if necessary, with note.
7803e12c5d1SDavid du Colombier * Pass user the Ureg struct and the note on his stack.
7813e12c5d1SDavid du Colombier */
7823e12c5d1SDavid du Colombier int
notify(Ureg * ureg)7837dd7cddfSDavid du Colombier notify(Ureg* ureg)
7843e12c5d1SDavid du Colombier {
785219b2ee8SDavid du Colombier int l;
7863e12c5d1SDavid du Colombier ulong s, sp;
7873e12c5d1SDavid du Colombier Note *n;
7883e12c5d1SDavid du Colombier
7897dd7cddfSDavid du Colombier if(up->procctl)
7907dd7cddfSDavid du Colombier procctl(up);
7917dd7cddfSDavid du Colombier if(up->nnote == 0)
7923e12c5d1SDavid du Colombier return 0;
7933e12c5d1SDavid du Colombier
7943ff48bf5SDavid du Colombier if(up->fpstate == FPactive){
7953ff48bf5SDavid du Colombier fpsave(&up->fpsave);
7963ff48bf5SDavid du Colombier up->fpstate = FPinactive;
7973ff48bf5SDavid du Colombier }
7983ff48bf5SDavid du Colombier up->fpstate |= FPillegal;
7993ff48bf5SDavid du Colombier
8003e12c5d1SDavid du Colombier s = spllo();
8017dd7cddfSDavid du Colombier qlock(&up->debug);
8027dd7cddfSDavid du Colombier up->notepending = 0;
8037dd7cddfSDavid du Colombier n = &up->note[0];
8043e12c5d1SDavid du Colombier if(strncmp(n->msg, "sys:", 4) == 0){
8053e12c5d1SDavid du Colombier l = strlen(n->msg);
8069a747e4fSDavid du Colombier if(l > ERRMAX-15) /* " pc=0x12345678\0" */
8079a747e4fSDavid du Colombier l = ERRMAX-15;
8084e3613abSDavid du Colombier seprint(n->msg+l, &n->msg[sizeof n->msg], " pc=0x%.8lux",
8094e3613abSDavid du Colombier ureg->pc);
8103e12c5d1SDavid du Colombier }
811219b2ee8SDavid du Colombier
8127dd7cddfSDavid du Colombier if(n->flag!=NUser && (up->notified || up->notify==0)){
8137dd7cddfSDavid du Colombier if(n->flag == NDebug)
8143e12c5d1SDavid du Colombier pprint("suicide: %s\n", n->msg);
8157dd7cddfSDavid du Colombier qunlock(&up->debug);
8163e12c5d1SDavid du Colombier pexit(n->msg, n->flag!=NDebug);
8173e12c5d1SDavid du Colombier }
818219b2ee8SDavid du Colombier
8197dd7cddfSDavid du Colombier if(up->notified){
8207dd7cddfSDavid du Colombier qunlock(&up->debug);
821219b2ee8SDavid du Colombier splhi();
822219b2ee8SDavid du Colombier return 0;
823219b2ee8SDavid du Colombier }
824219b2ee8SDavid du Colombier
8257dd7cddfSDavid du Colombier if(!up->notify){
8267dd7cddfSDavid du Colombier qunlock(&up->debug);
827bd389b36SDavid du Colombier pexit(n->msg, n->flag!=NDebug);
828bd389b36SDavid du Colombier }
8297dd7cddfSDavid du Colombier sp = ureg->usp;
830208510e1SDavid du Colombier sp -= 256; /* debugging: preserve context causing problem */
8313e12c5d1SDavid du Colombier sp -= sizeof(Ureg);
832208510e1SDavid du Colombier if(0) print("%s %lud: notify %.8lux %.8lux %.8lux %s\n",
833208510e1SDavid du Colombier up->text, up->pid, ureg->pc, ureg->usp, sp, n->msg);
834219b2ee8SDavid du Colombier
8357dd7cddfSDavid du Colombier if(!okaddr((ulong)up->notify, 1, 0)
8369a747e4fSDavid du Colombier || !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)){
8377dd7cddfSDavid du Colombier qunlock(&up->debug);
8382f205b96SDavid du Colombier pprint("suicide: bad address in notify\n");
8393e12c5d1SDavid du Colombier pexit("Suicide", 0);
8403e12c5d1SDavid du Colombier }
841219b2ee8SDavid du Colombier
8427dd7cddfSDavid du Colombier memmove((Ureg*)sp, ureg, sizeof(Ureg));
8437dd7cddfSDavid du Colombier *(Ureg**)(sp-BY2WD) = up->ureg; /* word under Ureg is old up->ureg */
8447dd7cddfSDavid du Colombier up->ureg = (void*)sp;
8459a747e4fSDavid du Colombier sp -= BY2WD+ERRMAX;
8469a747e4fSDavid du Colombier memmove((char*)sp, up->note[0].msg, ERRMAX);
8473e12c5d1SDavid du Colombier sp -= 3*BY2WD;
8483e12c5d1SDavid du Colombier *(ulong*)(sp+2*BY2WD) = sp+3*BY2WD; /* arg 2 is string */
8497dd7cddfSDavid du Colombier *(ulong*)(sp+1*BY2WD) = (ulong)up->ureg; /* arg 1 is ureg* */
8503e12c5d1SDavid du Colombier *(ulong*)(sp+0*BY2WD) = 0; /* arg 0 is pc */
8517dd7cddfSDavid du Colombier ureg->usp = sp;
8527dd7cddfSDavid du Colombier ureg->pc = (ulong)up->notify;
8537dd7cddfSDavid du Colombier up->notified = 1;
8547dd7cddfSDavid du Colombier up->nnote--;
8557dd7cddfSDavid du Colombier memmove(&up->lastnote, &up->note[0], sizeof(Note));
8567dd7cddfSDavid du Colombier memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));
857219b2ee8SDavid du Colombier
8587dd7cddfSDavid du Colombier qunlock(&up->debug);
8593e12c5d1SDavid du Colombier splx(s);
860219b2ee8SDavid du Colombier return 1;
8613e12c5d1SDavid du Colombier }
8623e12c5d1SDavid du Colombier
8633e12c5d1SDavid du Colombier /*
8643e12c5d1SDavid du Colombier * Return user to state before notify()
8653e12c5d1SDavid du Colombier */
8663e12c5d1SDavid du Colombier void
noted(Ureg * ureg,ulong arg0)8677dd7cddfSDavid du Colombier noted(Ureg* ureg, ulong arg0)
8683e12c5d1SDavid du Colombier {
8697dd7cddfSDavid du Colombier Ureg *nureg;
870219b2ee8SDavid du Colombier ulong oureg, sp;
8713e12c5d1SDavid du Colombier
8727dd7cddfSDavid du Colombier qlock(&up->debug);
8737dd7cddfSDavid du Colombier if(arg0!=NRSTR && !up->notified) {
8747dd7cddfSDavid du Colombier qunlock(&up->debug);
875219b2ee8SDavid du Colombier pprint("call to noted() when not notified\n");
8763e12c5d1SDavid du Colombier pexit("Suicide", 0);
8773e12c5d1SDavid du Colombier }
8787dd7cddfSDavid du Colombier up->notified = 0;
879219b2ee8SDavid du Colombier
8807dd7cddfSDavid du Colombier nureg = up->ureg; /* pointer to user returned Ureg struct */
881219b2ee8SDavid du Colombier
8823ff48bf5SDavid du Colombier up->fpstate &= ~FPillegal;
8833ff48bf5SDavid du Colombier
884219b2ee8SDavid du Colombier /* sanity clause */
8857dd7cddfSDavid du Colombier oureg = (ulong)nureg;
886219b2ee8SDavid du Colombier if(!okaddr((ulong)oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
8877dd7cddfSDavid du Colombier qunlock(&up->debug);
8882f205b96SDavid du Colombier pprint("bad ureg in noted or call to noted when not notified\n");
889219b2ee8SDavid du Colombier pexit("Suicide", 0);
890219b2ee8SDavid du Colombier }
891219b2ee8SDavid du Colombier
8927dd7cddfSDavid du Colombier /*
8937dd7cddfSDavid du Colombier * Check the segment selectors are all valid, otherwise
8947dd7cddfSDavid du Colombier * a fault will be taken on attempting to return to the
8957dd7cddfSDavid du Colombier * user process.
8967dd7cddfSDavid du Colombier * Take care with the comparisons as different processor
8977dd7cddfSDavid du Colombier * generations push segment descriptors in different ways.
8987dd7cddfSDavid du Colombier */
8997dd7cddfSDavid du Colombier if((nureg->cs & 0xFFFF) != UESEL || (nureg->ss & 0xFFFF) != UDSEL
9007dd7cddfSDavid du Colombier || (nureg->ds & 0xFFFF) != UDSEL || (nureg->es & 0xFFFF) != UDSEL
9017dd7cddfSDavid du Colombier || (nureg->fs & 0xFFFF) != UDSEL || (nureg->gs & 0xFFFF) != UDSEL){
9027dd7cddfSDavid du Colombier qunlock(&up->debug);
9032f205b96SDavid du Colombier pprint("bad segment selector in noted\n");
9047dd7cddfSDavid du Colombier pexit("Suicide", 0);
9057dd7cddfSDavid du Colombier }
906219b2ee8SDavid du Colombier
907219b2ee8SDavid du Colombier /* don't let user change system flags */
9087dd7cddfSDavid du Colombier nureg->flags = (ureg->flags & ~0xCD5) | (nureg->flags & 0xCD5);
909219b2ee8SDavid du Colombier
9107dd7cddfSDavid du Colombier memmove(ureg, nureg, sizeof(Ureg));
911219b2ee8SDavid du Colombier
9123e12c5d1SDavid du Colombier switch(arg0){
9133e12c5d1SDavid du Colombier case NCONT:
914219b2ee8SDavid du Colombier case NRSTR:
915208510e1SDavid du Colombier if(0) print("%s %lud: noted %.8lux %.8lux\n",
916208510e1SDavid du Colombier up->text, up->pid, nureg->pc, nureg->usp);
9177dd7cddfSDavid du Colombier if(!okaddr(nureg->pc, 1, 0) || !okaddr(nureg->usp, BY2WD, 0)){
9187dd7cddfSDavid du Colombier qunlock(&up->debug);
919219b2ee8SDavid du Colombier pprint("suicide: trap in noted\n");
920219b2ee8SDavid du Colombier pexit("Suicide", 0);
921219b2ee8SDavid du Colombier }
9227dd7cddfSDavid du Colombier up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD));
9237dd7cddfSDavid du Colombier qunlock(&up->debug);
924219b2ee8SDavid du Colombier break;
925219b2ee8SDavid du Colombier
926219b2ee8SDavid du Colombier case NSAVE:
9277dd7cddfSDavid du Colombier if(!okaddr(nureg->pc, BY2WD, 0)
9287dd7cddfSDavid du Colombier || !okaddr(nureg->usp, BY2WD, 0)){
9297dd7cddfSDavid du Colombier qunlock(&up->debug);
930219b2ee8SDavid du Colombier pprint("suicide: trap in noted\n");
931219b2ee8SDavid du Colombier pexit("Suicide", 0);
9323e12c5d1SDavid du Colombier }
9337dd7cddfSDavid du Colombier qunlock(&up->debug);
9349a747e4fSDavid du Colombier sp = oureg-4*BY2WD-ERRMAX;
935219b2ee8SDavid du Colombier splhi();
9367dd7cddfSDavid du Colombier ureg->sp = sp;
937219b2ee8SDavid du Colombier ((ulong*)sp)[1] = oureg; /* arg 1 0(FP) is ureg* */
938219b2ee8SDavid du Colombier ((ulong*)sp)[0] = 0; /* arg 0 is pc */
939219b2ee8SDavid du Colombier break;
9403e12c5d1SDavid du Colombier
9413e12c5d1SDavid du Colombier default:
942219b2ee8SDavid du Colombier pprint("unknown noted arg 0x%lux\n", arg0);
9437dd7cddfSDavid du Colombier up->lastnote.flag = NDebug;
9447dd7cddfSDavid du Colombier /* fall through */
9453e12c5d1SDavid du Colombier
9463e12c5d1SDavid du Colombier case NDFLT:
9477dd7cddfSDavid du Colombier if(up->lastnote.flag == NDebug){
9487dd7cddfSDavid du Colombier qunlock(&up->debug);
9497dd7cddfSDavid du Colombier pprint("suicide: %s\n", up->lastnote.msg);
950219b2ee8SDavid du Colombier } else
9517dd7cddfSDavid du Colombier qunlock(&up->debug);
9527dd7cddfSDavid du Colombier pexit(up->lastnote.msg, up->lastnote.flag!=NDebug);
9533e12c5d1SDavid du Colombier }
9543e12c5d1SDavid du Colombier }
9553e12c5d1SDavid du Colombier
956*fac6300fSDavid du Colombier void
validalign(uintptr addr,unsigned align)957*fac6300fSDavid du Colombier validalign(uintptr addr, unsigned align)
958*fac6300fSDavid du Colombier {
959*fac6300fSDavid du Colombier /*
960*fac6300fSDavid du Colombier * Plan 9 is a 32-bit O/S, and the hardware it runs on
961*fac6300fSDavid du Colombier * does not usually have instructions which move 64-bit
962*fac6300fSDavid du Colombier * quantities directly, synthesizing the operations
963*fac6300fSDavid du Colombier * with 32-bit move instructions. Therefore, the compiler
964*fac6300fSDavid du Colombier * (and hardware) usually only enforce 32-bit alignment,
965*fac6300fSDavid du Colombier * if at all.
966*fac6300fSDavid du Colombier *
967*fac6300fSDavid du Colombier * Take this out if the architecture warrants it.
968*fac6300fSDavid du Colombier */
969*fac6300fSDavid du Colombier if(align == sizeof(vlong))
970*fac6300fSDavid du Colombier align = sizeof(long);
971*fac6300fSDavid du Colombier
972*fac6300fSDavid du Colombier /*
973*fac6300fSDavid du Colombier * Check align is a power of 2, then addr alignment.
974*fac6300fSDavid du Colombier */
975*fac6300fSDavid du Colombier if((align != 0 && !(align & (align-1))) && !(addr & (align-1)))
976*fac6300fSDavid du Colombier return;
977*fac6300fSDavid du Colombier postnote(up, 1, "sys: odd address", NDebug);
978*fac6300fSDavid du Colombier error(Ebadarg);
979*fac6300fSDavid du Colombier /*NOTREACHED*/
980*fac6300fSDavid du Colombier }
981*fac6300fSDavid du Colombier
9827dd7cddfSDavid du Colombier long
execregs(ulong entry,ulong ssize,ulong nargs)9837dd7cddfSDavid du Colombier execregs(ulong entry, ulong ssize, ulong nargs)
9847dd7cddfSDavid du Colombier {
9857dd7cddfSDavid du Colombier ulong *sp;
9867dd7cddfSDavid du Colombier Ureg *ureg;
9877dd7cddfSDavid du Colombier
9884de34a7eSDavid du Colombier up->fpstate = FPinit;
9894de34a7eSDavid du Colombier fpoff();
9904de34a7eSDavid du Colombier
9917dd7cddfSDavid du Colombier sp = (ulong*)(USTKTOP - ssize);
9927dd7cddfSDavid du Colombier *--sp = nargs;
9937dd7cddfSDavid du Colombier
9947dd7cddfSDavid du Colombier ureg = up->dbgreg;
9957dd7cddfSDavid du Colombier ureg->usp = (ulong)sp;
9967dd7cddfSDavid du Colombier ureg->pc = entry;
997e288d156SDavid du Colombier return USTKTOP-sizeof(Tos); /* address of kernel/user shared data */
9987dd7cddfSDavid du Colombier }
9997dd7cddfSDavid du Colombier
100059cc4ca5SDavid du Colombier /*
100159cc4ca5SDavid du Colombier * return the userpc the last exception happened at
100259cc4ca5SDavid du Colombier */
10037dd7cddfSDavid du Colombier ulong
userpc(void)10047dd7cddfSDavid du Colombier userpc(void)
10057dd7cddfSDavid du Colombier {
10067dd7cddfSDavid du Colombier Ureg *ureg;
10077dd7cddfSDavid du Colombier
10087dd7cddfSDavid du Colombier ureg = (Ureg*)up->dbgreg;
10097dd7cddfSDavid du Colombier return ureg->pc;
10107dd7cddfSDavid du Colombier }
10117dd7cddfSDavid du Colombier
10127dd7cddfSDavid du Colombier /* This routine must save the values of registers the user is not permitted
10137dd7cddfSDavid du Colombier * to write from devproc and then restore the saved values before returning.
10143e12c5d1SDavid du Colombier */
10153e12c5d1SDavid du Colombier void
setregisters(Ureg * ureg,char * pureg,char * uva,int n)10167dd7cddfSDavid du Colombier setregisters(Ureg* ureg, char* pureg, char* uva, int n)
10173e12c5d1SDavid du Colombier {
1018756a7013SDavid du Colombier ulong cs, ds, es, flags, fs, gs, ss;
10193e12c5d1SDavid du Colombier
1020756a7013SDavid du Colombier ss = ureg->ss;
10217dd7cddfSDavid du Colombier flags = ureg->flags;
10227dd7cddfSDavid du Colombier cs = ureg->cs;
1023756a7013SDavid du Colombier ds = ureg->ds;
1024756a7013SDavid du Colombier es = ureg->es;
1025756a7013SDavid du Colombier fs = ureg->fs;
1026756a7013SDavid du Colombier gs = ureg->gs;
10273e12c5d1SDavid du Colombier memmove(pureg, uva, n);
1028756a7013SDavid du Colombier ureg->gs = gs;
1029756a7013SDavid du Colombier ureg->fs = fs;
1030756a7013SDavid du Colombier ureg->es = es;
1031756a7013SDavid du Colombier ureg->ds = ds;
10327dd7cddfSDavid du Colombier ureg->cs = cs;
1033756a7013SDavid du Colombier ureg->flags = (ureg->flags & 0x00FF) | (flags & 0xFF00);
10347dd7cddfSDavid du Colombier ureg->ss = ss;
10357dd7cddfSDavid du Colombier }
10367dd7cddfSDavid du Colombier
10377dd7cddfSDavid du Colombier static void
linkproc(void)10387dd7cddfSDavid du Colombier linkproc(void)
10397dd7cddfSDavid du Colombier {
10407dd7cddfSDavid du Colombier spllo();
10417dd7cddfSDavid du Colombier up->kpfun(up->kparg);
10423ff48bf5SDavid du Colombier pexit("kproc dying", 0);
10437dd7cddfSDavid du Colombier }
10447dd7cddfSDavid du Colombier
10457dd7cddfSDavid du Colombier void
kprocchild(Proc * p,void (* func)(void *),void * arg)10467dd7cddfSDavid du Colombier kprocchild(Proc* p, void (*func)(void*), void* arg)
10477dd7cddfSDavid du Colombier {
10487dd7cddfSDavid du Colombier /*
10497dd7cddfSDavid du Colombier * gotolabel() needs a word on the stack in
10507dd7cddfSDavid du Colombier * which to place the return PC used to jump
10517dd7cddfSDavid du Colombier * to linkproc().
10527dd7cddfSDavid du Colombier */
10537dd7cddfSDavid du Colombier p->sched.pc = (ulong)linkproc;
10547dd7cddfSDavid du Colombier p->sched.sp = (ulong)p->kstack+KSTACK-BY2WD;
10557dd7cddfSDavid du Colombier
10567dd7cddfSDavid du Colombier p->kpfun = func;
10577dd7cddfSDavid du Colombier p->kparg = arg;
10587dd7cddfSDavid du Colombier }
10597dd7cddfSDavid du Colombier
10607dd7cddfSDavid du Colombier void
forkchild(Proc * p,Ureg * ureg)10617dd7cddfSDavid du Colombier forkchild(Proc *p, Ureg *ureg)
10627dd7cddfSDavid du Colombier {
10637dd7cddfSDavid du Colombier Ureg *cureg;
10647dd7cddfSDavid du Colombier
10657dd7cddfSDavid du Colombier /*
10667dd7cddfSDavid du Colombier * Add 2*BY2WD to the stack to account for
10677dd7cddfSDavid du Colombier * - the return PC
10687dd7cddfSDavid du Colombier * - trap's argument (ur)
10697dd7cddfSDavid du Colombier */
10707dd7cddfSDavid du Colombier p->sched.sp = (ulong)p->kstack+KSTACK-(sizeof(Ureg)+2*BY2WD);
10717dd7cddfSDavid du Colombier p->sched.pc = (ulong)forkret;
10727dd7cddfSDavid du Colombier
10737dd7cddfSDavid du Colombier cureg = (Ureg*)(p->sched.sp+2*BY2WD);
10747dd7cddfSDavid du Colombier memmove(cureg, ureg, sizeof(Ureg));
10757dd7cddfSDavid du Colombier /* return value of syscall in child */
10767dd7cddfSDavid du Colombier cureg->ax = 0;
10777dd7cddfSDavid du Colombier
10787dd7cddfSDavid du Colombier /* Things from bottom of syscall which were never executed */
10797dd7cddfSDavid du Colombier p->psstate = 0;
10807dd7cddfSDavid du Colombier p->insyscall = 0;
10817dd7cddfSDavid du Colombier }
10827dd7cddfSDavid du Colombier
10837dd7cddfSDavid du Colombier /* Give enough context in the ureg to produce a kernel stack for
10847dd7cddfSDavid du Colombier * a sleeping process
10857dd7cddfSDavid du Colombier */
10867dd7cddfSDavid du Colombier void
setkernur(Ureg * ureg,Proc * p)10877dd7cddfSDavid du Colombier setkernur(Ureg* ureg, Proc* p)
10887dd7cddfSDavid du Colombier {
10897dd7cddfSDavid du Colombier ureg->pc = p->sched.pc;
10907dd7cddfSDavid du Colombier ureg->sp = p->sched.sp+4;
10917dd7cddfSDavid du Colombier }
10927dd7cddfSDavid du Colombier
10937dd7cddfSDavid du Colombier ulong
dbgpc(Proc * p)10947dd7cddfSDavid du Colombier dbgpc(Proc *p)
10957dd7cddfSDavid du Colombier {
10967dd7cddfSDavid du Colombier Ureg *ureg;
10977dd7cddfSDavid du Colombier
10987dd7cddfSDavid du Colombier ureg = p->dbgreg;
10997dd7cddfSDavid du Colombier if(ureg == 0)
11007dd7cddfSDavid du Colombier return 0;
11017dd7cddfSDavid du Colombier
11027dd7cddfSDavid du Colombier return ureg->pc;
11033e12c5d1SDavid du Colombier }
1104