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