]> git.lizzy.rs Git - plan9front.git/blobdiff - sys/src/9/pc/devarch.c
kernel: cleanup the software mouse cursor mess
[plan9front.git] / sys / src / 9 / pc / devarch.c
index c4527168267e121a84b815649af346c1331362f8..2da6f5d556590560a186c954ea46e777f605ab63 100644 (file)
@@ -36,13 +36,22 @@ enum {
        Qmsr,
        Qbase,
 
-       Qmax = 16,
+       Qmax = 32,
 };
+
+enum {
+       CR4Osfxsr = 1 << 9,
+       CR4Oxmmex = 1 << 10,
+};
+
 enum {                         /* cpuid standard function codes */
        Highstdfunc = 0,        /* also returns vendor string */
        Procsig,
        Proctlbcache,
        Procserial,
+       
+       Highextfunc = 0x80000000,
+       Procextfeat,
 };
 
 typedef long Rdwrfn(Chan*, void*, long, vlong);
@@ -56,15 +65,13 @@ static Dirtab archdir[Qmax] = {
        "iob",          { Qiob, 0 },            0,      0660,
        "iow",          { Qiow, 0 },            0,      0660,
        "iol",          { Qiol, 0 },            0,      0660,
-       "msr",  { Qmsr, 0},     0,      0660,
+       "msr",          { Qmsr, 0 },            0,      0660,
 };
 Lock archwlock;        /* the lock is only for changing archdir */
 int narchdir = Qbase;
 int (*_pcmspecial)(char*, ISAConf*);
 void (*_pcmspecialclose)(int);
 
-static int doi8253set = 1;
-
 /*
  * Add a file to the #P listing.  Once added, you can't delete it.
  * You can't add a file with the same name as one already there,
@@ -85,6 +92,7 @@ addarchfile(char *name, int perm, Rdwrfn *rdfn, Rdwrfn *wrfn)
        lock(&archwlock);
        if(narchdir >= Qmax){
                unlock(&archwlock);
+               print("addarchfile: out of entries for %s\n", name);
                return nil;
        }
 
@@ -188,7 +196,7 @@ ioreserve(int, int size, int align, char *tag)
        m->start = port;
        m->end = port + size;
        m->reserved = 1;
-       strncpy(m->tag, tag, sizeof(m->tag));
+       strncpy(m->tag, tag, sizeof(m->tag)-1);
        m->tag[sizeof(m->tag)-1] = 0;
        *l = m;
 
@@ -212,8 +220,7 @@ ioalloc(int port, int size, int align, char *tag)
        if(port < 0){
                /* find a free port above 0x400 and below 0x1000 */
                port = 0x400;
