]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/devarch.c
kernel: cleanup the software mouse cursor mess
[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         { 23,   1,      13,     "AMD Ryzen" },
688
689         { -1,   -1,     11,     "unknown", },   /* total default */
690 };
691
692 /*
693  * WinChip 240MHz
694  */
695 static X86type x86winchip[] =
696 {
697         {5,     4,      23,     "Winchip",},    /* guesswork */
698         {6,     7,      23,     "Via C3 Samuel 2 or Ezra",},
699         {6,     8,      23,     "Via C3 Ezra-T",},
700         {6,     9,      23,     "Via C3 Eden-N",},
701         { -1,   -1,     23,     "unknown", },   /* total default */
702 };
703
704 /*
705  * SiS 55x
706  */
707 static X86type x86sis[] =
708 {
709         {5,     0,      23,     "SiS 55x",},    /* guesswork */
710         { -1,   -1,     23,     "unknown", },   /* total default */
711 };
712
713 static X86type *cputype;
714
715 static void     simplecycles(uvlong*);
716 void    (*cycles)(uvlong*) = simplecycles;
717 void    _cycles(uvlong*);       /* in l.s */
718
719 static void
720 simplecycles(uvlong*x)
721 {
722         *x = m->ticks;
723 }
724
725 void
726 cpuidprint(void)
727 {
728         print("cpu%d: %dMHz %s %s (AX %8.8uX CX %8.8uX DX %8.8uX)\n",
729                 m->machno, m->cpumhz, m->cpuidid, m->cpuidtype,
730                 m->cpuidax, m->cpuidcx, m->cpuiddx);
731 }
732
733 /*
734  *  figure out:
735  *      - cpu type
736  *      - whether or not we have a TSC (cycle counter)
737  *      - whether or not it supports page size extensions
738  *              (if so turn it on)
739  *      - whether or not it supports machine check exceptions
740  *              (if so turn it on)
741  *      - whether or not it supports the page global flag
742  *              (if so turn it on)
743  */
744 int
745 cpuidentify(void)
746 {
747         char *p;
748         int family, model, nomce;
749         X86type *t, *tab;
750         uintptr cr4;
751         ulong regs[4];
752         vlong mca, mct;
753
754         cpuid(Highstdfunc, regs);
755         memmove(m->cpuidid,   &regs[1], BY2WD); /* bx */
756         memmove(m->cpuidid+4, &regs[3], BY2WD); /* dx */
757         memmove(m->cpuidid+8, &regs[2], BY2WD); /* cx */
758         m->cpuidid[12] = '\0';
759
760         cpuid(Procsig, regs);
761         m->cpuidax = regs[0];
762         m->cpuidcx = regs[2];
763         m->cpuiddx = regs[3];
764         
765         m->cpuidfamily = m->cpuidax >> 8 & 0xf;
766         m->cpuidmodel = m->cpuidax >> 4 & 0xf;
767         m->cpuidstepping = m->cpuidax & 0xf;
768         switch(m->cpuidfamily){
769         case 15:
770                 m->cpuidfamily += m->cpuidax >> 20 & 0xff;
771                 m->cpuidmodel += m->cpuidax >> 16 & 0xf;
772                 break;
773         case 6:
774                 m->cpuidmodel += m->cpuidax >> 16 & 0xf;
775                 break;
776         }
777
778         if(strncmp(m->cpuidid, "AuthenticAMD", 12) == 0 ||
779            strncmp(m->cpuidid, "Geode by NSC", 12) == 0)
780                 tab = x86amd;
781         else if(strncmp(m->cpuidid, "CentaurHauls", 12) == 0)
782                 tab = x86winchip;
783         else if(strncmp(m->cpuidid, "SiS SiS SiS ", 12) == 0)
784                 tab = x86sis;
785         else
786                 tab = x86intel;
787
788         family = m->cpuidfamily;
789         model = m->cpuidmodel;
790         for(t=tab; t->name; t++)
791                 if((t->family == family && t->model == model)
792                 || (t->family == family && t->model == -1)
793                 || (t->family == -1))
794                         break;
795
796         m->cpuidtype = t->name;
797
798         /*
799          *  if there is one, set tsc to a known value
800          */
801         if(m->cpuiddx & Tsc){
802                 m->havetsc = 1;
803                 cycles = _cycles;
804                 if(m->cpuiddx & Cpumsr)
805                         wrmsr(0x10, 0);
806         }
807
808         /*
809          *  use i8253 to guess our cpu speed
810          */
811         guesscpuhz(t->aalcycles);
812
813         /*
814          * If machine check exception, page size extensions or page global bit
815          * are supported enable them in CR4 and clear any other set extensions.
816          * If machine check was enabled clear out any lingering status.
817          */
818         if(m->cpuiddx & (Pge|Mce|Pse)){
819                 cr4 = getcr4();
820                 if(m->cpuiddx & Pse)
821                         cr4 |= 0x10;            /* page size extensions */
822                 if(p = getconf("*nomce"))
823                         nomce = strtoul(p, 0, 0);
824                 else
825                         nomce = 0;
826                 if((m->cpuiddx & Mce) != 0 && !nomce){
827                         if((m->cpuiddx & Mca) != 0){
828                                 vlong cap;
829                                 int bank;
830
831                                 cap = 0;
832                                 rdmsr(0x179, &cap);
833
834                                 if(cap & 0x100)
835                                         wrmsr(0x17B, ~0ULL);    /* enable all mca features */
836
837                                 bank = cap & 0xFF;
838                                 if(bank > 64)
839                                         bank = 64;
840
841                                 /* init MCi .. MC1 (except MC0) */
842                                 while(--bank > 0){
843                                         wrmsr(0x400 + bank*4, ~0ULL);
844                                         wrmsr(0x401 + bank*4, 0);
845                                 }
846
847                                 if(family != 6 || model >= 0x1A)
848                                         wrmsr(0x400, ~0ULL);
849
850                                 wrmsr(0x401, 0);
851                         }
852                         else if(family == 5){
853                                 rdmsr(0x00, &mca);
854                                 rdmsr(0x01, &mct);
855                         }
856                         cr4 |= 0x40;            /* machine check enable */
857                 }
858
859                 /*
860                  * Detect whether the chip supports the global bit
861                  * in page directory and page table entries.  When set
862                  * in a particular entry, it means ``don't bother removing
863                  * this from the TLB when CR3 changes.''
864                  *
865                  * We flag all kernel pages with this bit.  Doing so lessens the
866                  * overhead of switching processes on bare hardware,
867                  * even more so on VMware.  See mmu.c:/^memglobal.
868                  *
869                  * For future reference, should we ever need to do a
870                  * full TLB flush, it can be accomplished by clearing
871                  * the PGE bit in CR4, writing to CR3, and then
872                  * restoring the PGE bit.
873                  */
874                 if(m->cpuiddx & Pge){
875                         cr4 |= 0x80;            /* page global enable bit */
876                         m->havepge = 1;
877                 }
878
879                 putcr4(cr4);
880
881                 if((m->cpuiddx & (Mca|Mce)) == Mce)
882                         rdmsr(0x01, &mct);
883         }
884
885         if(m->cpuiddx & Mtrr)
886                 mtrrsync();
887
888         if((m->cpuiddx & (Sse|Fxsr)) == (Sse|Fxsr)){                    /* have sse fp? */
889                 fpsave = fpssesave;
890                 fprestore = fpsserestore;
891                 putcr4(getcr4() | CR4Osfxsr|CR4Oxmmex);
892         } else {
893                 fpsave = fpx87save;
894                 fprestore = fpx87restore;
895         }
896
897         if(strcmp(m->cpuidid, "GenuineIntel") == 0 && (m->cpuidcx & Rdrnd) != 0)
898                 hwrandbuf = rdrandbuf;
899         else
900                 hwrandbuf = nil;
901         
902         if(sizeof(uintptr) == 8) {
903                 /* 8-byte watchpoints are supported in Long Mode */
904                 m->havewatchpt8 = 1;
905
906                 /* check and enable NX bit */
907                 cpuid(Highextfunc, regs);
908                 if(regs[0] >= Procextfeat){
909                         cpuid(Procextfeat, regs);
910                         if((regs[3] & (1<<20)) != 0){
911                                 vlong efer;
912
913                                 /* enable no-execute feature */
914                                 if(rdmsr(Efer, &efer) != -1){
915                                         efer |= 1ull<<11;
916                                         if(wrmsr(Efer, efer) != -1)
917                                                 m->havenx = 1;
918                                 }
919                         }
920                 }
921         } else if(strcmp(m->cpuidid, "GenuineIntel") == 0){
922                 /* some random CPUs that support 8-byte watchpoints */
923                 if(family == 15 && (model == 3 || model == 4 || model == 6)
924                 || family == 6 && (model == 15 || model == 23 || model == 28))
925                         m->havewatchpt8 = 1;
926                 /* Intel SDM claims amd64 support implies 8-byte watchpoint support */
927                 cpuid(Highextfunc, regs);
928                 if(regs[0] >= Procextfeat){
929                         cpuid(Procextfeat, regs);
930                         if((regs[3] & 1<<29) != 0)
931                                 m->havewatchpt8 = 1;
932                 }
933         }
934
935         cputype = t;
936         return t->family;
937 }
938
939 static long
940 cputyperead(Chan*, void *a, long n, vlong offset)
941 {
942         char str[32];
943         ulong mhz;
944
945         mhz = (m->cpuhz+999999)/1000000;
946
947         snprint(str, sizeof(str), "%s %lud\n", cputype->name, mhz);
948         return readstr(offset, a, n, str);
949 }
950
951 static long
952 archctlread(Chan*, void *a, long nn, vlong offset)
953 {
954         int n;
955         char *buf, *p, *ep;
956
957         p = buf = smalloc(READSTR);
958         ep = p + READSTR;
959         p = seprint(p, ep, "cpu %s %lud%s\n",
960                 cputype->name, (ulong)(m->cpuhz+999999)/1000000,
961                 m->havepge ? " pge" : "");
962         p = seprint(p, ep, "pge %s\n", getcr4()&0x80 ? "on" : "off");
963         p = seprint(p, ep, "coherence ");
964         if(coherence == mb386)
965                 p = seprint(p, ep, "mb386\n");
966         else if(coherence == mb586)
967                 p = seprint(p, ep, "mb586\n");
968         else if(coherence == mfence)
969                 p = seprint(p, ep, "mfence\n");
970         else if(coherence == nop)
971                 p = seprint(p, ep, "nop\n");
972         else
973                 p = seprint(p, ep, "0x%p\n", coherence);
974         p = seprint(p, ep, "cmpswap ");
975         if(cmpswap == cmpswap386)
976                 p = seprint(p, ep, "cmpswap386\n");
977         else if(cmpswap == cmpswap486)
978                 p = seprint(p, ep, "cmpswap486\n");
979         else
980                 p = seprint(p, ep, "0x%p\n", cmpswap);
981         p = seprint(p, ep, "arch %s\n", arch->id);
982         n = p - buf;
983         n += mtrrprint(p, ep - p);
984         buf[n] = '\0';
985
986         n = readstr(offset, a, nn, buf);
987         free(buf);
988         return n;
989 }
990
991 enum
992 {
993         CMpge,
994         CMcoherence,
995         CMcache,
996 };
997
998 static Cmdtab archctlmsg[] =
999 {
1000         CMpge,          "pge",          2,
1001         CMcoherence,    "coherence",    2,
1002         CMcache,        "cache",        4,
1003 };
1004
1005 static long
1006 archctlwrite(Chan*, void *a, long n, vlong)
1007 {
1008         uvlong base, size;
1009         Cmdbuf *cb;
1010         Cmdtab *ct;
1011         char *ep;
1012
1013         cb = parsecmd(a, n);
1014         if(waserror()){
1015                 free(cb);
1016                 nexterror();
1017         }
1018         ct = lookupcmd(cb, archctlmsg, nelem(archctlmsg));
1019         switch(ct->index){
1020         case CMpge:
1021                 if(!m->havepge)
1022                         error("processor does not support pge");
1023                 if(strcmp(cb->f[1], "on") == 0)
1024                         putcr4(getcr4() | 0x80);
1025                 else if(strcmp(cb->f[1], "off") == 0)
1026                         putcr4(getcr4() & ~0x80);
1027                 else
1028                         cmderror(cb, "invalid pge ctl");
1029                 break;
1030         case CMcoherence:
1031                 if(strcmp(cb->f[1], "mb386") == 0)
1032                         coherence = mb386;
1033                 else if(strcmp(cb->f[1], "mb586") == 0){
1034                         if(m->cpuidfamily < 5)
1035                                 error("invalid coherence ctl on this cpu family");
1036                         coherence = mb586;
1037                 }else if(strcmp(cb->f[1], "mfence") == 0){
1038                         if((m->cpuiddx & Sse2) == 0)
1039                                 error("invalid coherence ctl on this cpu family");
1040                         coherence = mfence;
1041                 }else if(strcmp(cb->f[1], "nop") == 0){
1042                         /* only safe on vmware */
1043                         if(conf.nmach > 1)
1044                                 error("cannot disable coherence on a multiprocessor");
1045                         coherence = nop;
1046                 }else
1047                         cmderror(cb, "invalid coherence ctl");
1048                 break;
1049         case CMcache:
1050                 base = strtoull(cb->f[1], &ep, 0);
1051                 if(*ep)
1052                         error("cache: parse error: base not a number?");
1053                 size = strtoull(cb->f[2], &ep, 0);
1054                 if(*ep)
1055                         error("cache: parse error: size not a number?");
1056                 ep = mtrr(base, size, cb->f[3]);
1057                 if(ep != nil)
1058                         error(ep);
1059                 break;
1060         }
1061         free(cb);
1062         poperror();
1063         return n;
1064 }
1065
1066 static long
1067 rmemrw(int isr, void *a, long n, vlong off)
1068 {
1069         uintptr addr = off;
1070
1071         if(off < 0 || n < 0)
1072                 error("bad offset/count");
1073         if(isr){
1074                 if(addr >= MB)
1075                         return 0;
1076                 if(addr+n > MB)
1077                         n = MB - addr;
1078                 memmove(a, KADDR(addr), n);
1079         }else{
1080                 /* allow vga framebuf's write access */
1081                 if(addr >= MB || addr+n > MB ||
1082                     (addr < 0xA0000 || addr+n > 0xB0000+0x10000))
1083                         error("bad offset/count in write");
1084                 memmove(KADDR(addr), a, n);
1085         }
1086         return n;
1087 }
1088
1089 static long
1090 rmemread(Chan*, void *a, long n, vlong off)
1091 {
1092         return rmemrw(1, a, n, off);
1093 }
1094
1095 static long
1096 rmemwrite(Chan*, void *a, long n, vlong off)
1097 {
1098         return rmemrw(0, a, n, off);
1099 }
1100
1101 void
1102 archinit(void)
1103 {
1104         PCArch **p;
1105
1106         arch = &archgeneric;
1107         for(p = knownarch; *p != nil; p++){
1108                 if((*p)->ident != nil && (*p)->ident() == 0){
1109                         arch = *p;
1110                         break;
1111                 }
1112         }
1113         if(arch != &archgeneric){
1114                 if(arch->id == nil)
1115                         arch->id = archgeneric.id;
1116                 if(arch->reset == nil)
1117                         arch->reset = archgeneric.reset;
1118                 if(arch->serialpower == nil)
1119                         arch->serialpower = archgeneric.serialpower;
1120                 if(arch->modempower == nil)
1121                         arch->modempower = archgeneric.modempower;
1122                 if(arch->intrinit == nil)
1123                         arch->intrinit = archgeneric.intrinit;
1124                 if(arch->intrenable == nil)
1125                         arch->intrenable = archgeneric.intrenable;
1126         }
1127
1128         /*
1129          *  Decide whether to use copy-on-reference (386 and mp).
1130          *  We get another chance to set it in mpinit() for a
1131          *  multiprocessor.
1132          */
1133         if(m->cpuidfamily == 3)
1134                 conf.copymode = 1;
1135
1136         if(m->cpuidfamily >= 4)
1137                 cmpswap = cmpswap486;
1138
1139         if(m->cpuidfamily >= 5)
1140                 coherence = mb586;
1141
1142         if(m->cpuiddx & Sse2)
1143                 coherence = mfence;
1144
1145         addarchfile("cputype", 0444, cputyperead, nil);
1146         addarchfile("archctl", 0664, archctlread, archctlwrite);
1147         addarchfile("realmodemem", 0660, rmemread, rmemwrite);
1148 }
1149
1150 /*
1151  *  call either the pcmcia or pccard device setup
1152  */
1153 int
1154 pcmspecial(char *idstr, ISAConf *isa)
1155 {
1156         return (_pcmspecial != nil)? _pcmspecial(idstr, isa): -1;
1157 }
1158
1159 /*
1160  *  call either the pcmcia or pccard device teardown
1161  */
1162 void
1163 pcmspecialclose(int a)
1164 {
1165         if (_pcmspecialclose != nil)
1166                 _pcmspecialclose(a);
1167 }
1168
1169 /*
1170  *  return value and speed of timer set in arch->clockenable
1171  */
1172 uvlong
1173 fastticks(uvlong *hz)
1174 {
1175         return (*arch->fastclock)(hz);
1176 }
1177
1178 ulong
1179 µs(void)
1180 {
1181         return fastticks2us((*arch->fastclock)(nil));
1182 }
1183
1184 /*
1185  *  set next timer interrupt
1186  */
1187 void
1188 timerset(Tval x)
1189 {
1190         (*arch->timerset)(x);
1191 }
1192
1193 /*
1194  *  put the processor in the halt state if we've no processes to run.
1195  *  an interrupt will get us going again.
1196  *
1197  *  halting in an smp system can result in a startup latency for
1198  *  processes that become ready.
1199  *  if idle_spin is zero, we care more about saving energy
1200  *  than reducing this latency.
1201  *
1202  *  the performance loss with idle_spin == 0 seems to be slight
1203  *  and it reduces lock contention (thus system time and real time)
1204  *  on many-core systems with large values of NPROC.
1205  */
1206 void
1207 idlehands(void)
1208 {
1209         extern int nrdy, idle_spin;
1210
1211         if(conf.nmach == 1)
1212                 halt();
1213         else if(m->cpuidcx & Monitor)
1214                 mwait(&nrdy);
1215         else if(idle_spin == 0)
1216                 halt();
1217 }
1218
1219 int
1220 isaconfig(char *class, int ctlrno, ISAConf *isa)
1221 {
1222         char cc[32], *p, *x;
1223         int i;
1224
1225         snprint(cc, sizeof cc, "%s%d", class, ctlrno);
1226         p = getconf(cc);
1227         if(p == nil)
1228                 return 0;
1229
1230         x = nil;
1231         kstrdup(&x, p);
1232         p = x;
1233
1234         isa->type = "";
1235         isa->nopt = tokenize(p, isa->opt, NISAOPT);
1236         for(i = 0; i < isa->nopt; i++){
1237                 p = isa->opt[i];
1238                 if(cistrncmp(p, "type=", 5) == 0)
1239                         isa->type = p + 5;
1240                 else if(cistrncmp(p, "port=", 5) == 0)
1241                         isa->port = strtoul(p+5, &p, 0);
1242                 else if(cistrncmp(p, "irq=", 4) == 0)
1243                         isa->irq = strtoul(p+4, &p, 0);
1244                 else if(cistrncmp(p, "dma=", 4) == 0)
1245                         isa->dma = strtoul(p+4, &p, 0);
1246                 else if(cistrncmp(p, "mem=", 4) == 0)
1247                         isa->mem = strtoul(p+4, &p, 0);
1248                 else if(cistrncmp(p, "size=", 5) == 0)
1249                         isa->size = strtoul(p+5, &p, 0);
1250                 else if(cistrncmp(p, "freq=", 5) == 0)
1251                         isa->freq = strtoul(p+5, &p, 0);
1252         }
1253         return 1;
1254 }
1255
1256 void
1257 dumpmcregs(void)
1258 {
1259         vlong v, w;
1260         int bank;
1261
1262         if((m->cpuiddx & (Mce|Cpumsr)) != (Mce|Cpumsr))
1263                 return;
1264         if((m->cpuiddx & Mca) == 0){
1265                 rdmsr(0x00, &v);
1266                 rdmsr(0x01, &w);
1267                 iprint("MCA %8.8llux MCT %8.8llux\n", v, w);
1268                 return;
1269         }
1270         rdmsr(0x179, &v);
1271         rdmsr(0x17A, &w);
1272         iprint("MCG CAP %.16llux STATUS %.16llux\n", v, w);
1273
1274         bank = v & 0xFF;
1275         if(bank > 64)
1276                 bank = 64;
1277         while(--bank >= 0){
1278                 rdmsr(0x401 + bank*4, &v);
1279                 if((v & (1ull << 63)) == 0)
1280                         continue;
1281                 iprint("MC%d STATUS %.16llux", bank, v);
1282                 if(v & (1ull << 58)){
1283                         rdmsr(0x402 + bank*4, &w);
1284                         iprint(" ADDR %.16llux", w);
1285                 }
1286                 if(v & (1ull << 59)){
1287                         rdmsr(0x403 + bank*4, &w);
1288                         iprint(" MISC %.16llux", w);
1289                 }
1290                 iprint("\n");
1291         }
1292 }
1293
1294 void
1295 setupwatchpts(Proc *pr, Watchpt *wp, int nwp)
1296 {
1297         int i;
1298         u8int cfg;
1299         Watchpt *p;
1300
1301         if(nwp > 4)
1302                 error("there are four watchpoints.");
1303         if(nwp == 0){
1304                 memset(pr->dr, 0, sizeof(pr->dr));
1305                 return;
1306         }
1307         for(p = wp; p < wp + nwp; p++){
1308                 switch(p->type){
1309                 case WATCHRD|WATCHWR: case WATCHWR:
1310                         break;
1311                 case WATCHEX:
1312                         if(p->len != 1)
1313                                 error("length must be 1 on breakpoints");
1314                         break;
1315                 default:
1316                         error("type must be rw-, -w- or --x");
1317                 }
1318                 switch(p->len){
1319                 case 1: case 2: case 4:
1320                         break;
1321                 case 8:
1322                         if(m->havewatchpt8) break;
1323                 default:
1324                         error(m->havewatchpt8 ? "length must be 1,2,4,8" : "length must be 1,2,4");
1325                 }
1326                 if((p->addr & p->len - 1) != 0)
1327                         error("address must be aligned according to length");
1328         }
1329         
1330         memset(pr->dr, 0, sizeof(pr->dr));
1331         pr->dr[6] = 0xffff8ff0;
1332         for(i = 0; i < nwp; i++){
1333                 pr->dr[i] = wp[i].addr;
1334                 switch(wp[i].type){
1335                         case WATCHRD|WATCHWR: cfg = 3; break;
1336                         case WATCHWR: cfg = 1; break;
1337                         case WATCHEX: cfg = 0; break;
1338                         default: continue;
1339                 }
1340                 switch(wp[i].len){
1341                         case 1: break;
1342                         case 2: cfg |= 4; break;
1343                         case 4: cfg |= 12; break;
1344                         case 8: cfg |= 8; break;
1345                         default: continue;
1346                 }
1347                 pr->dr[7] |= cfg << 16 + 4 * i;
1348                 pr->dr[7] |= 1 << 2 * i + 1;
1349         }
1350 }