xref: /plan9/sys/src/9/pc/devarch.c (revision ff579efb6d9c16f03df7f0fbdbd7810dcb61813e)
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,   &regs[1], BY2WD);	/* bx */
735 	memmove(m->cpuidid+4, &regs[3], BY2WD);	/* dx */
736 	memmove(m->cpuidid+8, &regs[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 	int n;
844 	char *buf, *p, *ep;
845 
846 	p = buf = malloc(READSTR);
847 	ep = p + READSTR;
848 	p = seprint(p, ep, "cpu %s %lud%s\n",
849 		cputype->name, (ulong)(m->cpuhz+999999)/1000000,
850 		m->havepge ? " pge" : "");
851 	p = seprint(p, ep, "pge %s\n", getcr4()&0x80 ? "on" : "off");
852 	p = seprint(p, ep, "coherence ");
853 	if(coherence == mb386)
854 		p = seprint(p, ep, "mb386\n");
855 	else if(coherence == mb586)
856 		p = seprint(p, ep, "mb586\n");
857 	else if(coherence == mfence)
858 		p = seprint(p, ep, "mfence\n");
859 	else if(coherence == nop)
860 		p = seprint(p, ep, "nop\n");
861 	else
862 		p = seprint(p, ep, "0x%p\n", coherence);
863 	p = seprint(p, ep, "cmpswap ");
864 	if(cmpswap == cmpswap386)
865 		p = seprint(p, ep, "cmpswap386\n");
866 	else if(cmpswap == cmpswap486)
867 		p = seprint(p, ep, "cmpswap486\n");
868 	else
869 		p = seprint(p, ep, "0x%p\n", cmpswap);
870 	p = seprint(p, ep, "i8253set %s\n", doi8253set ? "on" : "off");
871 	n = p - buf;
872 	n += mtrrprint(p, ep - p);
873 	buf[n] = '\0';
874 
875 	n = readstr(offset, a, nn, buf);
876 	free(buf);
877 	return n;
878 }
879 
880 enum
881 {
882 	CMpge,
883 	CMcoherence,
884 	CMi8253set,
885 	CMcache,
886 };
887 
888 static Cmdtab archctlmsg[] =
889 {
890 	CMpge,		"pge",		2,
891 	CMcoherence,	"coherence",	2,
892 	CMi8253set,	"i8253set",	2,
893 	CMcache,		"cache",		4,
894 };
895 
896 static long
897 archctlwrite(Chan*, void *a, long n, vlong)
898 {
899 	uvlong base, size;
900 	Cmdbuf *cb;
901 	Cmdtab *ct;
902 	char *ep;
903 
904 	cb = parsecmd(a, n);
905 	if(waserror()){
906 		free(cb);
907 		nexterror();
908 	}
909 	ct = lookupcmd(cb, archctlmsg, nelem(archctlmsg));
910 	switch(ct->index){
911 	case CMpge:
912 		if(!m->havepge)
913 			error("processor does not support pge");
914 		if(strcmp(cb->f[1], "on") == 0)
915 			putcr4(getcr4() | 0x80);
916 		else if(strcmp(cb->f[1], "off") == 0)
917 			putcr4(getcr4() & ~0x80);
918 		else
919 			cmderror(cb, "invalid pge ctl");
920 		break;
921 	case CMcoherence:
922 		if(strcmp(cb->f[1], "mb386") == 0)
923 			coherence = mb386;
924 		else if(strcmp(cb->f[1], "mb586") == 0){
925 			if(X86FAMILY(m->cpuidax) < 5)
926 				error("invalid coherence ctl on this cpu family");
927 			coherence = mb586;
928 		}else if(strcmp(cb->f[1], "mfence") == 0){
929 			if((m->cpuiddx & Sse2) == 0)
930 				error("invalid coherence ctl on this cpu family");
931 			coherence = mfence;
932 		}else if(strcmp(cb->f[1], "nop") == 0){
933 			/* only safe on vmware */
934 			if(conf.nmach > 1)
935 				error("cannot disable coherence on a multiprocessor");
936 			coherence = nop;
937 		}else
938 			cmderror(cb, "invalid coherence ctl");
939 		break;
940 	case CMi8253set:
941 		if(strcmp(cb->f[1], "on") == 0)
942 			doi8253set = 1;
943 		else if(strcmp(cb->f[1], "off") == 0){
944 			doi8253set = 0;
945 			(*arch->timerset)(0);
946 		}else
947 			cmderror(cb, "invalid i2853set ctl");
948 		break;
949 	case CMcache:
950 		base = strtoull(cb->f[1], &ep, 0);
951 		if(*ep)
952 			error("cache: parse error: base not a number?");
953 		size = strtoull(cb->f[2], &ep, 0);
954 		if(*ep)
955 			error("cache: parse error: size not a number?");
956 		mtrr(base, size, cb->f[3]);
957 		break;
958 	}
959 	free(cb);
960 	poperror();
961 	return n;
962 }
963 
964 void
965 archinit(void)
966 {
967 	PCArch **p;
968 
969 	arch = 0;
970 	for(p = knownarch; *p; p++){
971 		if((*p)->ident && (*p)->ident() == 0){
972 			arch = *p;
973 			break;
974 		}
975 	}
976 	if(arch == 0)
977 		arch = &archgeneric;
978 	else{
979 		if(arch->id == 0)
980 			arch->id = archgeneric.id;
981 		if(arch->reset == 0)
982 			arch->reset = archgeneric.reset;
983 		if(arch->serialpower == 0)
984 			arch->serialpower = archgeneric.serialpower;
985 		if(arch->modempower == 0)
986 			arch->modempower = archgeneric.modempower;
987 		if(arch->intrinit == 0)
988 			arch->intrinit = archgeneric.intrinit;
989 		if(arch->intrenable == 0)
990 			arch->intrenable = archgeneric.intrenable;
991 	}
992 
993 	/*
994 	 *  Decide whether to use copy-on-reference (386 and mp).
995 	 *  We get another chance to set it in mpinit() for a
996 	 *  multiprocessor.
997 	 */
998 	if(X86FAMILY(m->cpuidax) == 3)
999 		conf.copymode = 1;
1000 
1001 	if(X86FAMILY(m->cpuidax) >= 4)
1002 		cmpswap = cmpswap486;
1003 
1004 	if(X86FAMILY(m->cpuidax) >= 5)
1005 		coherence = mb586;
1006 
1007 	if(m->cpuiddx & Sse2)
1008 		coherence = mfence;
1009 
1010 	addarchfile("cputype", 0444, cputyperead, nil);
1011 	addarchfile("archctl", 0664, archctlread, archctlwrite);
1012 }
1013 
1014 /*
1015  *  call either the pcmcia or pccard device setup
1016  */
1017 int
1018 pcmspecial(char *idstr, ISAConf *isa)
1019 {
1020 	return (_pcmspecial != nil)? _pcmspecial(idstr, isa): -1;
1021 }
1022 
1023 /*
1024  *  call either the pcmcia or pccard device teardown
1025  */
1026 void
1027 pcmspecialclose(int a)
1028 {
1029 	if (_pcmspecialclose != nil)
1030 		_pcmspecialclose(a);
1031 }
1032 
1033 /*
1034  *  return value and speed of timer set in arch->clockenable
1035  */
1036 uvlong
1037 fastticks(uvlong *hz)
1038 {
1039 	return (*arch->fastclock)(hz);
1040 }
1041 
1042 ulong
1043 µs(void)
1044 {
1045 	return fastticks2us((*arch->fastclock)(nil));
1046 }
1047 
1048 /*
1049  *  set next timer interrupt
1050  */
1051 void
1052 timerset(Tval x)
1053 {
1054 	if(doi8253set)
1055 		(*arch->timerset)(x);
1056 }
1057