-               for(l = &iomap.m; *l; l = &(*l)->next){
-                       m = *l;
+               for(l = &iomap.m; (m = *l) != nil; l = &m->next){
                        if (m->start < 0x400) continue;
                        i = m->start - port;
                        if(i > size)
@@ -223,7 +230,7 @@ ioalloc(int port, int size, int align, char *tag)
                        else
                                port = m->end;
                }
-               if(*l == nil){
+               if(m == nil){
                        unlock(&iomap);
                        return -1;
                }
@@ -234,11 +241,10 @@ ioalloc(int port, int size, int align, char *tag)
                        return -1;
                }
                /* see if the space clashes with previously allocated ports */
-               for(l = &iomap.m; *l; l = &(*l)->next){
-                       m = *l;
+               for(l = &iomap.m; (m = *l) != nil; l = &m->next){
                        if(m->end <= port)
                                continue;
-                       if(m->reserved && m->start == port && m->end == port + size) {
+                       if(m->reserved && m->start == port && m->end >= port + size) {
                                m->reserved = 0;
                                unlock(&iomap);
                                return m->start;
@@ -259,7 +265,7 @@ ioalloc(int port, int size, int align, char *tag)
        m->next = *l;
        m->start = port;
        m->end = port + size;
-       strncpy(m->tag, tag, sizeof(m->tag));
+       strncpy(m->tag, tag, sizeof(m->tag)-1);
        m->tag[sizeof(m->tag)-1] = 0;
        *l = m;
 
@@ -275,15 +281,14 @@ iofree(int port)
        IOMap *m, **l;
 
        lock(&iomap);
-       for(l = &iomap.m; *l; l = &(*l)->next){
-               if((*l)->start == port){
-                       m = *l;
+       for(l = &iomap.m; (m = *l) != nil; l = &m->next){
+               if(m->start == port){
                        *l = m->next;
                        m->next = iomap.free;
                        iomap.free = m;
                        break;
                }
-               if((*l)->start > port)
+               if(m->start > port)
                        break;
        }
        archdir[0].qid.vers++;
@@ -295,7 +300,7 @@ iounused(int start, int end)
 {
        IOMap *m;
 
-       for(m = iomap.m; m; m = m->next){
+       for(m = iomap.m; m != nil; m = m->next){
                if(start >= m->start && start < m->end
                || start <= m->start && end > m->start)
                        return 0;
@@ -304,8 +309,11 @@ iounused(int start, int end)
 }
 
 static void
-checkport(int start, int end)
+checkport(uint start, uint end)
 {
+       if(end < start || end > 0x10000)
+               error(Ebadarg);
+
        /* standard vga regs are OK */
        if(start >= 0x2b0 && end <= 0x2df+1)
                return;
@@ -346,140 +354,132 @@ archclose(Chan*)
 {
 }
 
-enum
-{
-       Linelen= 31,
-};
-
 static long
 archread(Chan *c, void *a, long n, vlong offset)
 {
-       char *buf, *p;
-       int port;
+       char buf[32], *p;
+       uint port, end;
        ushort *sp;
        ulong *lp;
        vlong *vp;
        IOMap *m;
        Rdwrfn *fn;
+       int i;
 
+       port = offset;
+       end = port+n;
        switch((ulong)c->qid.path){
-
        case Qdir:
                return devdirread(c, a, n, archdir, narchdir, devgen);
 
        case Qiob:
-               port = offset;
-               checkport(offset, offset+n);
-               for(p = a; port < offset+n; port++)
+               checkport(port, end);
+               for(p = a; port < end; port++)
                        *p++ = inb(port);
                return n;
 
        case Qiow:
                if(n & 1)
                        error(Ebadarg);
-               checkport(offset, offset+n);
-               sp = a;
-               for(port = offset; port < offset+n; port += 2)
+               checkport(port, end);
+               for(sp = a; port < end; port += 2)
                        *sp++ = ins(port);
                return n;
 
        case Qiol:
                if(n & 3)
                        error(Ebadarg);
-               checkport(offset, offset+n);
-               lp = a;
-               for(port = offset; port < offset+n; port += 4)
+               checkport(port, end);
+               for(lp = a; port < end; port += 4)
                        *lp++ = inl(port);
                return n;
 
        case Qmsr:
                if(n & 7)
                        error(Ebadarg);
-               vp = a;
-               for(port = offset; port < offset+n; port += 8)
-                       rdmsr(port, vp++);
+               if((uint)n/8 > -port)
+                       error(Ebadarg);
+               end = port+(n/8);
+               for(vp = a; port != end; port++)
+                       if(rdmsr(port, vp++) < 0)
+                               error(Ebadarg);
                return n;
 
        case Qioalloc:
-               break;
+               lock(&iomap);
+               i = 0;
+               for(m = iomap.m; m != nil; m = m->next){
+                       i = snprint(buf, sizeof(buf), "%8lux %8lux %-12.12s\n",
+                               m->start, m->end-1, m->tag);
+                       offset -= i;
+                       if(offset < 0)
+                               break;
+               }
+               unlock(&iomap);
+               if(offset >= 0)
+                       return 0;
+               if(n > -offset)
+                       n = -offset;
+               offset += i;
+               memmove(a, buf+offset, n);
+               return n;
 
        default:
                if(c->qid.path < narchdir && (fn = readfn[c->qid.path]))
                        return fn(c, a, n, offset);
                error(Eperm);
-               break;
+               return 0;
        }
-
-       if((buf = malloc(n)) == nil)
-               error(Enomem);
-       p = buf;
-       n = n/Linelen;
-       offset = offset/Linelen;
-
-       lock(&iomap);
-       for(m = iomap.m; n > 0 && m != nil; m = m->next){
-               if(offset-- > 0)
-                       continue;
-               sprint(p, "%8lux %8lux %-12.12s\n", m->start, m->end-1, m->tag);
-               p += Linelen;
-               n--;
-       }
-       unlock(&iomap);
-
-       n = p - buf;
-       memmove(a, buf, n);
-       free(buf);
-
-       return n;
 }
 
 static long
 archwrite(Chan *c, void *a, long n, vlong offset)
 {
+       uint port, end;
        char *p;
-       int port;
        ushort *sp;
        ulong *lp;
        vlong *vp;
        Rdwrfn *fn;
 
+       port = offset;
+       end = port+n;
        switch((ulong)c->qid.path){
-
        case Qiob:
-               p = a;
-               checkport(offset, offset+n);
-               for(port = offset; port < offset+n; port++)
+               checkport(port, end);
+               for(p = a; port < end; port++)
                        outb(port, *p++);
                return n;
 
        case Qiow:
                if(n & 1)
                        error(Ebadarg);
-               checkport(offset, offset+n);
-               sp = a;
-               for(port = offset; port < offset+n; port += 2)
+               checkport(port, end);
+               for(sp = a; port < end; port += 2)
                        outs(port, *sp++);
                return n;
 
        case Qiol:
                if(n & 3)
                        error(Ebadarg);
-               checkport(offset, offset+n);
-               lp = a;
-               for(port = offset; port < offset+n; port += 4)
+               checkport(port, end);
+               for(lp = a; port < end; port += 4)
                        outl(port, *lp++);
                return n;
 
        case Qmsr:
                if(n & 7)
                        error(Ebadarg);
-               vp = a;
-               for(port = offset; port < offset+n; port += 8)
-                       wrmsr(port, *vp++);
+               if((uint)n/8 > -port)
+                       error(Ebadarg);
+               end = port+(n/8);
+               for(vp = a; port != end; port++)
+                       if(wrmsr(port, *vp++) < 0)
+                               error(Ebadarg);
                return n;
 
        default:
-               if(c->qid.path < narchdir && (fn = writefn[c->qid.path]))
+               if(c->qid.path < narchdir && (fn = writefn[c->qid.path]) != nil)
                        return fn(c, a, n, offset);
                error(Eperm);
                break;
@@ -524,7 +524,7 @@ nop(void)
 {
 }
 
-static void
+void
 archreset(void)
 {
        i8042reset();
@@ -544,6 +544,7 @@ archreset(void)
        outb(0xcf9, 0x02);
        outb(0xcf9, 0x06);
 
+       print("can't reset\n");
        for(;;)
                idle();
 }
@@ -683,6 +684,7 @@ static X86type x86amd[] =
        { 6,    -1,     11,     "AMD-Athlon", },/* guesswork */
        { 0xF,  -1,     11,     "AMD-K8", },    /* guesswork */
        { 0x1F, -1,     11,     "AMD-K10", },   /* guesswork */
+       { 23,   1,      13,     "AMD Ryzen" },
 
        { -1,   -1,     11,     "unknown", },   /* total default */
 };
@@ -723,16 +725,9 @@ simplecycles(uvlong*x)
 void
 cpuidprint(void)
 {
-       int i;
-       char buf[128];
-
-       i = sprint(buf, "cpu%d: %dMHz ", m->machno, m->cpumhz);
-       if(m->cpuidid[0])
-               i += sprint(buf+i, "%12.12s ", m->cpuidid);
-       seprint(buf+i, buf + sizeof buf - 1,
-               "%s (cpuid: AX 0x%4.4uX DX 0x%4.4uX)\n",
-               m->cpuidtype, m->cpuidax, m->cpuiddx);
-       print(buf);
+       print("cpu%d: %dMHz %s %s (AX %8.8uX CX %8.8uX DX %8.8uX)\n",
+               m->machno, m->cpumhz, m->cpuidid, m->cpuidtype,
+               m->cpuidax, m->cpuidcx, m->cpuiddx);
 }
 
 /*
@@ -752,7 +747,7 @@ cpuidentify(void)
        char *p;
        int family, model, nomce;
        X86type *t, *tab;
-       ulong cr4;
+       uintptr cr4;
        ulong regs[4];
        vlong mca, mct;
 
@@ -764,7 +759,21 @@ cpuidentify(void)
 
        cpuid(Procsig, regs);
        m->cpuidax = regs[0];
+       m->cpuidcx = regs[2];
        m->cpuiddx = regs[3];
+       
+       m->cpuidfamily = m->cpuidax >> 8 & 0xf;
+       m->cpuidmodel = m->cpuidax >> 4 & 0xf;
+       m->cpuidstepping = m->cpuidax & 0xf;
+       switch(m->cpuidfamily){
+       case 15:
+               m->cpuidfamily += m->cpuidax >> 20 & 0xff;
+               m->cpuidmodel += m->cpuidax >> 16 & 0xf;
+               break;
+       case 6:
+               m->cpuidmodel += m->cpuidax >> 16 & 0xf;
+               break;
+       }
 
        if(strncmp(m->cpuidid, "AuthenticAMD", 12) == 0 ||
           strncmp(m->cpuidid, "Geode by NSC", 12) == 0)
@@ -776,8 +785,8 @@ cpuidentify(void)
        else
                tab = x86intel;
 
-       family = X86FAMILY(m->cpuidax);
-       model = X86MODEL(m->cpuidax);
+       family = m->cpuidfamily;
+       model = m->cpuidmodel;
        for(t=tab; t->name; t++)
                if((t->family == family && t->model == model)
                || (t->family == family && t->model == -1)
@@ -806,20 +815,45 @@ cpuidentify(void)
         * are supported enable them in CR4 and clear any other set extensions.
         * If machine check was enabled clear out any lingering status.
         */
-       if(m->cpuiddx & (Pge|Mce|0x8)){
-               cr4 = 0;
-               if(m->cpuiddx & 0x08)
+       if(m->cpuiddx & (Pge|Mce|Pse)){
+               cr4 = getcr4();
+               if(m->cpuiddx & Pse)
                        cr4 |= 0x10;            /* page size extensions */
                if(p = getconf("*nomce"))
                        nomce = strtoul(p, 0, 0);
                else
                        nomce = 0;
-               if((m->cpuiddx & Mce) && !nomce){
-                       cr4 |= 0x40;            /* machine check enable */
-                       if(family == 5){
+               if((m->cpuiddx & Mce) != 0 && !nomce){
+                       if((m->cpuiddx & Mca) != 0){
+                               vlong cap;
+                               int bank;
+
+                               cap = 0;
+                               rdmsr(0x179, &cap);
+
+                               if(cap & 0x100)
+                                       wrmsr(0x17B, ~0ULL);    /* enable all mca features */
+
+                               bank = cap & 0xFF;
+                               if(bank > 64)
+                                       bank = 64;
+
+                               /* init MCi .. MC1 (except MC0) */
+                               while(--bank > 0){
+                                       wrmsr(0x400 + bank*4, ~0ULL);
+                                       wrmsr(0x401 + bank*4, 0);
+                               }
+
+                               if(family != 6 || model >= 0x1A)
+                                       wrmsr(0x400, ~0ULL);
+
+                               wrmsr(0x401, 0);
+                       }
+                       else if(family == 5){
                                rdmsr(0x00, &mca);
                                rdmsr(0x01, &mct);
                        }
+                       cr4 |= 0x40;            /* machine check enable */
                }
 
                /*
@@ -843,10 +877,61 @@ cpuidentify(void)
                }
 
                putcr4(cr4);
-               if(m->cpuiddx & Mce)
+
+               if((m->cpuiddx & (Mca|Mce)) == Mce)
                        rdmsr(0x01, &mct);
        }
 
+       if(m->cpuiddx & Mtrr)
+               mtrrsync();
+
+       if((m->cpuiddx & (Sse|Fxsr)) == (Sse|Fxsr)){                    /* have sse fp? */
+               fpsave = fpssesave;
+               fprestore = fpsserestore;
+               putcr4(getcr4() | CR4Osfxsr|CR4Oxmmex);
+       } else {
+               fpsave = fpx87save;
+               fprestore = fpx87restore;
+       }
+
+       if(strcmp(m->cpuidid, "GenuineIntel") == 0 && (m->cpuidcx & Rdrnd) != 0)
+               hwrandbuf = rdrandbuf;
+       else
+               hwrandbuf = nil;
+       
+       if(sizeof(uintptr) == 8) {
+               /* 8-byte watchpoints are supported in Long Mode */
+               m->havewatchpt8 = 1;
+
+               /* check and enable NX bit */
+               cpuid(Highextfunc, regs);
+               if(regs[0] >= Procextfeat){
+                       cpuid(Procextfeat, regs);
+                       if((regs[3] & (1<<20)) != 0){
+                               vlong efer;
+
+                               /* enable no-execute feature */
+                               if(rdmsr(Efer, &efer) != -1){
+                                       efer |= 1ull<<11;
+                                       if(wrmsr(Efer, efer) != -1)
+                                               m->havenx = 1;
+                               }
+                       }
+               }
+       } else if(strcmp(m->cpuidid, "GenuineIntel") == 0){
+               /* some random CPUs that support 8-byte watchpoints */
+               if(family == 15 && (model == 3 || model == 4 || model == 6)
+               || family == 6 && (model == 15 || model == 23 || model == 28))
+                       m->havewatchpt8 = 1;
+               /* Intel SDM claims amd64 support implies 8-byte watchpoint support */
+               cpuid(Highextfunc, regs);
+               if(regs[0] >= Procextfeat){
+                       cpuid(Procextfeat, regs);
+                       if((regs[3] & 1<<29) != 0)
+                               m->havewatchpt8 = 1;
+               }
+       }
+
        cputype = t;
        return t->family;
 }
@@ -869,7 +954,7 @@ archctlread(Chan*, void *a, long nn, vlong offset)
        int n;
        char *buf, *p, *ep;
 
-       p = buf = malloc(READSTR);
+       p = buf = smalloc(READSTR);
        ep = p + READSTR;
        p = seprint(p, ep, "cpu %s %lud%s\n",
                cputype->name, (ulong)(m->cpuhz+999999)/1000000,
@@ -893,7 +978,7 @@ archctlread(Chan*, void *a, long nn, vlong offset)
                p = seprint(p, ep, "cmpswap486\n");
        else
                p = seprint(p, ep, "0x%p\n", cmpswap);
-       p = seprint(p, ep, "i8253set %s\n", doi8253set ? "on" : "off");
+       p = seprint(p, ep, "arch %s\n", arch->id);
        n = p - buf;
        n += mtrrprint(p, ep - p);
        buf[n] = '\0';
@@ -907,7 +992,6 @@ enum
 {
        CMpge,
        CMcoherence,
-       CMi8253set,
        CMcache,
 };
 
@@ -915,8 +999,7 @@ static Cmdtab archctlmsg[] =
 {
        CMpge,          "pge",          2,
        CMcoherence,    "coherence",    2,
-       CMi8253set,     "i8253set",     2,
-       CMcache,                "cache",                4,
+       CMcache,        "cache",        4,
 };
 
 static long
@@ -948,7 +1031,7 @@ archctlwrite(Chan*, void *a, long n, vlong)
                if(strcmp(cb->f[1], "mb386") == 0)
                        coherence = mb386;
                else if(strcmp(cb->f[1], "mb586") == 0){
-                       if(X86FAMILY(m->cpuidax) < 5)
+                       if(m->cpuidfamily < 5)
                                error("invalid coherence ctl on this cpu family");
                        coherence = mb586;
                }else if(strcmp(cb->f[1], "mfence") == 0){
@@ -963,15 +1046,6 @@ archctlwrite(Chan*, void *a, long n, vlong)
                }else
                        cmderror(cb, "invalid coherence ctl");
                break;
-       case CMi8253set:
-               if(strcmp(cb->f[1], "on") == 0)
-                       doi8253set = 1;
-               else if(strcmp(cb->f[1], "off") == 0){
-                       doi8253set = 0;
-                       (*arch->timerset)(0);
-               }else
-                       cmderror(cb, "invalid i2853set ctl");
-               break;
        case CMcache:
                base = strtoull(cb->f[1], &ep, 0);
                if(*ep)
@@ -979,7 +1053,9 @@ archctlwrite(Chan*, void *a, long n, vlong)
                size = strtoull(cb->f[2], &ep, 0);
                if(*ep)
                        error("cache: parse error: size not a number?");
-               mtrr(base, size, cb->f[3]);
+               ep = mtrr(base, size, cb->f[3]);
+               if(ep != nil)
+                       error(ep);
                break;
        }
        free(cb);
@@ -988,17 +1064,38 @@ archctlwrite(Chan*, void *a, long n, vlong)
 }
 
 static long
-mordorread(Chan*, void*, long, vlong)
+rmemrw(int isr, void *a, long n, vlong off)
 {
-       error("one does not simply read from mordor");
-       return 0;
+       uintptr addr = off;
+
+       if(off < 0 || n < 0)
+               error("bad offset/count");
+       if(isr){
+               if(addr >= MB)
+                       return 0;
+               if(addr+n > MB)
+                       n = MB - addr;
+               memmove(a, KADDR(addr), n);
+       }else{
+               /* allow vga framebuf's write access */
+               if(addr >= MB || addr+n > MB ||
+                   (addr < 0xA0000 || addr+n > 0xB0000+0x10000))
+                       error("bad offset/count in write");
+               memmove(KADDR(addr), a, n);
+       }
+       return n;
 }
 
 static long
-mordorwrite(Chan*, void*, long, vlong)
+rmemread(Chan*, void *a, long n, vlong off)
 {
-       error("one does not simply write into mordor");
-       return 0;
+       return rmemrw(1, a, n, off);
+}
+
+static long
+rmemwrite(Chan*, void *a, long n, vlong off)
+{
+       return rmemrw(0, a, n, off);
 }
 
 void
@@ -1006,27 +1103,25 @@ archinit(void)
 {
        PCArch **p;
 
-       arch = 0;
-       for(p = knownarch; *p; p++){
-               if((*p)->ident && (*p)->ident() == 0){
+       arch = &archgeneric;
+       for(p = knownarch; *p != nil; p++){
+               if((*p)->ident != nil && (*p)->ident() == 0){
                        arch = *p;
                        break;
                }
        }
-       if(arch == 0)
-               arch = &archgeneric;
-       else{
-               if(arch->id == 0)
+       if(arch != &archgeneric){
+               if(arch->id == nil)
                        arch->id = archgeneric.id;
-               if(arch->reset == 0)
+               if(arch->reset == nil)
                        arch->reset = archgeneric.reset;
-               if(arch->serialpower == 0)
+               if(arch->serialpower == nil)
                        arch->serialpower = archgeneric.serialpower;
-               if(arch->modempower == 0)
+               if(arch->modempower == nil)
                        arch->modempower = archgeneric.modempower;
-               if(arch->intrinit == 0)
+               if(arch->intrinit == nil)
                        arch->intrinit = archgeneric.intrinit;
-               if(arch->intrenable == 0)
+               if(arch->intrenable == nil)
                        arch->intrenable = archgeneric.intrenable;
        }
 
@@ -1035,13 +1130,13 @@ archinit(void)
         *  We get another chance to set it in mpinit() for a
         *  multiprocessor.
         */
-       if(X86FAMILY(m->cpuidax) == 3)
+       if(m->cpuidfamily == 3)
                conf.copymode = 1;
 
-       if(X86FAMILY(m->cpuidax) >= 4)
+       if(m->cpuidfamily >= 4)
                cmpswap = cmpswap486;
 
-       if(X86FAMILY(m->cpuidax) >= 5)
+       if(m->cpuidfamily >= 5)
                coherence = mb586;
 
        if(m->cpuiddx & Sse2)
@@ -1049,7 +1144,7 @@ archinit(void)
 
        addarchfile("cputype", 0444, cputyperead, nil);
        addarchfile("archctl", 0664, archctlread, archctlwrite);
-       addarchfile("mordor", 0666, mordorread, mordorwrite);
+       addarchfile("realmodemem", 0660, rmemread, rmemwrite);
 }
 
 /*
@@ -1092,6 +1187,164 @@ ulong
 void
 timerset(Tval x)
 {
-       if(doi8253set)
-               (*arch->timerset)(x);
+       (*arch->timerset)(x);
+}
+
+/*
+ *  put the processor in the halt state if we've no processes to run.
+ *  an interrupt will get us going again.
+ *
+ *  halting in an smp system can result in a startup latency for
+ *  processes that become ready.
+ *  if idle_spin is zero, we care more about saving energy
+ *  than reducing this latency.
+ *
+ *  the performance loss with idle_spin == 0 seems to be slight
+ *  and it reduces lock contention (thus system time and real time)
+ *  on many-core systems with large values of NPROC.
+ */
+void
+idlehands(void)
+{
+       extern int nrdy, idle_spin;
+
+       if(conf.nmach == 1)
+               halt();
+       else if(m->cpuidcx & Monitor)
+               mwait(&nrdy);
+       else if(idle_spin == 0)
+               halt();
+}
+
+int
+isaconfig(char *class, int ctlrno, ISAConf *isa)
+{
+       char cc[32], *p, *x;
+       int i;
+
+       snprint(cc, sizeof cc, "%s%d", class, ctlrno);
+       p = getconf(cc);
+       if(p == nil)
+               return 0;
+
+       x = nil;
+       kstrdup(&x, p);
+       p = x;
+
+       isa->type = "";
+       isa->nopt = tokenize(p, isa->opt, NISAOPT);
+       for(i = 0; i < isa->nopt; i++){
+               p = isa->opt[i];
+               if(cistrncmp(p, "type=", 5) == 0)
+                       isa->type = p + 5;
+               else if(cistrncmp(p, "port=", 5) == 0)
+                       isa->port = strtoul(p+5, &p, 0);
+               else if(cistrncmp(p, "irq=", 4) == 0)
+                       isa->irq = strtoul(p+4, &p, 0);
+               else if(cistrncmp(p, "dma=", 4) == 0)
+                       isa->dma = strtoul(p+4, &p, 0);
+               else if(cistrncmp(p, "mem=", 4) == 0)
+                       isa->mem = strtoul(p+4, &p, 0);
+               else if(cistrncmp(p, "size=", 5) == 0)
+                       isa->size = strtoul(p+5, &p, 0);
+               else if(cistrncmp(p, "freq=", 5) == 0)
+                       isa->freq = strtoul(p+5, &p, 0);
+       }
+       return 1;
+}
+
+void
+dumpmcregs(void)
+{
+       vlong v, w;
+       int bank;
+
+       if((m->cpuiddx & (Mce|Cpumsr)) != (Mce|Cpumsr))
+               return;
+       if((m->cpuiddx & Mca) == 0){
+               rdmsr(0x00, &v);
+               rdmsr(0x01, &w);
+               iprint("MCA %8.8llux MCT %8.8llux\n", v, w);
+               return;
+       }
+       rdmsr(0x179, &v);
+       rdmsr(0x17A, &w);
+       iprint("MCG CAP %.16llux STATUS %.16llux\n", v, w);
+
+       bank = v & 0xFF;
+       if(bank > 64)
+               bank = 64;
+       while(--bank >= 0){
+               rdmsr(0x401 + bank*4, &v);
+               if((v & (1ull << 63)) == 0)
+                       continue;
+               iprint("MC%d STATUS %.16llux", bank, v);
+               if(v & (1ull << 58)){
+                       rdmsr(0x402 + bank*4, &w);
+                       iprint(" ADDR %.16llux", w);
+               }
+               if(v & (1ull << 59)){
+                       rdmsr(0x403 + bank*4, &w);
+                       iprint(" MISC %.16llux", w);
+               }
+               iprint("\n");
+       }
+}
+
+void
+setupwatchpts(Proc *pr, Watchpt *wp, int nwp)
+{
+       int i;
+       u8int cfg;
+       Watchpt *p;
+
+       if(nwp > 4)
+               error("there are four watchpoints.");
+       if(nwp == 0){
+               memset(pr->dr, 0, sizeof(pr->dr));
+               return;
+       }
+       for(p = wp; p < wp + nwp; p++){
+               switch(p->type){
+               case WATCHRD|WATCHWR: case WATCHWR:
+                       break;
+               case WATCHEX:
+                       if(p->len != 1)
+                               error("length must be 1 on breakpoints");
+                       break;
+               default:
+                       error("type must be rw-, -w- or --x");
+               }
+               switch(p->len){
+               case 1: case 2: case 4:
+                       break;
+               case 8:
+                       if(m->havewatchpt8) break;
+               default:
+                       error(m->havewatchpt8 ? "length must be 1,2,4,8" : "length must be 1,2,4");
+               }
+               if((p->addr & p->len - 1) != 0)
+                       error("address must be aligned according to length");
+       }
+       
+       memset(pr->dr, 0, sizeof(pr->dr));
+       pr->dr[6] = 0xffff8ff0;
+       for(i = 0; i < nwp; i++){
+               pr->dr[i] = wp[i].addr;
+               switch(wp[i].type){
+                       case WATCHRD|WATCHWR: cfg = 3; break;
+                       case WATCHWR: cfg = 1; break;
+                       case WATCHEX: cfg = 0; break;
+                       default: continue;
+               }
+               switch(wp[i].len){
+                       case 1: break;
+                       case 2: cfg |= 4; break;
+                       case 4: cfg |= 12; break;
+                       case 8: cfg |= 8; break;
+                       default: continue;
+               }
+               pr->dr[7] |= cfg << 16 + 4 * i;
+               pr->dr[7] |= 1 << 2 * i + 1;
+       }
 }