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