xref: /plan9/sys/src/9/pc/devarch.c (revision 4e3613ab15c331a9ada113286cc0f2a35bc0373d)
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,   &regs[1], BY2WD);	/* bx */
759 	memmove(m->cpuidid+4, &regs[3], BY2WD);	/* dx */
760 	memmove(m->cpuidid+8, &regs[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