]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/devarch.c
usbehci: catch interrupt in tsleep
[plan9front.git] / sys / src / 9 / pc / devarch.c
1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "io.h"
7 #include "ureg.h"
8 #include "../port/error.h"
9
10 typedef struct IOMap IOMap;
11 struct IOMap
12 {
13         IOMap   *next;
14         int     reserved;
15         char    tag[13];
16         ulong   start;
17         ulong   end;
18 };
19
20 static struct
21 {
22         Lock;
23         IOMap   *m;
24         IOMap   *free;
25         IOMap   maps[32];       /* some initial free maps */
26
27         QLock   ql;             /* lock for reading map */
28 } iomap;
29
30 enum {
31         Qdir = 0,
32         Qioalloc = 1,
33         Qiob,
34         Qiow,
35         Qiol,
36         Qmsr,
37         Qbase,
38
39         Qmax = 32,
40 };
41
42 enum {
43         CR4Osfxsr = 1 << 9,
44         CR4Oxmmex = 1 << 10,
45 };
46
47 enum {                          /* cpuid standard function codes */
48         Highstdfunc = 0,        /* also returns vendor string */
49         Procsig,
50         Proctlbcache,
51         Procserial,
52         
53         Highextfunc = 0x80000000,
54         Procextfeat,
55 };
56
57 typedef long Rdwrfn(Chan*, void*, long, vlong);
58
59 static Rdwrfn *readfn[Qmax];
60 static Rdwrfn *writefn[Qmax];
61
62 static Dirtab archdir[Qmax] = {
63         ".",            { Qdir, 0, QTDIR },     0,      0555,
64         "ioalloc",      { Qioalloc, 0 },        0,      0444,
65         "iob",          { Qiob, 0 },            0,      0660,
66         "iow",          { Qiow, 0 },            0,      0660,
67         "iol",          { Qiol, 0 },            0,      0660,
68         "msr",          { Qmsr, 0 },            0,      0660,
69 };
70 Lock archwlock; /* the lock is only for changing archdir */
71 int narchdir = Qbase;
72 int (*_pcmspecial)(char*, ISAConf*);
73 void (*_pcmspecialclose)(int);
74
75 /*
76  * Add a file to the #P listing.  Once added, you can't delete it.
77  * You can't add a file with the same name as one already there,
78  * and you get a pointer to the Dirtab entry so you can do things
79  * like change the Qid version.  Changing the Qid path is disallowed.
80  */
81 Dirtab*
82 addarchfile(char *name, int perm, Rdwrfn *rdfn, Rdwrfn *wrfn)
83 {
84         int i;
85         Dirtab d;
86         Dirtab *dp;
87
88         memset(&d, 0, sizeof d);
89         strcpy(d.name, name);
90         d.perm = perm;
91
92         lock(&archwlock);
93         if(narchdir >= Qmax){
94                 unlock(&archwlock);
95                 print("addarchfile: out of entries for %s\n", name);
96                 return nil;
97         }
98
99         for(i=0; i<narchdir; i++)
100                 if(strcmp(archdir[i].name, name) == 0){
101                         unlock(&archwlock);
102                         return nil;
103                 }
104
105         d.qid.path = narchdir;
106         archdir[narchdir] = d;
107         readfn[narchdir] = rdfn;
108         writefn[narchdir] = wrfn;
109         dp = &archdir[narchdir++];
110         unlock(&archwlock);
111
112         return dp;
113 }
114
115 void
116 ioinit(void)
117 {
118         char *excluded;
119         int i;
120
121         for(i = 0; i < nelem(iomap.maps)-1; i++)
122                 iomap.maps[i].next = &iomap.maps[i+1];
123         iomap.maps[i].next = nil;
124         iomap.free = iomap.maps;
125
126         /*
127          * This is necessary to make the IBM X20 boot.
128          * Have not tracked down the reason.
129          * i82557 is at 0x1000, the dummy entry is needed for swappable devs.
130          */
131         ioalloc(0x0fff, 1, 0, "dummy");
132
133         if ((excluded = getconf("ioexclude")) != nil) {
134                 char *s;
135
136                 s = excluded;
137                 while (s && *s != '\0' && *s != '\n') {
138                         char *ends;
139                         int io_s, io_e;
140
141                         io_s = (int)strtol(s, &ends, 0);
142                         if (ends == nil || ends == s || *ends != '-') {
143                                 print("ioinit: cannot parse option string\n");
144                                 break;
145                         }
146                         s = ++ends;
147
148                         io_e = (int)strtol(s, &ends, 0);
149                         if (ends && *ends == ',')
150                                 *ends++ = '\0';
151                         s = ends;
152
153                         ioalloc(io_s, io_e - io_s + 1, 0, "pre-allocated");
154                 }
155         }
156
157 }
158
159 /*
160  * Reserve a range to be ioalloced later.
161  * This is in particular useful for exchangable cards, such
162  * as pcmcia and cardbus cards.
163  */
164 int
165 ioreserve(int, int size, int align, char *tag)
166 {
167         IOMap *m, **l;
168         int i, port;
169
170         lock(&iomap);
171         /* find a free port above 0x400 and below 0x1000 */
172         port = 0x400;
173         for(l = &iomap.m; *l; l = &(*l)->next){
174                 m = *l;
175                 if (m->start < 0x400) continue;
176                 i = m->start - port;
177                 if(i > size)
178                         break;
179                 if(align > 0)
180                         port = ((port+align-1)/align)*align;
181                 else
182                         port = m->end;
183         }
184         if(*l == nil){
185                 unlock(&iomap);
186                 return -1;
187         }
188         m = iomap.free;
189         if(m == nil){
190                 print("ioalloc: out of maps");
191                 unlock(&iomap);
192                 return port;
193         }
194         iomap.free = m->next;
195         m->next = *l;
196         m->start = port;
197         m->end = port + size;
198         m->reserved = 1;
199         strncpy(m->tag, tag, sizeof(m->tag)-1);
200         m->tag[sizeof(m->tag)-1] = 0;
201         *l = m;
202
203         archdir[0].qid.vers++;
204
205         unlock(&iomap);
206         return m->start;
207 }
208
209 /*
210  *      alloc some io port space and remember who it was
211  *      alloced to.  if port < 0, find a free region.
212  */
213 int
214 ioalloc(int port, int size, int align, char *tag)
215 {
216         IOMap *m, **l;
217         int i;
218
219         lock(&iomap);
220         if(port < 0){
221                 /* find a free port above 0x400 and below 0x1000 */
222                 port = 0x400;
223                 for(l = &iomap.m; (m = *l) != nil; l = &m->next){
224                         if (m->start < 0x400) continue;
225                         i = m->start - port;
226                         if(i > size)
227                                 break;
228                         if(align > 0)
229                                 port = ((port+align-1)/align)*align;
230                         else
231                                 port = m->end;
232                 }
233                 if(m == nil){
234                         unlock(&iomap);
235                         return -1;
236                 }
237         } else {
238                 /* Only 64KB I/O space on the x86. */
239                 if((port+size) > 0x10000){
240                         unlock(&iomap);
241                         return -1;
242                 }
243                 /* see if the space clashes with previously allocated ports */
244                 for(l = &iomap.m; (m = *l) != nil; l = &m->next){
245                         if(m->end <= port)
246                                 continue;
247                         if(m->reserved && m->start == port && m->end >= port + size) {
248                                 m->reserved = 0;
249                                 unlock(&iomap);
250                                 return m->start;
251                         }
252                         if(m->start >= port+size)
253                                 break;
254                         unlock(&iomap);
255                         return -1;
256                 }
257         }
258         m = iomap.free;
259         if(m == nil){
260                 print("ioalloc: out of maps");
261                 unlock(&iomap);
262                 return port;
263         }
264         iomap.free = m->next;
265         m->next = *l;
266         m->start = port;
267         m->end = port + size;
268         strncpy(m->tag, tag, sizeof(m->tag)-1);
269         m->tag[sizeof(m->tag)-1] = 0;
270         *l = m;
271
272         archdir[0].qid.vers++;
273
274         unlock(&iomap);
275         return m->start;
276 }
277
278 void
279 iofree(int port)
280 {
281         IOMap *m, **l;
282
283         lock(&iomap);
284         for(l = &iomap.m; (m = *l) != nil; l = &m->next){
285                 if(m->start == port){
286                         *l = m->next;
287                         m->next = iomap.free;
288                         iomap.free = m;
289                         break;
290                 }
291                 if(m->start > port)
292                         break;
293         }
294         archdir[0].qid.vers++;
295         unlock(&iomap);
296 }
297
298 int
299 iounused(int start, int end)
300 {
301         IOMap *m;
302
303         for(m = iomap.m; m != nil; m = m->next){
304                 if(start >= m->start && start < m->end
305                 || start <= m->start && end > m->start)
306                         return 0;
307         }
308         return 1;
309 }
310
311 static void
312 checkport(int start, int end)
313 {
314         /* standard vga regs are OK */
315         if(start >= 0x2b0 && end <= 0x2df+1)
316                 return;
317         if(start >= 0x3c0 && end <= 0x3da+1)
318                 return;
319
320         if(iounused(start, end))
321                 return;
322         error(Eperm);
323 }
324
325 static Chan*
326 archattach(char* spec)
327 {
328         return devattach('P', spec);
329 }
330
331 Walkqid*
332 archwalk(Chan* c, Chan *nc, char** name, int nname)
333 {
334         return devwalk(c, nc, name, nname, archdir, narchdir, devgen);
335 }
336
337 static int
338 archstat(Chan* c, uchar* dp, int n)
339 {
340         return devstat(c, dp, n, archdir, narchdir, devgen);
341 }
342
343 static Chan*
344 archopen(Chan* c, int omode)
345 {
346         return devopen(c, omode, archdir, narchdir, devgen);
347 }
348
349 static void
350 archclose(Chan*)
351 {
352 }
353
354 static long
355 archread(Chan *c, void *a, long n, vlong offset)
356 {
357         char buf[32], *p;
358         int port, i;
359         ushort *sp;
360         ulong *lp;
361         vlong *vp;
362         IOMap *m;
363         Rdwrfn *fn;
364
365         switch((ulong)c->qid.path){
366         case Qdir:
367                 return devdirread(c, a, n, archdir, narchdir, devgen);
368
369         case Qiob:
370                 port = offset;
371                 checkport(offset, offset+n);
372                 for(p = a; port < offset+n; port++)
373                         *p++ = inb(port);
374                 return n;
375
376         case Qiow:
377                 if(n & 1)
378                         error(Ebadarg);
379                 checkport(offset, offset+n);
380                 sp = a;
381                 for(port = offset; port < offset+n; port += 2)
382                         *sp++ = ins(port);
383                 return n;
384
385         case Qiol:
386                 if(n & 3)
387                         error(Ebadarg);
388                 checkport(offset, offset+n);
389                 lp = a;
390                 for(port = offset; port < offset+n; port += 4)
391                         *lp++ = inl(port);
392                 return n;
393
394         case Qmsr:
395                 if(n & 7)
396                         error(Ebadarg);
397                 vp = a;
398                 for(port = offset; port < offset+n; port += 8)
399                         if(rdmsr(port, vp++) < 0)
400                                 error(Ebadarg);
401                 return n;
402
403         case Qioalloc:
404                 lock(&iomap);
405                 i = 0;
406                 for(m = iomap.m; m != nil; m = m->next){
407                         i = snprint(buf, sizeof(buf), "%8lux %8lux %-12.12s\n", m->start, m->end-1, m->tag);
408                         offset -= i;
409                         if(offset < 0)
410                                 break;
411                 }
412                 unlock(&iomap);
413                 if(offset >= 0)
414                         return 0;
415                 if(n > -offset)
416                         n = -offset;
417                 offset += i;
418                 memmove(a, buf+offset, n);
419                 return n;
420
421         default:
422                 if(c->qid.path < narchdir && (fn = readfn[c->qid.path]))
423                         return fn(c, a, n, offset);
424                 error(Eperm);
425                 return 0;
426         }
427 }
428
429 static long
430 archwrite(Chan *c, void *a, long n, vlong offset)
431 {
432         char *p;
433         int port;
434         ushort *sp;
435         ulong *lp;
436         vlong *vp;
437         Rdwrfn *fn;
438
439         switch((ulong)c->qid.path){
440         case Qiob:
441                 p = a;
442                 checkport(offset, offset+n);
443                 for(port = offset; port < offset+n; port++)
444                         outb(port, *p++);
445                 return n;
446
447         case Qiow:
448                 if(n & 1)
449                         error(Ebadarg);
450                 checkport(offset, offset+n);
451                 sp = a;
452                 for(port = offset; port < offset+n; port += 2)
453                         outs(port, *sp++);
454                 return n;
455
456         case Qiol:
457                 if(n & 3)
458                         error(Ebadarg);
459                 checkport(offset, offset+n);
460                 lp = a;
461                 for(port = offset; port < offset+n; port += 4)
462                         outl(port, *lp++);
463                 return n;
464
465         case Qmsr:
466                 if(n & 7)
467                         error(Ebadarg);
468                 vp = a;
469                 for(port = offset; port < offset+n; port += 8)
470                         if(wrmsr(port, *vp++) < 0)
471                                 error(Ebadarg);
472                 return n;
473
474         default:
475                 if(c->qid.path < narchdir && (fn = writefn[c->qid.path]) != nil)
476                         return fn(c, a, n, offset);
477                 error(Eperm);
478                 break;
479         }
480         return 0;
481 }
482
483 Dev archdevtab = {
484         'P',
485         "arch",
486
487         devreset,
488         devinit,
489         devshutdown,
490         archattach,
491         archwalk,
492         archstat,
493         archopen,
494         devcreate,
495         archclose,
496         archread,
497         devbread,
498         archwrite,
499         devbwrite,
500         devremove,
501         devwstat,
502 };
503
504 /*
505  *  the following is a generic version of the
506  *  architecture specific stuff
507  */
508
509 static int
510 unimplemented(int)
511 {
512         return 0;
513 }
514
515 static void
516 nop(void)
517 {
518 }
519
520 void
521 archreset(void)
522 {
523         i8042reset();
524
525         /*
526          * Often the BIOS hangs during restart if a conventional 8042
527          * warm-boot sequence is tried. The following is Intel specific and
528          * seems to perform a cold-boot, but at least it comes back.
529          * And sometimes there is no keyboard...
530          *
531          * The reset register (0xcf9) is usually in one of the bridge
532          * chips. The actual location and sequence could be extracted from
533          * ACPI but why bother, this is the end of the line anyway.
534          */
535         print("Takes a licking and keeps on ticking...\n");
536         *(ushort*)KADDR(0x472) = 0x1234;        /* BIOS warm-boot flag */
537         outb(0xcf9, 0x02);
538         outb(0xcf9, 0x06);
539
540         print("can't reset\n");
541         for(;;)
542                 idle();
543 }
544
545 /*
546  * 386 has no compare-and-swap instruction.
547  * Run it with interrupts turned off instead.
548  */
549 static int
550 cmpswap386(long *addr, long old, long new)
551 {
552         int r, s;
553
554         s = splhi();
555         if(r = (*addr == old))
556                 *addr = new;
557         splx(s);
558         return r;
559 }
560
561 /*
562  * On a uniprocessor, you'd think that coherence could be nop,
563  * but it can't.  We still need a barrier when using coherence() in
564  * device drivers.
565  *
566  * On VMware, it's safe (and a huge win) to set this to nop.
567  * Aux/vmware does this via the #P/archctl file.
568  */
569 void (*coherence)(void) = nop;
570
571 int (*cmpswap)(long*, long, long) = cmpswap386;
572
573 PCArch* arch;
574 extern PCArch* knownarch[];
575
576 PCArch archgeneric = {
577 .id=            "generic",
578 .ident=         0,
579 .reset=         archreset,
580 .serialpower=   unimplemented,
581 .modempower=    unimplemented,
582
583 .intrinit=      i8259init,
584 .intrenable=    i8259enable,
585 .intrvecno=     i8259vecno,
586 .intrdisable=   i8259disable,
587 .intron=        i8259on,
588 .introff=       i8259off,
589
590 .clockenable=   i8253enable,
591 .fastclock=     i8253read,
592 .timerset=      i8253timerset,
593 };
594
595 typedef struct X86type X86type;
596 struct X86type {
597         int     family;
598         int     model;
599         int     aalcycles;
600         char*   name;
601 };
602
603 static X86type x86intel[] =
604 {
605         { 4,    0,      22,     "486DX", },     /* known chips */
606         { 4,    1,      22,     "486DX50", },
607         { 4,    2,      22,     "486SX", },
608         { 4,    3,      22,     "486DX2", },
609         { 4,    4,      22,     "486SL", },
610         { 4,    5,      22,     "486SX2", },
611         { 4,    7,      22,     "DX2WB", },     /* P24D */
612         { 4,    8,      22,     "DX4", },       /* P24C */
613         { 4,    9,      22,     "DX4WB", },     /* P24CT */
614         { 5,    0,      23,     "P5", },
615         { 5,    1,      23,     "P5", },
616         { 5,    2,      23,     "P54C", },
617         { 5,    3,      23,     "P24T", },
618         { 5,    4,      23,     "P55C MMX", },
619         { 5,    7,      23,     "P54C VRT", },
620         { 6,    1,      16,     "PentiumPro", },/* trial and error */
621         { 6,    3,      16,     "PentiumII", },
622         { 6,    5,      16,     "PentiumII/Xeon", },
623         { 6,    6,      16,     "Celeron", },
624         { 6,    7,      16,     "PentiumIII/Xeon", },
625         { 6,    8,      16,     "PentiumIII/Xeon", },
626         { 6,    0xB,    16,     "PentiumIII/Xeon", },
627         { 6,    0xF,    16,     "Xeon5000-series", },
628         { 6,    0x16,   16,     "Celeron", },
629         { 6,    0x17,   16,     "Core 2/Xeon", },
630         { 6,    0x1A,   16,     "Core i7/Xeon", },
631         { 6,    0x1C,   16,     "Atom", },
632         { 6,    0x1D,   16,     "Xeon MP", },
633         { 0xF,  1,      16,     "P4", },        /* P4 */
634         { 0xF,  2,      16,     "PentiumIV/Xeon", },
635         { 0xF,  6,      16,     "PentiumIV/Xeon", },
636
637         { 3,    -1,     32,     "386", },       /* family defaults */
638         { 4,    -1,     22,     "486", },
639         { 5,    -1,     23,     "P5", },
640         { 6,    -1,     16,     "P6", },
641         { 0xF,  -1,     16,     "P4", },        /* P4 */
642
643         { -1,   -1,     16,     "unknown", },   /* total default */
644 };
645
646 /*
647  * The AMD processors all implement the CPUID instruction.
648  * The later ones also return the processor name via functions
649  * 0x80000002, 0x80000003 and 0x80000004 in registers AX, BX, CX
650  * and DX:
651  *      K5      "AMD-K5(tm) Processor"
652  *      K6      "AMD-K6tm w/ multimedia extensions"
653  *      K6 3D   "AMD-K6(tm) 3D processor"
654  *      K6 3D+  ?
655  */
656 static X86type x86amd[] =
657 {
658         { 5,    0,      23,     "AMD-K5", },    /* guesswork */
659         { 5,    1,      23,     "AMD-K5", },    /* guesswork */
660         { 5,    2,      23,     "AMD-K5", },    /* guesswork */
661         { 5,    3,      23,     "AMD-K5", },    /* guesswork */
662         { 5,    4,      23,     "AMD Geode GX1", },     /* guesswork */
663         { 5,    5,      23,     "AMD Geode GX2", },     /* guesswork */
664         { 5,    6,      11,     "AMD-K6", },    /* trial and error */
665         { 5,    7,      11,     "AMD-K6", },    /* trial and error */
666         { 5,    8,      11,     "AMD-K6-2", },  /* trial and error */
667         { 5,    9,      11,     "AMD-K6-III", },/* trial and error */
668         { 5,    0xa,    23,     "AMD Geode LX", },      /* guesswork */
669
670         { 6,    1,      11,     "AMD-Athlon", },/* trial and error */
671         { 6,    2,      11,     "AMD-Athlon", },/* trial and error */
672
673         { 0x1F, 9,      11,     "AMD-K10 Opteron G34", },/* guesswork */
674
675         { 4,    -1,     22,     "Am486", },     /* guesswork */
676         { 5,    -1,     23,     "AMD-K5/K6", }, /* guesswork */
677         { 6,    -1,     11,     "AMD-Athlon", },/* guesswork */
678         { 0xF,  -1,     11,     "AMD-K8", },    /* guesswork */
679         { 0x1F, -1,     11,     "AMD-K10", },   /* guesswork */
680
681         { -1,   -1,     11,     "unknown", },   /* total default */
682 };
683
684 /*
685  * WinChip 240MHz
686  */
687 static X86type x86winchip[] =
688 {
689         {5,     4,      23,     "Winchip",},    /* guesswork */
690         {6,     7,      23,     "Via C3 Samuel 2 or Ezra",},
691         {6,     8,      23,     "Via C3 Ezra-T",},
692         {6,     9,      23,     "Via C3 Eden-N",},
693         { -1,   -1,     23,     "unknown", },   /* total default */
694 };
695
696 /*
697  * SiS 55x
698  */
699 static X86type x86sis[] =
700 {
701         {5,     0,      23,     "SiS 55x",},    /* guesswork */
702         { -1,   -1,     23,     "unknown", },   /* total default */
703 };
704
705 static X86type *cputype;
706
707 static void     simplecycles(uvlong*);
708 void    (*cycles)(uvlong*) = simplecycles;
709 void    _cycles(uvlong*);       /* in l.s */
710
711 static void
712 simplecycles(uvlong*x)
713 {
714         *x = m->ticks;
715 }
716
717 void
718 cpuidprint(void)
719 {
720         print("cpu%d: %dMHz %s %s (AX %8.8uX CX %8.8uX DX %8.8uX)\n",
721                 m->machno, m->cpumhz, m->cpuidid, m->cpuidtype,
722                 m->cpuidax, m->cpuidcx, m->cpuiddx);
723 }
724
725 /*
726  *  figure out:
727  *      - cpu type
728  *      - whether or not we have a TSC (cycle counter)
729  *      - whether or not it supports page size extensions
730  *              (if so turn it on)
731  *      - whether or not it supports machine check exceptions
732  *              (if so turn it on)
733  *      - whether or not it supports the page global flag
734  *              (if so turn it on)
735  */
736 int
737 cpuidentify(void)
738 {
739         char *p;
740         int family, model, nomce;
741         X86type *t, *tab;
742         uintptr cr4;
743         ulong regs[4];
744         vlong mca, mct;
745
746         cpuid(Highstdfunc, regs);
747         memmove(m->cpuidid,   &regs[1], BY2WD); /* bx */
748         memmove(m->cpuidid+4, &regs[3], BY2WD); /* dx */
749         memmove(m->cpuidid+8, &regs[2], BY2WD); /* cx */
750         m->cpuidid[12] = '\0';
751
752         cpuid(Procsig, regs);
753         m->cpuidax = regs[0];
754         m->cpuidcx = regs[2];
755         m->cpuiddx = regs[3];
756
757         if(strncmp(m->cpuidid, "AuthenticAMD", 12) == 0 ||
758            strncmp(m->cpuidid, "Geode by NSC", 12) == 0)
759                 tab = x86amd;
760         else if(strncmp(m->cpuidid, "CentaurHauls", 12) == 0)
761                 tab = x86winchip;
762         else if(strncmp(m->cpuidid, "SiS SiS SiS ", 12) == 0)
763                 tab = x86sis;
764         else
765                 tab = x86intel;
766
767         family = X86FAMILY(m->cpuidax);
768         model = X86MODEL(m->cpuidax);
769         for(t=tab; t->name; t++)
770                 if((t->family == family && t->model == model)
771                 || (t->family == family && t->model == -1)
772                 || (t->family == -1))
773                         break;
774
775         m->cpuidtype = t->name;
776
777         /*
778          *  if there is one, set tsc to a known value
779          */
780         if(m->cpuiddx & Tsc){
781                 m->havetsc = 1;
782                 cycles = _cycles;
783                 if(m->cpuiddx & Cpumsr)
784                         wrmsr(0x10, 0);
785         }
786
787         /*
788          *  use i8253 to guess our cpu speed
789          */
790         guesscpuhz(t->aalcycles);
791
792         /*
793          * If machine check exception, page size extensions or page global bit
794          * are supported enable them in CR4 and clear any other set extensions.
795          * If machine check was enabled clear out any lingering status.
796          */
797         if(m->cpuiddx & (Pge|Mce|Pse)){
798                 cr4 = getcr4();
799                 if(m->cpuiddx & Pse)
800                         cr4 |= 0x10;            /* page size extensions */
801                 if(p = getconf("*nomce"))
802                         nomce = strtoul(p, 0, 0);
803                 else
804                         nomce = 0;
805                 if((m->cpuiddx & Mce) != 0 && !nomce){
806                         if((m->cpuiddx & Mca) != 0){
807                                 vlong cap;
808                                 int bank;
809
810                                 cap = 0;
811                                 rdmsr(0x179, &cap);
812
813                                 if(cap & 0x100)
814                                         wrmsr(0x17B, ~0ULL);    /* enable all mca features */
815
816                                 bank = cap & 0xFF;
817                                 if(bank > 64)
818                                         bank = 64;
819
820                                 /* init MCi .. MC1 (except MC0) */
821                                 while(--bank > 0){
822                                         wrmsr(0x400 + bank*4, ~0ULL);
823                                         wrmsr(0x401 + bank*4, 0);
824                                 }
825
826                                 if(family != 6 || model >= 0x1A)
827                                         wrmsr(0x400, ~0ULL);
828
829                                 wrmsr(0x401, 0);
830                         }
831                         else if(family == 5){
832                                 rdmsr(0x00, &mca);
833                                 rdmsr(0x01, &mct);
834                         }
835                         cr4 |= 0x40;            /* machine check enable */
836                 }
837
838                 /*
839                  * Detect whether the chip supports the global bit
840                  * in page directory and page table entries.  When set
841                  * in a particular entry, it means ``don't bother removing
842                  * this from the TLB when CR3 changes.''
843                  *
844                  * We flag all kernel pages with this bit.  Doing so lessens the
845                  * overhead of switching processes on bare hardware,
846                  * even more so on VMware.  See mmu.c:/^memglobal.
847                  *
848                  * For future reference, should we ever need to do a
849                  * full TLB flush, it can be accomplished by clearing
850                  * the PGE bit in CR4, writing to CR3, and then
851                  * restoring the PGE bit.
852                  */
853                 if(m->cpuiddx & Pge){
854                         cr4 |= 0x80;            /* page global enable bit */
855                         m->havepge = 1;
856                 }
857
858                 putcr4(cr4);
859
860                 if((m->cpuiddx & (Mca|Mce)) == Mce)
861                         rdmsr(0x01, &mct);
862         }
863
864         if(m->cpuiddx & Mtrr)
865                 mtrrsync();
866
867         if((m->cpuiddx & (Sse|Fxsr)) == (Sse|Fxsr)){                    /* have sse fp? */
868                 fpsave = fpssesave;
869                 fprestore = fpsserestore;
870                 putcr4(getcr4() | CR4Osfxsr|CR4Oxmmex);
871         } else {
872                 fpsave = fpx87save;
873                 fprestore = fpx87restore;
874         }
875
876         if(strcmp(m->cpuidid, "GenuineIntel") == 0 && (m->cpuidcx & Rdrnd) != 0)
877                 hwrandbuf = rdrandbuf;
878         else
879                 hwrandbuf = nil;
880         
881         /* 8-byte watchpoints are supported in Long Mode */
882         if(sizeof(uintptr) == 8)
883                 m->havewatchpt8 = 1;
884         else if(strcmp(m->cpuidid, "GenuineIntel") == 0){
885                 /* some random CPUs that support 8-byte watchpoints */
886                 if(family == 15 && (model == 3 || model == 4 || model == 6)
887                 || family == 6 && (model == 15 || model == 23 || model == 28))
888                         m->havewatchpt8 = 1;
889                 /* Intel SDM claims amd64 support implies 8-byte watchpoint support */
890                 cpuid(Highextfunc, regs);
891                 if(regs[0] >= Procextfeat){
892                         cpuid(Procextfeat, regs);
893                         if((regs[3] & 1<<29) != 0)
894                                 m->havewatchpt8 = 1;
895                 }
896         }
897
898         cputype = t;
899         return t->family;
900 }
901
902 static long
903 cputyperead(Chan*, void *a, long n, vlong offset)
904 {
905         char str[32];
906         ulong mhz;
907
908         mhz = (m->cpuhz+999999)/1000000;
909
910         snprint(str, sizeof(str), "%s %lud\n", cputype->name, mhz);
911         return readstr(offset, a, n, str);
912 }
913
914 static long
915 archctlread(Chan*, void *a, long nn, vlong offset)
916 {
917         int n;
918         char *buf, *p, *ep;
919
920         p = buf = smalloc(READSTR);
921         ep = p + READSTR;
922         p = seprint(p, ep, "cpu %s %lud%s\n",
923                 cputype->name, (ulong)(m->cpuhz+999999)/1000000,
924                 m->havepge ? " pge" : "");
925         p = seprint(p, ep, "pge %s\n", getcr4()&0x80 ? "on" : "off");
926         p = seprint(p, ep, "coherence ");
927         if(coherence == mb386)
928                 p = seprint(p, ep, "mb386\n");
929         else if(coherence == mb586)
930                 p = seprint(p, ep, "mb586\n");
931         else if(coherence == mfence)
932                 p = seprint(p, ep, "mfence\n");
933         else if(coherence == nop)
934                 p = seprint(p, ep, "nop\n");
935         else
936                 p = seprint(p, ep, "0x%p\n", coherence);
937         p = seprint(p, ep, "cmpswap ");
938         if(cmpswap == cmpswap386)
939                 p = seprint(p, ep, "cmpswap386\n");
940         else if(cmpswap == cmpswap486)
941                 p = seprint(p, ep, "cmpswap486\n");
942         else
943                 p = seprint(p, ep, "0x%p\n", cmpswap);
944         p = seprint(p, ep, "arch %s\n", arch->id);
945         n = p - buf;
946         n += mtrrprint(p, ep - p);
947         buf[n] = '\0';
948
949         n = readstr(offset, a, nn, buf);
950         free(buf);
951         return n;
952 }
953
954 enum
955 {
956         CMpge,
957         CMcoherence,
958         CMcache,
959 };
960
961 static Cmdtab archctlmsg[] =
962 {
963         CMpge,          "pge",          2,
964         CMcoherence,    "coherence",    2,
965         CMcache,        "cache",        4,
966 };
967
968 static long
969 archctlwrite(Chan*, void *a, long n, vlong)
970 {
971         uvlong base, size;
972         Cmdbuf *cb;
973         Cmdtab *ct;
974         char *ep;
975
976         cb = parsecmd(a, n);
977         if(waserror()){
978                 free(cb);
979                 nexterror();
980         }
981         ct = lookupcmd(cb, archctlmsg, nelem(archctlmsg));
982         switch(ct->index){
983         case CMpge:
984                 if(!m->havepge)
985                         error("processor does not support pge");
986                 if(strcmp(cb->f[1], "on") == 0)
987                         putcr4(getcr4() | 0x80);
988                 else if(strcmp(cb->f[1], "off") == 0)
989                         putcr4(getcr4() & ~0x80);
990                 else
991                         cmderror(cb, "invalid pge ctl");
992                 break;
993         case CMcoherence:
994                 if(strcmp(cb->f[1], "mb386") == 0)
995                         coherence = mb386;
996                 else if(strcmp(cb->f[1], "mb586") == 0){
997                         if(X86FAMILY(m->cpuidax) < 5)
998                                 error("invalid coherence ctl on this cpu family");
999                         coherence = mb586;
1000                 }else if(strcmp(cb->f[1], "mfence") == 0){
1001                         if((m->cpuiddx & Sse2) == 0)
1002                                 error("invalid coherence ctl on this cpu family");
1003                         coherence = mfence;
1004                 }else if(strcmp(cb->f[1], "nop") == 0){
1005                         /* only safe on vmware */
1006                         if(conf.nmach > 1)
1007                                 error("cannot disable coherence on a multiprocessor");
1008                         coherence = nop;
1009                 }else
1010                         cmderror(cb, "invalid coherence ctl");
1011                 break;
1012         case CMcache:
1013                 base = strtoull(cb->f[1], &ep, 0);
1014                 if(*ep)
1015                         error("cache: parse error: base not a number?");
1016                 size = strtoull(cb->f[2], &ep, 0);
1017                 if(*ep)
1018                         error("cache: parse error: size not a number?");
1019                 ep = mtrr(base, size, cb->f[3]);
1020                 if(ep != nil)
1021                         error(ep);
1022                 break;
1023         }
1024         free(cb);
1025         poperror();
1026         return n;
1027 }
1028
1029 static long
1030 rmemrw(int isr, void *a, long n, vlong off)
1031 {
1032         uintptr addr = off;
1033
1034         if(off < 0 || n < 0)
1035                 error("bad offset/count");
1036         if(isr){
1037                 if(addr >= MB)
1038                         return 0;
1039                 if(addr+n > MB)
1040                         n = MB - addr;
1041                 memmove(a, KADDR(addr), n);
1042         }else{
1043                 /* allow vga framebuf's write access */
1044                 if(addr >= MB || addr+n > MB ||
1045                     (addr < 0xA0000 || addr+n > 0xB0000+0x10000))
1046                         error("bad offset/count in write");
1047                 memmove(KADDR(addr), a, n);
1048         }
1049         return n;
1050 }
1051
1052 static long
1053 rmemread(Chan*, void *a, long n, vlong off)
1054 {
1055         return rmemrw(1, a, n, off);
1056 }
1057
1058 static long
1059 rmemwrite(Chan*, void *a, long n, vlong off)
1060 {
1061         return rmemrw(0, a, n, off);
1062 }
1063
1064 void
1065 archinit(void)
1066 {
1067         PCArch **p;
1068
1069         arch = &archgeneric;
1070         for(p = knownarch; *p != nil; p++){
1071                 if((*p)->ident != nil && (*p)->ident() == 0){
1072                         arch = *p;
1073                         break;
1074                 }
1075         }
1076         if(arch != &archgeneric){
1077                 if(arch->id == nil)
1078                         arch->id = archgeneric.id;
1079                 if(arch->reset == nil)
1080                         arch->reset = archgeneric.reset;
1081                 if(arch->serialpower == nil)
1082                         arch->serialpower = archgeneric.serialpower;
1083                 if(arch->modempower == nil)
1084                         arch->modempower = archgeneric.modempower;
1085                 if(arch->intrinit == nil)
1086                         arch->intrinit = archgeneric.intrinit;
1087                 if(arch->intrenable == nil)
1088                         arch->intrenable = archgeneric.intrenable;
1089         }
1090
1091         /*
1092          *  Decide whether to use copy-on-reference (386 and mp).
1093          *  We get another chance to set it in mpinit() for a
1094          *  multiprocessor.
1095          */
1096         if(X86FAMILY(m->cpuidax) == 3)
1097                 conf.copymode = 1;
1098
1099         if(X86FAMILY(m->cpuidax) >= 4)
1100                 cmpswap = cmpswap486;
1101
1102         if(X86FAMILY(m->cpuidax) >= 5)
1103                 coherence = mb586;
1104
1105         if(m->cpuiddx & Sse2)
1106                 coherence = mfence;
1107
1108         addarchfile("cputype", 0444, cputyperead, nil);
1109         addarchfile("archctl", 0664, archctlread, archctlwrite);
1110         addarchfile("realmodemem", 0660, rmemread, rmemwrite);
1111 }
1112
1113 /*
1114  *  call either the pcmcia or pccard device setup
1115  */
1116 int
1117 pcmspecial(char *idstr, ISAConf *isa)
1118 {
1119         return (_pcmspecial != nil)? _pcmspecial(idstr, isa): -1;
1120 }
1121
1122 /*
1123  *  call either the pcmcia or pccard device teardown
1124  */
1125 void
1126 pcmspecialclose(int a)
1127 {
1128         if (_pcmspecialclose != nil)
1129                 _pcmspecialclose(a);
1130 }
1131
1132 /*
1133  *  return value and speed of timer set in arch->clockenable
1134  */
1135 uvlong
1136 fastticks(uvlong *hz)
1137 {
1138         return (*arch->fastclock)(hz);
1139 }
1140
1141 ulong
1142 µs(void)
1143 {
1144         return fastticks2us((*arch->fastclock)(nil));
1145 }
1146
1147 /*
1148  *  set next timer interrupt
1149  */
1150 void
1151 timerset(Tval x)
1152 {
1153         (*arch->timerset)(x);
1154 }
1155
1156 /*
1157  *  put the processor in the halt state if we've no processes to run.
1158  *  an interrupt will get us going again.
1159  *
1160  *  halting in an smp system can result in a startup latency for
1161  *  processes that become ready.
1162  *  if idle_spin is zero, we care more about saving energy
1163  *  than reducing this latency.
1164  *
1165  *  the performance loss with idle_spin == 0 seems to be slight
1166  *  and it reduces lock contention (thus system time and real time)
1167  *  on many-core systems with large values of NPROC.
1168  */
1169 void
1170 idlehands(void)
1171 {
1172         extern int nrdy, idle_spin;
1173
1174         if(conf.nmach == 1)
1175                 halt();
1176         else if(m->cpuidcx & Monitor)
1177                 mwait(&nrdy);
1178         else if(idle_spin == 0)
1179                 halt();
1180 }
1181
1182 int
1183 isaconfig(char *class, int ctlrno, ISAConf *isa)
1184 {
1185         char cc[32], *p, *x;
1186         int i;
1187
1188         snprint(cc, sizeof cc, "%s%d", class, ctlrno);
1189         p = getconf(cc);
1190         if(p == nil)
1191                 return 0;
1192
1193         x = nil;
1194         kstrdup(&x, p);
1195         p = x;
1196
1197         isa->type = "";
1198         isa->nopt = tokenize(p, isa->opt, NISAOPT);
1199         for(i = 0; i < isa->nopt; i++){
1200                 p = isa->opt[i];
1201                 if(cistrncmp(p, "type=", 5) == 0)
1202                         isa->type = p + 5;
1203                 else if(cistrncmp(p, "port=", 5) == 0)
1204                         isa->port = strtoul(p+5, &p, 0);
1205                 else if(cistrncmp(p, "irq=", 4) == 0)
1206                         isa->irq = strtoul(p+4, &p, 0);
1207                 else if(cistrncmp(p, "dma=", 4) == 0)
1208                         isa->dma = strtoul(p+4, &p, 0);
1209                 else if(cistrncmp(p, "mem=", 4) == 0)
1210                         isa->mem = strtoul(p+4, &p, 0);
1211                 else if(cistrncmp(p, "size=", 5) == 0)
1212                         isa->size = strtoul(p+5, &p, 0);
1213                 else if(cistrncmp(p, "freq=", 5) == 0)
1214                         isa->freq = strtoul(p+5, &p, 0);
1215         }
1216         return 1;
1217 }
1218
1219 void
1220 dumpmcregs(void)
1221 {
1222         vlong v, w;
1223         int bank;
1224
1225         if((m->cpuiddx & (Mce|Cpumsr)) != (Mce|Cpumsr))
1226                 return;
1227         if((m->cpuiddx & Mca) == 0){
1228                 rdmsr(0x00, &v);
1229                 rdmsr(0x01, &w);
1230                 iprint("MCA %8.8llux MCT %8.8llux\n", v, w);
1231                 return;
1232         }
1233         rdmsr(0x179, &v);
1234         rdmsr(0x17A, &w);
1235         iprint("MCG CAP %.16llux STATUS %.16llux\n", v, w);
1236
1237         bank = v & 0xFF;
1238         if(bank > 64)
1239                 bank = 64;
1240         while(--bank >= 0){
1241                 rdmsr(0x401 + bank*4, &v);
1242                 if((v & (1ull << 63)) == 0)
1243                         continue;
1244                 iprint("MC%d STATUS %.16llux", bank, v);
1245                 if(v & (1ull << 58)){
1246                         rdmsr(0x402 + bank*4, &w);
1247                         iprint(" ADDR %.16llux", w);
1248                 }
1249                 if(v & (1ull << 59)){
1250                         rdmsr(0x403 + bank*4, &w);
1251                         iprint(" MISC %.16llux", w);
1252                 }
1253                 iprint("\n");
1254         }
1255 }
1256
1257 void
1258 setupwatchpts(Proc *pr, Watchpt *wp, int nwp)
1259 {
1260         int i;
1261         u8int cfg;
1262         Watchpt *p;
1263
1264         if(nwp > 4)
1265                 error("there are four watchpoints.");
1266         if(nwp == 0){
1267                 memset(pr->dr, 0, sizeof(pr->dr));
1268                 return;
1269         }
1270         for(p = wp; p < wp + nwp; p++){
1271                 switch(p->type){
1272                 case WATCHRD|WATCHWR: case WATCHWR:
1273                         break;
1274                 case WATCHEX:
1275                         if(p->len != 1)
1276                                 error("length must be 1 on breakpoints");
1277                         break;
1278                 default:
1279                         error("type must be rw-, -w- or --x");
1280                 }
1281                 switch(p->len){
1282                 case 1: case 2: case 4:
1283                         break;
1284                 case 8:
1285                         if(m->havewatchpt8) break;
1286                 default:
1287                         error(m->havewatchpt8 ? "length must be 1,2,4,8" : "length must be 1,2,4");
1288                 }
1289                 if((p->addr & p->len - 1) != 0)
1290                         error("address must be aligned according to length");
1291         }
1292         
1293         memset(pr->dr, 0, sizeof(pr->dr));
1294         pr->dr[6] = 0xffff8ff0;
1295         for(i = 0; i < nwp; i++){
1296                 pr->dr[i] = wp[i].addr;
1297                 switch(wp[i].type){
1298                         case WATCHRD|WATCHWR: cfg = 3; break;
1299                         case WATCHWR: cfg = 1; break;
1300                         case WATCHEX: cfg = 0; break;
1301                         default: continue;
1302                 }
1303                 switch(wp[i].len){
1304                         case 1: break;
1305                         case 2: cfg |= 4; break;
1306                         case 4: cfg |= 12; break;
1307                         case 8: cfg |= 8; break;
1308                         default: continue;
1309                 }
1310                 pr->dr[7] |= cfg << 16 + 4 * i;
1311                 pr->dr[7] |= 1 << 2 * i + 1;
1312         }
1313 }