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