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