FreeBSD/Linux Kernel Cross Reference
sys/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, "Core 2 (Intel 64)", },
615 { 6, 0x17, 16, "Core 2 (Intel 64)", },
616 { 6, 0x1c, 16, "Atom", },
617 { 0xF, 1, 16, "P4", }, /* P4 */
618 { 0xF, 2, 16, "PentiumIV/Xeon", },
619
620 { 3, -1, 32, "386", }, /* family defaults */
621 { 4, -1, 22, "486", },
622 { 5, -1, 23, "P5", },
623 { 6, -1, 16, "P6", },
624 { 0xF, -1, 16, "P4", }, /* P4 */
625
626 { -1, -1, 16, "unknown", }, /* total default */
627 };
628
629 /*
630 * The AMD processors all implement the CPUID instruction.
631 * The later ones also return the processor name via functions
632 * 0x80000002, 0x80000003 and 0x80000004 in registers AX, BX, CX
633 * and DX:
634 * K5 "AMD-K5(tm) Processor"
635 * K6 "AMD-K6tm w/ multimedia extensions"
636 * K6 3D "AMD-K6(tm) 3D processor"
637 * K6 3D+ ?
638 */
639 static X86type x86amd[] =
640 {
641 { 5, 0, 23, "AMD-K5", }, /* guesswork */
642 { 5, 1, 23, "AMD-K5", }, /* guesswork */
643 { 5, 2, 23, "AMD-K5", }, /* guesswork */
644 { 5, 3, 23, "AMD-K5", }, /* guesswork */
645 { 5, 4, 23, "AMD Geode GX1", }, /* guesswork */
646 { 5, 5, 23, "AMD Geode GX2", }, /* guesswork */
647 { 5, 6, 11, "AMD-K6", }, /* trial and error */
648 { 5, 7, 11, "AMD-K6", }, /* trial and error */
649 { 5, 8, 11, "AMD-K6-2", }, /* trial and error */
650 { 5, 9, 11, "AMD-K6-III", },/* trial and error */
651 { 5, 0xa, 23, "AMD Geode LX", }, /* guesswork */
652
653 { 6, 1, 11, "AMD-Athlon", },/* trial and error */
654 { 6, 2, 11, "AMD-Athlon", },/* trial and error */
655
656 { 4, -1, 22, "Am486", }, /* guesswork */
657 { 5, -1, 23, "AMD-K5/K6", }, /* guesswork */
658 { 6, -1, 11, "AMD-Athlon", },/* guesswork */
659 { 0xF, -1, 11, "AMD64", }, /* guesswork */
660
661 { -1, -1, 11, "unknown", }, /* total default */
662 };
663
664 /*
665 * WinChip 240MHz
666 */
667 static X86type x86winchip[] =
668 {
669 {5, 4, 23, "Winchip",}, /* guesswork */
670 {6, 7, 23, "Via C3 Samuel 2 or Ezra",},
671 {6, 8, 23, "Via C3 Ezra-T",},
672 {6, 9, 23, "Via C3 Eden-N",},
673 { -1, -1, 23, "unknown", }, /* total default */
674 };
675
676 /*
677 * SiS 55x
678 */
679 static X86type x86sis[] =
680 {
681 {5, 0, 23, "SiS 55x",}, /* guesswork */
682 { -1, -1, 23, "unknown", }, /* total default */
683 };
684
685 static X86type *cputype;
686
687 static void simplecycles(uvlong*);
688 void (*cycles)(uvlong*) = simplecycles;
689 void _cycles(uvlong*); /* in l.s */
690
691 static void
692 simplecycles(uvlong*x)
693 {
694 *x = m->ticks;
695 }
696
697 void
698 cpuidprint(void)
699 {
700 int i;
701 char buf[128];
702
703 i = sprint(buf, "cpu%d: %dMHz ", m->machno, m->cpumhz);
704 if(m->cpuidid[0])
705 i += sprint(buf+i, "%12.12s ", m->cpuidid);
706 seprint(buf+i, buf + sizeof buf - 1,
707 "%s (cpuid: AX 0x%4.4uX DX 0x%4.4uX)\n",
708 m->cpuidtype, m->cpuidax, m->cpuiddx);
709 print(buf);
710 }
711
712 /*
713 * figure out:
714 * - cpu type
715 * - whether or not we have a TSC (cycle counter)
716 * - whether or not it supports page size extensions
717 * (if so turn it on)
718 * - whether or not it supports machine check exceptions
719 * (if so turn it on)
720 * - whether or not it supports the page global flag
721 * (if so turn it on)
722 */
723 int
724 cpuidentify(void)
725 {
726 char *p;
727 int family, model, nomce;
728 X86type *t, *tab;
729 ulong cr4;
730 ulong regs[4];
731 vlong mca, mct;
732
733 cpuid(Highstdfunc, regs);
734 memmove(m->cpuidid, ®s[1], BY2WD); /* bx */
735 memmove(m->cpuidid+4, ®s[3], BY2WD); /* dx */
736 memmove(m->cpuidid+8, ®s[2], BY2WD); /* cx */
737 m->cpuidid[12] = '\0';
738
739 cpuid(Procsig, regs);
740 m->cpuidax = regs[0];
741 m->cpuiddx = regs[3];
742
743 if(strncmp(m->cpuidid, "AuthenticAMD", 12) == 0 ||
744 strncmp(m->cpuidid, "Geode by NSC", 12) == 0)
745 tab = x86amd;
746 else if(strncmp(m->cpuidid, "CentaurHauls", 12) == 0)
747 tab = x86winchip;
748 else if(strncmp(m->cpuidid, "SiS SiS SiS ", 12) == 0)
749 tab = x86sis;
750 else
751 tab = x86intel;
752
753 family = X86FAMILY(m->cpuidax);
754 model = X86MODEL(m->cpuidax);
755 for(t=tab; t->name; t++)
756 if((t->family == family && t->model == model)
757 || (t->family == family && t->model == -1)
758 || (t->family == -1))
759 break;
760
761 m->cpuidtype = t->name;
762
763 /*
764 * if there is one, set tsc to a known value
765 */
766 if(m->cpuiddx & Tsc){
767 m->havetsc = 1;
768 cycles = _cycles;
769 if(m->cpuiddx & Cpumsr)
770 wrmsr(0x10, 0);
771 }
772
773 /*
774 * use i8253 to guess our cpu speed
775 */
776 guesscpuhz(t->aalcycles);
777
778 /*
779 * If machine check exception, page size extensions or page global bit
780 * are supported enable them in CR4 and clear any other set extensions.
781 * If machine check was enabled clear out any lingering status.
782 */
783 if(m->cpuiddx & (Pge|Mce|0x8)){
784 cr4 = 0;
785 if(m->cpuiddx & 0x08)
786 cr4 |= 0x10; /* page size extensions */
787 if(p = getconf("*nomce"))
788 nomce = strtoul(p, 0, 0);
789 else
790 nomce = 0;
791 if((m->cpuiddx & Mce) && !nomce){
792 cr4 |= 0x40; /* machine check enable */
793 if(family == 5){
794 rdmsr(0x00, &mca);
795 rdmsr(0x01, &mct);
796 }
797 }
798
799 /*
800 * Detect whether the chip supports the global bit
801 * in page directory and page table entries. When set
802 * in a particular entry, it means ``don't bother removing
803 * this from the TLB when CR3 changes.''
804 *
805 * We flag all kernel pages with this bit. Doing so lessens the
806 * overhead of switching processes on bare hardware,
807 * even more so on VMware. See mmu.c:/^memglobal.
808 *
809 * For future reference, should we ever need to do a
810 * full TLB flush, it can be accomplished by clearing
811 * the PGE bit in CR4, writing to CR3, and then
812 * restoring the PGE bit.
813 */
814 if(m->cpuiddx & Pge){
815 cr4 |= 0x80; /* page global enable bit */
816 m->havepge = 1;
817 }
818
819 putcr4(cr4);
820 if(m->cpuiddx & Mce)
821 rdmsr(0x01, &mct);
822 }
823
824 cputype = t;
825 return t->family;
826 }
827
828 static long
829 cputyperead(Chan*, void *a, long n, vlong offset)
830 {
831 char str[32];
832 ulong mhz;
833
834 mhz = (m->cpuhz+999999)/1000000;
835
836 snprint(str, sizeof(str), "%s %lud\n", cputype->name, mhz);
837 return readstr(offset, a, n, str);
838 }
839
840 static long
841 archctlread(Chan*, void *a, long nn, vlong offset)
842 {
843 char buf[256];
844 int n;
845
846 n = snprint(buf, sizeof buf, "cpu %s %lud%s\n",
847 cputype->name, (ulong)(m->cpuhz+999999)/1000000,
848 m->havepge ? " pge" : "");
849 n += snprint(buf+n, sizeof buf-n, "pge %s\n", getcr4()&0x80 ? "on" : "off");
850 n += snprint(buf+n, sizeof buf-n, "coherence ");
851 if(coherence == mb386)
852 n += snprint(buf+n, sizeof buf-n, "mb386\n");
853 else if(coherence == mb586)
854 n += snprint(buf+n, sizeof buf-n, "mb586\n");
855 else if(coherence == mfence)
856 n += snprint(buf+n, sizeof buf-n, "mfence\n");
857 else if(coherence == nop)
858 n += snprint(buf+n, sizeof buf-n, "nop\n");
859 else
860 n += snprint(buf+n, sizeof buf-n, "0x%p\n", coherence);
861 n += snprint(buf+n, sizeof buf-n, "cmpswap ");
862 if(cmpswap == cmpswap386)
863 n += snprint(buf+n, sizeof buf-n, "cmpswap386\n");
864 else if(cmpswap == cmpswap486)
865 n += snprint(buf+n, sizeof buf-n, "cmpswap486\n");
866 else
867 n += snprint(buf+n, sizeof buf-n, "0x%p\n", cmpswap);
868 n += snprint(buf+n, sizeof buf-n, "i8253set %s\n", doi8253set ? "on" : "off");
869 n += mtrrprint(buf+n, sizeof buf-n);
870 buf[n] = 0;
871 return readstr(offset, a, nn, buf);
872 }
873
874 enum
875 {
876 CMpge,
877 CMcoherence,
878 CMi8253set,
879 CMcache,
880 };
881
882 static Cmdtab archctlmsg[] =
883 {
884 CMpge, "pge", 2,
885 CMcoherence, "coherence", 2,
886 CMi8253set, "i8253set", 2,
887 CMcache, "cache", 4,
888 };
889
890 static long
891 archctlwrite(Chan*, void *a, long n, vlong)
892 {
893 Cmdbuf *cb;
894 Cmdtab *ct;
895 uintptr base;
896 ulong size;
897 char *ep;
898
899 cb = parsecmd(a, n);
900 if(waserror()){
901 free(cb);
902 nexterror();
903 }
904 ct = lookupcmd(cb, archctlmsg, nelem(archctlmsg));
905 switch(ct->index){
906 case CMpge:
907 if(!m->havepge)
908 error("processor does not support pge");
909 if(strcmp(cb->f[1], "on") == 0)
910 putcr4(getcr4() | 0x80);
911 else if(strcmp(cb->f[1], "off") == 0)
912 putcr4(getcr4() & ~0x80);
913 else
914 cmderror(cb, "invalid pge ctl");
915 break;
916 case CMcoherence:
917 if(strcmp(cb->f[1], "mb386") == 0)
918 coherence = mb386;
919 else if(strcmp(cb->f[1], "mb586") == 0){
920 if(X86FAMILY(m->cpuidax) < 5)
921 error("invalid coherence ctl on this cpu family");
922 coherence = mb586;
923 }else if(strcmp(cb->f[1], "mfence") == 0){
924 if((m->cpuiddx & Sse2) == 0)
925 error("invalid coherence ctl on this cpu family");
926 coherence = mfence;
927 }else if(strcmp(cb->f[1], "nop") == 0){
928 /* only safe on vmware */
929 if(conf.nmach > 1)
930 error("cannot disable coherence on a multiprocessor");
931 coherence = nop;
932 }else
933 cmderror(cb, "invalid coherence ctl");
934 break;
935 case CMi8253set:
936 if(strcmp(cb->f[1], "on") == 0)
937 doi8253set = 1;
938 else if(strcmp(cb->f[1], "off") == 0){
939 doi8253set = 0;
940 (*arch->timerset)(0);
941 }else
942 cmderror(cb, "invalid i2853set ctl");
943 break;
944 case CMcache:
945 base = strtoul(cb->f[1], &ep, 0);
946 if(*ep)
947 error("cache: parse error: base not a number?");
948 size = strtoul(cb->f[2], &ep, 0);
949 if(*ep)
950 error("cache: parse error: size not a number?");
951 mtrr(base, size, cb->f[3]);
952 break;
953 }
954 free(cb);
955 poperror();
956 return n;
957 }
958
959 void
960 archinit(void)
961 {
962 PCArch **p;
963
964 arch = 0;
965 for(p = knownarch; *p; p++){
966 if((*p)->ident && (*p)->ident() == 0){
967 arch = *p;
968 break;
969 }
970 }
971 if(arch == 0)
972 arch = &archgeneric;
973 else{
974 if(arch->id == 0)
975 arch->id = archgeneric.id;
976 if(arch->reset == 0)
977 arch->reset = archgeneric.reset;
978 if(arch->serialpower == 0)
979 arch->serialpower = archgeneric.serialpower;
980 if(arch->modempower == 0)
981 arch->modempower = archgeneric.modempower;
982 if(arch->intrinit == 0)
983 arch->intrinit = archgeneric.intrinit;
984 if(arch->intrenable == 0)
985 arch->intrenable = archgeneric.intrenable;
986 }
987
988 /*
989 * Decide whether to use copy-on-reference (386 and mp).
990 * We get another chance to set it in mpinit() for a
991 * multiprocessor.
992 */
993 if(X86FAMILY(m->cpuidax) == 3)
994 conf.copymode = 1;
995
996 if(X86FAMILY(m->cpuidax) >= 4)
997 cmpswap = cmpswap486;
998
999 if(X86FAMILY(m->cpuidax) >= 5)
1000 coherence = mb586;
1001
1002 if(m->cpuiddx & Sse2)
1003 coherence = mfence;
1004
1005 addarchfile("cputype", 0444, cputyperead, nil);
1006 addarchfile("archctl", 0664, archctlread, archctlwrite);
1007 }
1008
1009 /*
1010 * call either the pcmcia or pccard device setup
1011 */
1012 int
1013 pcmspecial(char *idstr, ISAConf *isa)
1014 {
1015 return (_pcmspecial != nil)? _pcmspecial(idstr, isa): -1;
1016 }
1017
1018 /*
1019 * call either the pcmcia or pccard device teardown
1020 */
1021 void
1022 pcmspecialclose(int a)
1023 {
1024 if (_pcmspecialclose != nil)
1025 _pcmspecialclose(a);
1026 }
1027
1028 /*
1029 * return value and speed of timer set in arch->clockenable
1030 */
1031 uvlong
1032 fastticks(uvlong *hz)
1033 {
1034 return (*arch->fastclock)(hz);
1035 }
1036
1037 ulong
1038 ยตs(void)
1039 {
1040 return fastticks2us((*arch->fastclock)(nil));
1041 }
1042
1043 /*
1044 * set next timer interrupt
1045 */
1046 void
1047 timerset(Tval x)
1048 {
1049 if(doi8253set)
1050 (*arch->timerset)(x);
1051 }
Cache object: 591a62aa571f284887a97a5ee9429d2f
|