]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/devarch.c
Import sources from 2011-03-30 iso image
[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         Qbase,
37
38         Qmax = 16,
39 };
40 enum {                          /* cpuid standard function codes */
41         Highstdfunc = 0,        /* also returns vendor string */
42         Procsig,
43         Proctlbcache,
44         Procserial,
45 };
46
47 typedef long Rdwrfn(Chan*, void*, long, vlong);
48
49 static Rdwrfn *readfn[Qmax];
50 static Rdwrfn *writefn[Qmax];
51
52 static Dirtab archdir[Qmax] = {
53         ".",            { Qdir, 0, QTDIR },     0,      0555,
54         "ioalloc",      { Qioalloc, 0 },        0,      0444,
55         "iob",          { Qiob, 0 },            0,      0660,
56         "iow",          { Qiow, 0 },            0,      0660,
57         "iol",          { Qiol, 0 },            0,      0660,
58 };
59 Lock archwlock; /* the lock is only for changing archdir */
60 int narchdir = Qbase;
61 int (*_pcmspecial)(char*, ISAConf*);
62 void (*_pcmspecialclose)(int);
63
64 static int doi8253set = 1;
65
66 /*
67  * Add a file to the #P listing.  Once added, you can't delete it.
68  * You can't add a file with the same name as one already there,
69  * and you get a pointer to the Dirtab entry so you can do things
70  * like change the Qid version.  Changing the Qid path is disallowed.
71  */
72 Dirtab*
73 addarchfile(char *name, int perm, Rdwrfn *rdfn, Rdwrfn *wrfn)
74 {
75         int i;
76         Dirtab d;
77         Dirtab *dp;
78
79         memset(&d, 0, sizeof d);
80         strcpy(d.name, name);
81         d.perm = perm;
82
83         lock(&archwlock);
84         if(narchdir >= Qmax){
85                 unlock(&archwlock);
86                 return nil;
87         }
88
89         for(i=0; i<narchdir; i++)
90                 if(strcmp(archdir[i].name, name) == 0){
91                         unlock(&archwlock);
92                         return nil;
93                 }
94
95         d.qid.path = narchdir;
96         archdir[narchdir] = d;
97         readfn[narchdir] = rdfn;
98         writefn[narchdir] = wrfn;
99         dp = &archdir[narchdir++];
100         unlock(&archwlock);
101
102         return dp;
103 }
104
105 void
106 ioinit(void)
107 {
108         char *excluded;
109         int i;
110
111         for(i = 0; i < nelem(iomap.maps)-1; i++)
112                 iomap.maps[i].next = &iomap.maps[i+1];
113         iomap.maps[i].next = nil;
114         iomap.free = iomap.maps;
115
116         /*
117          * This is necessary to make the IBM X20 boot.
118          * Have not tracked down the reason.
119          * i82557 is at 0x1000, the dummy entry is needed for swappable devs.
120          */
121         ioalloc(0x0fff, 1, 0, "dummy");
122
123         if ((excluded = getconf("ioexclude")) != nil) {
124                 char *s;
125
126                 s = excluded;
127                 while (s && *s != '\0' && *s != '\n') {
128                         char *ends;
129                         int io_s, io_e;
130
131                         io_s = (int)strtol(s, &ends, 0);
132                         if (ends == nil || ends == s || *ends != '-') {
133                                 print("ioinit: cannot parse option string\n");
134                                 break;
135                         }
136                         s = ++ends;
137
138                         io_e = (int)strtol(s, &ends, 0);
139                         if (ends && *ends == ',')
140                                 *ends++ = '\0';
141                         s = ends;
142
143                         ioalloc(io_s, io_e - io_s + 1, 0, "pre-allocated");
144                 }
145         }
146
147 }
148
149 /*
150  * Reserve a range to be ioalloced later.
151  * This is in particular useful for exchangable cards, such
152  * as pcmcia and cardbus cards.
153  */
154 int
155 ioreserve(int, int size, int align, char *tag)
156 {
157         IOMap *m, **l;
158         int i, port;
159
160         lock(&iomap);
161         /* find a free port above 0x400 and below 0x1000 */
162         port = 0x400;
163         for(l = &iomap.m; *l; l = &(*l)->next){
164                 m = *l;
165                 if (m->start < 0x400) continue;
166                 i = m->start - port;
167                 if(i > size)
168                         break;
169                 if(align > 0)
170                         port = ((port+align-1)/align)*align;
171                 else
172                         port = m->end;
173         }
174         if(*l == nil){
175                 unlock(&iomap);
176                 return -1;
177         }
178         m = iomap.free;
179         if(m == nil){
180                 print("ioalloc: out of maps");
181                 unlock(&iomap);
182                 return port;
183         }
184         iomap.free = m->next;
185         m->next = *l;
186         m->start = port;
187         m->end = port + size;
188         m->reserved = 1;
189         strncpy(m->tag, tag, sizeof(m->tag));
190         m->tag[sizeof(m->tag)-1] = 0;
191         *l = m;
192
193         archdir[0].qid.vers++;
194
195         unlock(&iomap);
196         return m->start;
197 }
198
199 /*
200  *      alloc some io port space and remember who it was
201  *      alloced to.  if port < 0, find a free region.
202  */
203 int
204 ioalloc(int port, int size, int align, char *tag)
205 {
206         IOMap *m, **l;
207         int i;
208
209         lock(&iomap);
210         if(port < 0){
211                 /* find a free port above 0x400 and below 0x1000 */
212                 port = 0x400;
213                 for(l = &iomap.m; *l; l = &(*l)->next){
214                         m = *l;
215                         if (m->start < 0x400) continue;
216                         i = m->start - port;
217                         if(i > size)
218                                 break;
219                         if(align > 0)
220                                 port = ((port+align-1)/align)*align;
221                         else
222                                 port = m->end;
223                 }
224                 if(*l == nil){
225                         unlock(&iomap);
226                         return -1;
227                 }
228         } else {
229                 /* Only 64KB I/O space on the x86. */
230                 if((port+size) > 0x10000){
231                         unlock(&iomap);
232                         return -1;
233                 }
234                 /* see if the space clashes with previously allocated ports */
235                 for(l = &iomap.m; *l; l = &(*l)->next){
236                         m = *l;
237                         if(m->end <= port)
238                                 continue;
239                         if(m->reserved && m->start == port && m->end == port + size) {
240                                 m->reserved = 0;
241                                 unlock(&iomap);
242                                 return m->start;
243                         }
244                         if(m->start >= port+size)
245                                 break;
246                         unlock(&iomap);
247                         return -1;
248                 }
249         }
250         m = iomap.free;
251         if(m == nil){
252                 print("ioalloc: out of maps");
253                 unlock(&iomap);
254                 return port;
255         }
256         iomap.free = m->next;
257         m->next = *l;
258         m->start = port;
259         m->end = port + size;
260         strncpy(m->tag, tag, sizeof(m->tag));
261         m->tag[sizeof(m->tag)-1] = 0;
262         *l = m;
263
264         archdir[0].qid.vers++;
265
266         unlock(&iomap);
267         return m->start;
268 }
269
270 void
271 iofree(int port)
272 {
273         IOMap *m, **l;
274
275         lock(&iomap);
276         for(l = &iomap.m; *l; l = &(*l)->next){
277                 if((*l)->start == port){
278                         m = *l;
279                         *l = m->next;
280                         m->next = iomap.free;
281                         iomap.free = m;
282                         break;
283                 }
284                 if((*l)->start > port)
285                         break;
286         }
287         archdir[0].qid.vers++;
288         unlock(&iomap);
289 }
290
291 int
292 iounused(int start, int end)
293 {
294         IOMap *m;
295
296         for(m = iomap.m; m; m = m->next){
297                 if(start >= m->start && start < m->end
298                 || start <= m->start && end > m->start)
299                         return 0;
300         }
301         return 1;
302 }
303
304 static void
305 checkport(int start, int end)
306 {
307         /* standard vga regs are OK */
308         if(start >= 0x2b0 && end <= 0x2df+1)
309                 return;
310         if(start >= 0x3c0 && end <= 0x3da+1)
311                 return;
312
313         if(iounused(start, end))
314                 return;
315         error(Eperm);
316 }
317
318 static Chan*
319 archattach(char* spec)
320 {
321         return devattach('P', spec);
322 }
323
324 Walkqid*
325 archwalk(Chan* c, Chan *nc, char** name, int nname)
326 {
327         return devwalk(c, nc, name, nname, archdir, narchdir, devgen);
328 }
329
330 static int
331 archstat(Chan* c, uchar* dp, int n)
332 {
333         return devstat(c, dp, n, archdir, narchdir, devgen);
334 }
335
336 static Chan*
337 archopen(Chan* c, int omode)
338 {
339         return devopen(c, omode, archdir, narchdir, devgen);
340 }
341
342 static void
343 archclose(Chan*)
344 {
345 }
346
347 enum
348 {
349         Linelen= 31,
350 };
351
352 static long
353 archread(Chan *c, void *a, long n, vlong offset)
354 {
355         char *buf, *p;
356         int port;
357         ushort *sp;
358         ulong *lp;
359         IOMap *m;
360         Rdwrfn *fn;
361
362         switch((ulong)c->qid.path){
363
364         case Qdir:
365                 return devdirread(c, a, n, archdir, narchdir, devgen);
366
367         case Qiob:
368                 port = offset;
369                 checkport(offset, offset+n);
370                 for(p = a; port < offset+n; port++)
371                         *p++ = inb(port);
372                 return n;
373
374         case Qiow:
375                 if(n & 1)
376                         error(Ebadarg);
377                 checkport(offset, offset+n);
378                 sp = a;
379                 for(port = offset; port < offset+n; port += 2)
380                         *sp++ = ins(port);
381                 return n;
382
383         case Qiol:
384                 if(n & 3)
385                         error(Ebadarg);
386                 checkport(offset, offset+n);
387                 lp = a;
388                 for(port = offset; port < offset+n; port += 4)
389                         *lp++ = inl(port);
390                 return n;
391
392         case Qioalloc:
393                 break;
394
395         default:
396                 if(c->qid.path < narchdir && (fn = readfn[c->qid.path]))
397                         return fn(c, a, n, offset);
398                 error(Eperm);
399                 break;
400         }
401
402         if((buf = malloc(n)) == nil)
403                 error(Enomem);
404         p = buf;
405         n = n/Linelen;
406         offset = offset/Linelen;
407
408         lock(&iomap);
409         for(m = iomap.m; n > 0 && m != nil; m = m->next){
410                 if(offset-- > 0)
411                         continue;
412                 sprint(p, "%8lux %8lux %-12.12s\n", m->start, m->end-1, m->tag);
413                 p += Linelen;
414                 n--;
415         }
416         unlock(&iomap);
417
418         n = p - buf;
419         memmove(a, buf, n);
420         free(buf);
421
422         return n;
423 }
424
425 static long
426 archwrite(Chan *c, void *a, long n, vlong offset)
427 {
428         char *p;
429         int port;
430         ushort *sp;
431         ulong *lp;
432         Rdwrfn *fn;
433
434         switch((ulong)c->qid.path){
435
436         case Qiob:
437                 p = a;
438                 checkport(offset, offset+n);
439                 for(port = offset; port < offset+n; port++)
440                         outb(port, *p++);
441                 return n;
442
443         case Qiow:
444                 if(n & 1)
445                         error(Ebadarg);
446                 checkport(offset, offset+n);
447                 sp = a;
448                 for(port = offset; port < offset+n; port += 2)
449                         outs(port, *sp++);
450                 return n;
451
452         case Qiol:
453                 if(n & 3)
454                         error(Ebadarg);
455                 checkport(offset, offset+n);
456                 lp = a;
457                 for(port = offset; port < offset+n; port += 4)
458                         outl(port, *lp++);
459                 return n;
460
461         default:
462                 if(c->qid.path < narchdir && (fn = writefn[c->qid.path]))
463                         return fn(c, a, n, offset);
464                 error(Eperm);
465                 break;
466         }
467         return 0;
468 }
469
470 Dev archdevtab = {
471         'P',
472         "arch",
473
474         devreset,
475         devinit,
476         devshutdown,
477         archattach,
478         archwalk,
479         archstat,
480         archopen,
481         devcreate,
482         archclose,
483         archread,
484         devbread,
485         archwrite,
486         devbwrite,
487         devremove,
488         devwstat,
489 };
490
491 /*
492  *  the following is a generic version of the
493  *  architecture specific stuff
494  */
495
496 static int
497 unimplemented(int)
498 {
499         return 0;
500 }
501
502 static void
503 nop(void)
504 {
505 }
506
507 static void
508 archreset(void)
509 {
510         i8042reset();
511
512         /*
513          * Often the BIOS hangs during restart if a conventional 8042
514          * warm-boot sequence is tried. The following is Intel specific and
515          * seems to perform a cold-boot, but at least it comes back.
516          * And sometimes there is no keyboard...
517          *
518          * The reset register (0xcf9) is usually in one of the bridge
519          * chips. The actual location and sequence could be extracted from
520          * ACPI but why bother, this is the end of the line anyway.
521          */
522         print("Takes a licking and keeps on ticking...\n");
523         *(ushort*)KADDR(0x472) = 0x1234;        /* BIOS warm-boot flag */
524         outb(0xcf9, 0x02);
525         outb(0xcf9, 0x06);
526
527         for(;;)
528                 idle();
529 }
530
531 /*
532  * 386 has no compare-and-swap instruction.
533  * Run it with interrupts turned off instead.
534  */
535 static int
536 cmpswap386(long *addr, long old, long new)
537 {
538         int r, s;
539
540         s = splhi();
541         if(r = (*addr == old))
542                 *addr = new;
543         splx(s);
544         return r;
545 }
546
547 /*
548  * On a uniprocessor, you'd think that coherence could be nop,
549  * but it can't.  We still need a barrier when using coherence() in
550  * device drivers.
551  *
552  * On VMware, it's safe (and a huge win) to set this to nop.
553  * Aux/vmware does this via the #P/archctl file.
554  */
555 void (*coherence)(void) = nop;
556
557 int (*cmpswap)(long*, long, long) = cmpswap386;
558
559 PCArch* arch;
560 extern PCArch* knownarch[];
561
562 PCArch archgeneric = {
563 .id=            "generic",
564 .ident=         0,
565 .reset=         archreset,
566 .serialpower=   unimplemented,
567 .modempower=    unimplemented,
568
569 .intrinit=      i8259init,
570 .intrenable=    i8259enable,
571 .intrvecno=     i8259vecno,
572 .intrdisable=   i8259disable,
573 .intron=        i8259on,
574 .introff=       i8259off,
575
576 .clockenable=   i8253enable,
577 .fastclock=     i8253read,
578 .timerset=      i8253timerset,
579 };
580
581 typedef struct X86type X86type;
582 struct X86type {
583         int     family;
584         int     model;
585         int     aalcycles;
586         char*   name;
587 };
588
589 static X86type x86intel[] =
590 {
591         { 4,    0,      22,     "486DX", },     /* known chips */
592         { 4,    1,      22,     "486DX50", },
593         { 4,    2,      22,     "486SX", },
594         { 4,    3,      22,     "486DX2", },
595         { 4,    4,      22,     "486SL", },
596         { 4,    5,      22,     "486SX2", },
597         { 4,    7,      22,     "DX2WB", },     /* P24D */
598         { 4,    8,      22,     "DX4", },       /* P24C */
599         { 4,    9,      22,     "DX4WB", },     /* P24CT */
600         { 5,    0,      23,     "P5", },
601         { 5,    1,      23,     "P5", },
602         { 5,    2,      23,     "P54C", },
603         { 5,    3,      23,     "P24T", },
604         { 5,    4,      23,     "P55C MMX", },
605         { 5,    7,      23,     "P54C VRT", },
606         { 6,    1,      16,     "PentiumPro", },/* trial and error */
607         { 6,    3,      16,     "PentiumII", },
608         { 6,    5,      16,     "PentiumII/Xeon", },
609         { 6,    6,      16,     "Celeron", },
610         { 6,    7,      16,     "PentiumIII/Xeon", },
611         { 6,    8,      16,     "PentiumIII/Xeon", },
612         { 6,    0xB,    16,     "PentiumIII/Xeon", },
613         { 6,    0xF,    16,     "Xeon5000-series", },
614         { 6,    0x16,   16,     "Celeron", },
615         { 6,    0x17,   16,     "Core 2/Xeon", },
616         { 6,    0x1A,   16,     "Core i7/Xeon", },
617         { 6,    0x1C,   16,     "Atom", },
618         { 6,    0x1D,   16,     "Xeon MP", },
619         { 0xF,  1,      16,     "P4", },        /* P4 */
620         { 0xF,  2,      16,     "PentiumIV/Xeon", },
621         { 0xF,  6,      16,     "PentiumIV/Xeon", },
622
623         { 3,    -1,     32,     "386", },       /* family defaults */
624         { 4,    -1,     22,     "486", },
625         { 5,    -1,     23,     "P5", },
626         { 6,    -1,     16,     "P6", },
627         { 0xF,  -1,     16,     "P4", },        /* P4 */
628
629         { -1,   -1,     16,     "unknown", },   /* total default */
630 };
631
632 /*
633  * The AMD processors all implement the CPUID instruction.
634  * The later ones also return the processor name via functions
635  * 0x80000002, 0x80000003 and 0x80000004 in registers AX, BX, CX
636  * and DX:
637  *      K5      "AMD-K5(tm) Processor"
638  *      K6      "AMD-K6tm w/ multimedia extensions"
639  *      K6 3D   "AMD-K6(tm) 3D processor"
640  *      K6 3D+  ?
641  */
642 static X86type x86amd[] =
643 {
644         { 5,    0,      23,     "AMD-K5", },    /* guesswork */
645         { 5,    1,      23,     "AMD-K5", },    /* guesswork */
646         { 5,    2,      23,     "AMD-K5", },    /* guesswork */
647         { 5,    3,      23,     "AMD-K5", },    /* guesswork */
648         { 5,    4,      23,     "AMD Geode GX1", },     /* guesswork */
649         { 5,    5,      23,     "AMD Geode GX2", },     /* guesswork */
650         { 5,    6,      11,     "AMD-K6", },    /* trial and error */
651         { 5,    7,      11,     "AMD-K6", },    /* trial and error */
652         { 5,    8,      11,     "AMD-K6-2", },  /* trial and error */
653         { 5,    9,      11,     "AMD-K6-III", },/* trial and error */
654         { 5,    0xa,    23,     "AMD Geode LX", },      /* guesswork */
655
656         { 6,    1,      11,     "AMD-Athlon", },/* trial and error */
657         { 6,    2,      11,     "AMD-Athlon", },/* trial and error */
658
659         { 0x1F, 9,      11,     "AMD-K10 Opteron G34", },/* guesswork */
660
661         { 4,    -1,     22,     "Am486", },     /* guesswork */
662         { 5,    -1,     23,     "AMD-K5/K6", }, /* guesswork */
663         { 6,    -1,     11,     "AMD-Athlon", },/* guesswork */
664         { 0xF,  -1,     11,     "AMD-K8", },    /* guesswork */
665         { 0x1F, -1,     11,     "AMD-K10", },   /* guesswork */
666
667         { -1,   -1,     11,     "unknown", },   /* total default */
668 };
669
670 /*
671  * WinChip 240MHz
672  */
673 static X86type x86winchip[] =
674 {
675         {5,     4,      23,     "Winchip",},    /* guesswork */
676         {6,     7,      23,     "Via C3 Samuel 2 or Ezra",},
677         {6,     8,      23,     "Via C3 Ezra-T",},
678         {6,     9,      23,     "Via C3 Eden-N",},
679         { -1,   -1,     23,     "unknown", },   /* total default */
680 };
681
682 /*
683  * SiS 55x
684  */
685 static X86type x86sis[] =
686 {
687         {5,     0,      23,     "SiS 55x",},    /* guesswork */
688         { -1,   -1,     23,     "unknown", },   /* total default */
689 };
690
691 static X86type *cputype;
692
693 static void     simplecycles(uvlong*);
694 void    (*cycles)(uvlong*) = simplecycles;
695 void    _cycles(uvlong*);       /* in l.s */
696
697 static void
698 simplecycles(uvlong*x)
699 {
700         *x = m->ticks;
701 }
702
703 void
704 cpuidprint(void)
705 {
706         int i;
707         char buf[128];
708
709         i = sprint(buf, "cpu%d: %dMHz ", m->machno, m->cpumhz);
710         if(m->cpuidid[0])
711                 i += sprint(buf+i, "%12.12s ", m->cpuidid);
712         seprint(buf+i, buf + sizeof buf - 1,
713                 "%s (cpuid: AX 0x%4.4uX DX 0x%4.4uX)\n",
714                 m->cpuidtype, m->cpuidax, m->cpuiddx);
715         print(buf);
716 }
717
718 /*
719  *  figure out:
720  *      - cpu type
721  *      - whether or not we have a TSC (cycle counter)
722  *      - whether or not it supports page size extensions
723  *              (if so turn it on)
724  *      - whether or not it supports machine check exceptions
725  *              (if so turn it on)
726  *      - whether or not it supports the page global flag
727  *              (if so turn it on)
728  */
729 int
730 cpuidentify(void)
731 {
732         char *p;
733         int family, model, nomce;
734         X86type *t, *tab;
735         ulong cr4;
736         ulong regs[4];
737         vlong mca, mct;
738
739         cpuid(Highstdfunc, regs);
740         memmove(m->cpuidid,   &regs[1], BY2WD); /* bx */
741         memmove(m->cpuidid+4, &regs[3], BY2WD); /* dx */
742         memmove(m->cpuidid+8, &regs[2], BY2WD); /* cx */
743         m->cpuidid[12] = '\0';
744
745         cpuid(Procsig, regs);
746         m->cpuidax = regs[0];
747         m->cpuiddx = regs[3];
748
749         if(strncmp(m->cpuidid, "AuthenticAMD", 12) == 0 ||
750            strncmp(m->cpuidid, "Geode by NSC", 12) == 0)
751                 tab = x86amd;
752         else if(strncmp(m->cpuidid, "CentaurHauls", 12) == 0)
753                 tab = x86winchip;
754         else if(strncmp(m->cpuidid, "SiS SiS SiS ", 12) == 0)
755                 tab = x86sis;
756         else
757                 tab = x86intel;
758
759         family = X86FAMILY(m->cpuidax);
760         model = X86MODEL(m->cpuidax);
761         for(t=tab; t->name; t++)
762                 if((t->family == family && t->model == model)
763                 || (t->family == family && t->model == -1)
764                 || (t->family == -1))
765                         break;
766
767         m->cpuidtype = t->name;
768
769         /*
770          *  if there is one, set tsc to a known value
771          */
772         if(m->cpuiddx & Tsc){
773                 m->havetsc = 1;
774                 cycles = _cycles;
775                 if(m->cpuiddx & Cpumsr)
776                         wrmsr(0x10, 0);
777         }
778
779         /*
780          *  use i8253 to guess our cpu speed
781          */
782         guesscpuhz(t->aalcycles);
783
784         /*
785          * If machine check exception, page size extensions or page global bit
786          * are supported enable them in CR4 and clear any other set extensions.
787          * If machine check was enabled clear out any lingering status.
788          */
789         if(m->cpuiddx & (Pge|Mce|0x8)){
790                 cr4 = 0;
791                 if(m->cpuiddx & 0x08)
792                         cr4 |= 0x10;            /* page size extensions */
793                 if(p = getconf("*nomce"))
794                         nomce = strtoul(p, 0, 0);
795                 else
796                         nomce = 0;
797                 if((m->cpuiddx & Mce) && !nomce){
798                         cr4 |= 0x40;            /* machine check enable */
799                         if(family == 5){
800                                 rdmsr(0x00, &mca);
801                                 rdmsr(0x01, &mct);
802                         }
803                 }
804
805                 /*
806                  * Detect whether the chip supports the global bit
807                  * in page directory and page table entries.  When set
808                  * in a particular entry, it means ``don't bother removing
809                  * this from the TLB when CR3 changes.''
810                  *
811                  * We flag all kernel pages with this bit.  Doing so lessens the
812                  * overhead of switching processes on bare hardware,
813                  * even more so on VMware.  See mmu.c:/^memglobal.
814                  *
815                  * For future reference, should we ever need to do a
816                  * full TLB flush, it can be accomplished by clearing
817                  * the PGE bit in CR4, writing to CR3, and then
818                  * restoring the PGE bit.
819                  */
820                 if(m->cpuiddx & Pge){
821                         cr4 |= 0x80;            /* page global enable bit */
822                         m->havepge = 1;
823                 }
824
825                 putcr4(cr4);
826                 if(m->cpuiddx & Mce)
827                         rdmsr(0x01, &mct);
828         }
829
830         cputype = t;
831         return t->family;
832 }
833
834 static long
835 cputyperead(Chan*, void *a, long n, vlong offset)
836 {
837         char str[32];
838         ulong mhz;
839
840         mhz = (m->cpuhz+999999)/1000000;
841
842         snprint(str, sizeof(str), "%s %lud\n", cputype->name, mhz);
843         return readstr(offset, a, n, str);
844 }
845
846 static long
847 archctlread(Chan*, void *a, long nn, vlong offset)
848 {
849         int n;
850         char *buf, *p, *ep;
851
852         p = buf = malloc(READSTR);
853         ep = p + READSTR;
854         p = seprint(p, ep, "cpu %s %lud%s\n",
855                 cputype->name, (ulong)(m->cpuhz+999999)/1000000,
856                 m->havepge ? " pge" : "");
857         p = seprint(p, ep, "pge %s\n", getcr4()&0x80 ? "on" : "off");
858         p = seprint(p, ep, "coherence ");
859         if(coherence == mb386)
860                 p = seprint(p, ep, "mb386\n");
861         else if(coherence == mb586)
862                 p = seprint(p, ep, "mb586\n");
863         else if(coherence == mfence)
864                 p = seprint(p, ep, "mfence\n");
865         else if(coherence == nop)
866                 p = seprint(p, ep, "nop\n");
867         else
868                 p = seprint(p, ep, "0x%p\n", coherence);
869         p = seprint(p, ep, "cmpswap ");
870         if(cmpswap == cmpswap386)
871                 p = seprint(p, ep, "cmpswap386\n");
872         else if(cmpswap == cmpswap486)
873                 p = seprint(p, ep, "cmpswap486\n");
874         else
875                 p = seprint(p, ep, "0x%p\n", cmpswap);
876         p = seprint(p, ep, "i8253set %s\n", doi8253set ? "on" : "off");
877         n = p - buf;
878         n += mtrrprint(p, ep - p);
879         buf[n] = '\0';
880
881         n = readstr(offset, a, nn, buf);
882         free(buf);
883         return n;
884 }
885
886 enum
887 {
888         CMpge,
889         CMcoherence,
890         CMi8253set,
891         CMcache,
892 };
893
894 static Cmdtab archctlmsg[] =
895 {
896         CMpge,          "pge",          2,
897         CMcoherence,    "coherence",    2,
898         CMi8253set,     "i8253set",     2,
899         CMcache,                "cache",                4,
900 };
901
902 static long
903 archctlwrite(Chan*, void *a, long n, vlong)
904 {
905         uvlong base, size;
906         Cmdbuf *cb;
907         Cmdtab *ct;
908         char *ep;
909
910         cb = parsecmd(a, n);
911         if(waserror()){
912                 free(cb);
913                 nexterror();
914         }
915         ct = lookupcmd(cb, archctlmsg, nelem(archctlmsg));
916         switch(ct->index){
917         case CMpge:
918                 if(!m->havepge)
919                         error("processor does not support pge");
920                 if(strcmp(cb->f[1], "on") == 0)
921                         putcr4(getcr4() | 0x80);
922                 else if(strcmp(cb->f[1], "off") == 0)
923                         putcr4(getcr4() & ~0x80);
924                 else
925                         cmderror(cb, "invalid pge ctl");
926                 break;
927         case CMcoherence:
928                 if(strcmp(cb->f[1], "mb386") == 0)
929                         coherence = mb386;
930                 else if(strcmp(cb->f[1], "mb586") == 0){
931                         if(X86FAMILY(m->cpuidax) < 5)
932                                 error("invalid coherence ctl on this cpu family");
933                         coherence = mb586;
934                 }else if(strcmp(cb->f[1], "mfence") == 0){
935                         if((m->cpuiddx & Sse2) == 0)
936                                 error("invalid coherence ctl on this cpu family");
937                         coherence = mfence;
938                 }else if(strcmp(cb->f[1], "nop") == 0){
939                         /* only safe on vmware */
940                         if(conf.nmach > 1)
941                                 error("cannot disable coherence on a multiprocessor");
942                         coherence = nop;
943                 }else
944                         cmderror(cb, "invalid coherence ctl");
945                 break;
946         case CMi8253set:
947                 if(strcmp(cb->f[1], "on") == 0)
948                         doi8253set = 1;
949                 else if(strcmp(cb->f[1], "off") == 0){
950                         doi8253set = 0;
951                         (*arch->timerset)(0);
952                 }else
953                         cmderror(cb, "invalid i2853set ctl");
954                 break;
955         case CMcache:
956                 base = strtoull(cb->f[1], &ep, 0);
957                 if(*ep)
958                         error("cache: parse error: base not a number?");
959                 size = strtoull(cb->f[2], &ep, 0);
960                 if(*ep)
961                         error("cache: parse error: size not a number?");
962                 mtrr(base, size, cb->f[3]);
963                 break;
964         }
965         free(cb);
966         poperror();
967         return n;
968 }
969
970 void
971 archinit(void)
972 {
973         PCArch **p;
974
975         arch = 0;
976         for(p = knownarch; *p; p++){
977                 if((*p)->ident && (*p)->ident() == 0){
978                         arch = *p;
979                         break;
980                 }
981         }
982         if(arch == 0)
983                 arch = &archgeneric;
984         else{
985                 if(arch->id == 0)
986                         arch->id = archgeneric.id;
987                 if(arch->reset == 0)
988                         arch->reset = archgeneric.reset;
989                 if(arch->serialpower == 0)
990                         arch->serialpower = archgeneric.serialpower;
991                 if(arch->modempower == 0)
992                         arch->modempower = archgeneric.modempower;
993                 if(arch->intrinit == 0)
994                         arch->intrinit = archgeneric.intrinit;
995                 if(arch->intrenable == 0)
996                         arch->intrenable = archgeneric.intrenable;
997         }
998
999         /*
1000          *  Decide whether to use copy-on-reference (386 and mp).
1001          *  We get another chance to set it in mpinit() for a
1002          *  multiprocessor.
1003          */
1004         if(X86FAMILY(m->cpuidax) == 3)
1005                 conf.copymode = 1;
1006
1007         if(X86FAMILY(m->cpuidax) >= 4)
1008                 cmpswap = cmpswap486;
1009
1010         if(X86FAMILY(m->cpuidax) >= 5)
1011                 coherence = mb586;
1012
1013         if(m->cpuiddx & Sse2)
1014                 coherence = mfence;
1015
1016         addarchfile("cputype", 0444, cputyperead, nil);
1017         addarchfile("archctl", 0664, archctlread, archctlwrite);
1018 }
1019
1020 /*
1021  *  call either the pcmcia or pccard device setup
1022  */
1023 int
1024 pcmspecial(char *idstr, ISAConf *isa)
1025 {
1026         return (_pcmspecial != nil)? _pcmspecial(idstr, isa): -1;
1027 }
1028
1029 /*
1030  *  call either the pcmcia or pccard device teardown
1031  */
1032 void
1033 pcmspecialclose(int a)
1034 {
1035         if (_pcmspecialclose != nil)
1036                 _pcmspecialclose(a);
1037 }
1038
1039 /*
1040  *  return value and speed of timer set in arch->clockenable
1041  */
1042 uvlong
1043 fastticks(uvlong *hz)
1044 {
1045         return (*arch->fastclock)(hz);
1046 }
1047
1048 ulong
1049 µs(void)
1050 {
1051         return fastticks2us((*arch->fastclock)(nil));
1052 }
1053
1054 /*
1055  *  set next timer interrupt
1056  */
1057 void
1058 timerset(Tval x)
1059 {
1060         if(doi8253set)
1061                 (*arch->timerset)(x);
1062 }