xref: /plan9/sys/src/9/pc/devarch.c (revision 4e3613ab15c331a9ada113286cc0f2a35bc0373d)
17dd7cddfSDavid du Colombier #include "u.h"
27dd7cddfSDavid du Colombier #include "../port/lib.h"
37dd7cddfSDavid du Colombier #include "mem.h"
47dd7cddfSDavid du Colombier #include "dat.h"
57dd7cddfSDavid du Colombier #include "fns.h"
67dd7cddfSDavid du Colombier #include "io.h"
77dd7cddfSDavid du Colombier #include "ureg.h"
87dd7cddfSDavid du Colombier #include "../port/error.h"
97dd7cddfSDavid du Colombier 
107dd7cddfSDavid du Colombier typedef struct IOMap IOMap;
117dd7cddfSDavid du Colombier struct IOMap
127dd7cddfSDavid du Colombier {
137dd7cddfSDavid du Colombier 	IOMap	*next;
149a747e4fSDavid du Colombier 	int	reserved;
157dd7cddfSDavid du Colombier 	char	tag[13];
167dd7cddfSDavid du Colombier 	ulong	start;
177dd7cddfSDavid du Colombier 	ulong	end;
187dd7cddfSDavid du Colombier };
197dd7cddfSDavid du Colombier 
207dd7cddfSDavid du Colombier static struct
217dd7cddfSDavid du Colombier {
227dd7cddfSDavid du Colombier 	Lock;
237dd7cddfSDavid du Colombier 	IOMap	*m;
247dd7cddfSDavid du Colombier 	IOMap	*free;
2541dd6b47SDavid du Colombier 	IOMap	maps[32];	/* some initial free maps */
267dd7cddfSDavid du Colombier 
2741dd6b47SDavid du Colombier 	QLock	ql;		/* lock for reading map */
287dd7cddfSDavid du Colombier } iomap;
297dd7cddfSDavid du Colombier 
307dd7cddfSDavid du Colombier enum {
319a747e4fSDavid du Colombier 	Qdir = 0,
329a747e4fSDavid du Colombier 	Qioalloc = 1,
337dd7cddfSDavid du Colombier 	Qiob,
347dd7cddfSDavid du Colombier 	Qiow,
357dd7cddfSDavid du Colombier 	Qiol,
3680ee5cbfSDavid du Colombier 	Qbase,
3780ee5cbfSDavid du Colombier 
3880ee5cbfSDavid du Colombier 	Qmax = 16,
397dd7cddfSDavid du Colombier };
4091e577b2SDavid du Colombier 
4191e577b2SDavid du Colombier enum {
4291e577b2SDavid du Colombier 	CR4Osfxsr = 1 << 9,
4391e577b2SDavid du Colombier };
4491e577b2SDavid du Colombier 
4526d1d1dfSDavid du Colombier enum {				/* cpuid standard function codes */
4626d1d1dfSDavid du Colombier 	Highstdfunc = 0,	/* also returns vendor string */
4726d1d1dfSDavid du Colombier 	Procsig,
4826d1d1dfSDavid du Colombier 	Proctlbcache,
4926d1d1dfSDavid du Colombier 	Procserial,
5026d1d1dfSDavid du Colombier };
517dd7cddfSDavid du Colombier 
5280ee5cbfSDavid du Colombier typedef long Rdwrfn(Chan*, void*, long, vlong);
5380ee5cbfSDavid du Colombier 
5480ee5cbfSDavid du Colombier static Rdwrfn *readfn[Qmax];
5580ee5cbfSDavid du Colombier static Rdwrfn *writefn[Qmax];
5680ee5cbfSDavid du Colombier 
5780ee5cbfSDavid du Colombier static Dirtab archdir[Qmax] = {
589a747e4fSDavid du Colombier 	".",		{ Qdir, 0, QTDIR },	0,	0555,
597dd7cddfSDavid du Colombier 	"ioalloc",	{ Qioalloc, 0 },	0,	0444,
607dd7cddfSDavid du Colombier 	"iob",		{ Qiob, 0 },		0,	0660,
617dd7cddfSDavid du Colombier 	"iow",		{ Qiow, 0 },		0,	0660,
627dd7cddfSDavid du Colombier 	"iol",		{ Qiol, 0 },		0,	0660,
637dd7cddfSDavid du Colombier };
6480ee5cbfSDavid du Colombier Lock archwlock;	/* the lock is only for changing archdir */
6580ee5cbfSDavid du Colombier int narchdir = Qbase;
669a747e4fSDavid du Colombier int (*_pcmspecial)(char*, ISAConf*);
679a747e4fSDavid du Colombier void (*_pcmspecialclose)(int);
689a747e4fSDavid du Colombier 
69ed250ae1SDavid du Colombier static int doi8253set = 1;
7080ee5cbfSDavid du Colombier 
7180ee5cbfSDavid du Colombier /*
7280ee5cbfSDavid du Colombier  * Add a file to the #P listing.  Once added, you can't delete it.
7380ee5cbfSDavid du Colombier  * You can't add a file with the same name as one already there,
7480ee5cbfSDavid du Colombier  * and you get a pointer to the Dirtab entry so you can do things
7580ee5cbfSDavid du Colombier  * like change the Qid version.  Changing the Qid path is disallowed.
7680ee5cbfSDavid du Colombier  */
7780ee5cbfSDavid du Colombier Dirtab*
addarchfile(char * name,int perm,Rdwrfn * rdfn,Rdwrfn * wrfn)7880ee5cbfSDavid du Colombier addarchfile(char *name, int perm, Rdwrfn *rdfn, Rdwrfn *wrfn)
7980ee5cbfSDavid du Colombier {
8080ee5cbfSDavid du Colombier 	int i;
8180ee5cbfSDavid du Colombier 	Dirtab d;
8280ee5cbfSDavid du Colombier 	Dirtab *dp;
8380ee5cbfSDavid du Colombier 
8480ee5cbfSDavid du Colombier 	memset(&d, 0, sizeof d);
8580ee5cbfSDavid du Colombier 	strcpy(d.name, name);
8680ee5cbfSDavid du Colombier 	d.perm = perm;
8780ee5cbfSDavid du Colombier 
8880ee5cbfSDavid du Colombier 	lock(&archwlock);
8980ee5cbfSDavid du Colombier 	if(narchdir >= Qmax){
9080ee5cbfSDavid du Colombier 		unlock(&archwlock);
9180ee5cbfSDavid du Colombier 		return nil;
9280ee5cbfSDavid du Colombier 	}
9380ee5cbfSDavid du Colombier 
9480ee5cbfSDavid du Colombier 	for(i=0; i<narchdir; i++)
9580ee5cbfSDavid du Colombier 		if(strcmp(archdir[i].name, name) == 0){
9680ee5cbfSDavid du Colombier 			unlock(&archwlock);
9780ee5cbfSDavid du Colombier 			return nil;
9880ee5cbfSDavid du Colombier 		}
9980ee5cbfSDavid du Colombier 
10080ee5cbfSDavid du Colombier 	d.qid.path = narchdir;
10180ee5cbfSDavid du Colombier 	archdir[narchdir] = d;
10280ee5cbfSDavid du Colombier 	readfn[narchdir] = rdfn;
10380ee5cbfSDavid du Colombier 	writefn[narchdir] = wrfn;
10480ee5cbfSDavid du Colombier 	dp = &archdir[narchdir++];
10580ee5cbfSDavid du Colombier 	unlock(&archwlock);
10680ee5cbfSDavid du Colombier 
10780ee5cbfSDavid du Colombier 	return dp;
10880ee5cbfSDavid du Colombier }
1097dd7cddfSDavid du Colombier 
1107dd7cddfSDavid du Colombier void
ioinit(void)1117dd7cddfSDavid du Colombier ioinit(void)
1127dd7cddfSDavid du Colombier {
1139a747e4fSDavid du Colombier 	char *excluded;
1147dd7cddfSDavid du Colombier 	int i;
1157dd7cddfSDavid du Colombier 
1167dd7cddfSDavid du Colombier 	for(i = 0; i < nelem(iomap.maps)-1; i++)
1177dd7cddfSDavid du Colombier 		iomap.maps[i].next = &iomap.maps[i+1];
1187dd7cddfSDavid du Colombier 	iomap.maps[i].next = nil;
1197dd7cddfSDavid du Colombier 	iomap.free = iomap.maps;
1207dd7cddfSDavid du Colombier 
121ef9eff0bSDavid du Colombier 	/*
122e40528acSDavid du Colombier 	 * This is necessary to make the IBM X20 boot.
123e40528acSDavid du Colombier 	 * Have not tracked down the reason.
12441dd6b47SDavid du Colombier 	 * i82557 is at 0x1000, the dummy entry is needed for swappable devs.
125dc5a79c1SDavid du Colombier 	 */
12641dd6b47SDavid du Colombier 	ioalloc(0x0fff, 1, 0, "dummy");
1279a747e4fSDavid du Colombier 
1289a747e4fSDavid du Colombier 	if ((excluded = getconf("ioexclude")) != nil) {
1299a747e4fSDavid du Colombier 		char *s;
1309a747e4fSDavid du Colombier 
1319a747e4fSDavid du Colombier 		s = excluded;
1329a747e4fSDavid du Colombier 		while (s && *s != '\0' && *s != '\n') {
1339a747e4fSDavid du Colombier 			char *ends;
1349a747e4fSDavid du Colombier 			int io_s, io_e;
1359a747e4fSDavid du Colombier 
1369a747e4fSDavid du Colombier 			io_s = (int)strtol(s, &ends, 0);
1379a747e4fSDavid du Colombier 			if (ends == nil || ends == s || *ends != '-') {
1389a747e4fSDavid du Colombier 				print("ioinit: cannot parse option string\n");
1399a747e4fSDavid du Colombier 				break;
1409a747e4fSDavid du Colombier 			}
1419a747e4fSDavid du Colombier 			s = ++ends;
1429a747e4fSDavid du Colombier 
1439a747e4fSDavid du Colombier 			io_e = (int)strtol(s, &ends, 0);
1449a747e4fSDavid du Colombier 			if (ends && *ends == ',')
1459a747e4fSDavid du Colombier 				*ends++ = '\0';
1469a747e4fSDavid du Colombier 			s = ends;
1479a747e4fSDavid du Colombier 
1489a747e4fSDavid du Colombier 			ioalloc(io_s, io_e - io_s + 1, 0, "pre-allocated");
1499a747e4fSDavid du Colombier 		}
1509a747e4fSDavid du Colombier 	}
1519a747e4fSDavid du Colombier 
1529a747e4fSDavid du Colombier }
1539a747e4fSDavid du Colombier 
15441dd6b47SDavid du Colombier /*
15541dd6b47SDavid du Colombier  * Reserve a range to be ioalloced later.
15641dd6b47SDavid du Colombier  * This is in particular useful for exchangable cards, such
15741dd6b47SDavid du Colombier  * as pcmcia and cardbus cards.
15841dd6b47SDavid du Colombier  */
1599a747e4fSDavid du Colombier int
ioreserve(int,int size,int align,char * tag)1605d82c6aeSDavid du Colombier ioreserve(int, int size, int align, char *tag)
1619a747e4fSDavid du Colombier {
1629a747e4fSDavid du Colombier 	IOMap *m, **l;
1635d82c6aeSDavid du Colombier 	int i, port;
1649a747e4fSDavid du Colombier 
1659a747e4fSDavid du Colombier 	lock(&iomap);
16641dd6b47SDavid du Colombier 	/* find a free port above 0x400 and below 0x1000 */
1679a747e4fSDavid du Colombier 	port = 0x400;
1689a747e4fSDavid du Colombier 	for(l = &iomap.m; *l; l = &(*l)->next){
1699a747e4fSDavid du Colombier 		m = *l;
1709a747e4fSDavid du Colombier 		if (m->start < 0x400) continue;
1719a747e4fSDavid du Colombier 		i = m->start - port;
1729a747e4fSDavid du Colombier 		if(i > size)
1739a747e4fSDavid du Colombier 			break;
1749a747e4fSDavid du Colombier 		if(align > 0)
1759a747e4fSDavid du Colombier 			port = ((port+align-1)/align)*align;
1769a747e4fSDavid du Colombier 		else
1779a747e4fSDavid du Colombier 			port = m->end;
1789a747e4fSDavid du Colombier 	}
1799a747e4fSDavid du Colombier 	if(*l == nil){
1809a747e4fSDavid du Colombier 		unlock(&iomap);
1819a747e4fSDavid du Colombier 		return -1;
1829a747e4fSDavid du Colombier 	}
1839a747e4fSDavid du Colombier 	m = iomap.free;
1849a747e4fSDavid du Colombier 	if(m == nil){
1859a747e4fSDavid du Colombier 		print("ioalloc: out of maps");
1869a747e4fSDavid du Colombier 		unlock(&iomap);
1879a747e4fSDavid du Colombier 		return port;
1889a747e4fSDavid du Colombier 	}
1899a747e4fSDavid du Colombier 	iomap.free = m->next;
1909a747e4fSDavid du Colombier 	m->next = *l;
1919a747e4fSDavid du Colombier 	m->start = port;
1929a747e4fSDavid du Colombier 	m->end = port + size;
1939a747e4fSDavid du Colombier 	m->reserved = 1;
1949a747e4fSDavid du Colombier 	strncpy(m->tag, tag, sizeof(m->tag));
1959a747e4fSDavid du Colombier 	m->tag[sizeof(m->tag)-1] = 0;
1969a747e4fSDavid du Colombier 	*l = m;
1979a747e4fSDavid du Colombier 
1989a747e4fSDavid du Colombier 	archdir[0].qid.vers++;
1999a747e4fSDavid du Colombier 
2009a747e4fSDavid du Colombier 	unlock(&iomap);
2019a747e4fSDavid du Colombier 	return m->start;
2027dd7cddfSDavid du Colombier }
2037dd7cddfSDavid du Colombier 
20441dd6b47SDavid du Colombier /*
20541dd6b47SDavid du Colombier  *	alloc some io port space and remember who it was
20641dd6b47SDavid du Colombier  *	alloced to.  if port < 0, find a free region.
20741dd6b47SDavid du Colombier  */
2087dd7cddfSDavid du Colombier int
ioalloc(int port,int size,int align,char * tag)2097dd7cddfSDavid du Colombier ioalloc(int port, int size, int align, char *tag)
2107dd7cddfSDavid du Colombier {
2117dd7cddfSDavid du Colombier 	IOMap *m, **l;
2127dd7cddfSDavid du Colombier 	int i;
2137dd7cddfSDavid du Colombier 
2147dd7cddfSDavid du Colombier 	lock(&iomap);
2157dd7cddfSDavid du Colombier 	if(port < 0){
21641dd6b47SDavid du Colombier 		/* find a free port above 0x400 and below 0x1000 */
2177dd7cddfSDavid du Colombier 		port = 0x400;
2187dd7cddfSDavid du Colombier 		for(l = &iomap.m; *l; l = &(*l)->next){
2197dd7cddfSDavid du Colombier 			m = *l;
2209a747e4fSDavid du Colombier 			if (m->start < 0x400) continue;
2217dd7cddfSDavid du Colombier 			i = m->start - port;
2227dd7cddfSDavid du Colombier 			if(i > size)
2237dd7cddfSDavid du Colombier 				break;
2247dd7cddfSDavid du Colombier 			if(align > 0)
2257dd7cddfSDavid du Colombier 				port = ((port+align-1)/align)*align;
2267dd7cddfSDavid du Colombier 			else
2277dd7cddfSDavid du Colombier 				port = m->end;
2287dd7cddfSDavid du Colombier 		}
2297dd7cddfSDavid du Colombier 		if(*l == nil){
2307dd7cddfSDavid du Colombier 			unlock(&iomap);
2317dd7cddfSDavid du Colombier 			return -1;
2327dd7cddfSDavid du Colombier 		}
2337dd7cddfSDavid du Colombier 	} else {
23441dd6b47SDavid du Colombier 		/* Only 64KB I/O space on the x86. */
235ed250ae1SDavid du Colombier 		if((port+size) > 0x10000){
2369a747e4fSDavid du Colombier 			unlock(&iomap);
2379a747e4fSDavid du Colombier 			return -1;
2389a747e4fSDavid du Colombier 		}
23941dd6b47SDavid du Colombier 		/* see if the space clashes with previously allocated ports */
2407dd7cddfSDavid du Colombier 		for(l = &iomap.m; *l; l = &(*l)->next){
2417dd7cddfSDavid du Colombier 			m = *l;
2427dd7cddfSDavid du Colombier 			if(m->end <= port)
2437dd7cddfSDavid du Colombier 				continue;
2449a747e4fSDavid du Colombier 			if(m->reserved && m->start == port && m->end == port + size) {
2459a747e4fSDavid du Colombier 				m->reserved = 0;
2469a747e4fSDavid du Colombier 				unlock(&iomap);
2479a747e4fSDavid du Colombier 				return m->start;
2489a747e4fSDavid du Colombier 			}
2497dd7cddfSDavid du Colombier 			if(m->start >= port+size)
2507dd7cddfSDavid du Colombier 				break;
2517dd7cddfSDavid du Colombier 			unlock(&iomap);
2527dd7cddfSDavid du Colombier 			return -1;
2537dd7cddfSDavid du Colombier 		}
2547dd7cddfSDavid du Colombier 	}
2557dd7cddfSDavid du Colombier 	m = iomap.free;
2567dd7cddfSDavid du Colombier 	if(m == nil){
2577dd7cddfSDavid du Colombier 		print("ioalloc: out of maps");
2587dd7cddfSDavid du Colombier 		unlock(&iomap);
2597dd7cddfSDavid du Colombier 		return port;
2607dd7cddfSDavid du Colombier 	}
2617dd7cddfSDavid du Colombier 	iomap.free = m->next;
2627dd7cddfSDavid du Colombier 	m->next = *l;
2637dd7cddfSDavid du Colombier 	m->start = port;
2647dd7cddfSDavid du Colombier 	m->end = port + size;
2657dd7cddfSDavid du Colombier 	strncpy(m->tag, tag, sizeof(m->tag));
2667dd7cddfSDavid du Colombier 	m->tag[sizeof(m->tag)-1] = 0;
2677dd7cddfSDavid du Colombier 	*l = m;
2687dd7cddfSDavid du Colombier 
26980ee5cbfSDavid du Colombier 	archdir[0].qid.vers++;
2707dd7cddfSDavid du Colombier 
2717dd7cddfSDavid du Colombier 	unlock(&iomap);
2727dd7cddfSDavid du Colombier 	return m->start;
2737dd7cddfSDavid du Colombier }
2747dd7cddfSDavid du Colombier 
2757dd7cddfSDavid du Colombier void
iofree(int port)2767dd7cddfSDavid du Colombier iofree(int port)
2777dd7cddfSDavid du Colombier {
2787dd7cddfSDavid du Colombier 	IOMap *m, **l;
2797dd7cddfSDavid du Colombier 
2807dd7cddfSDavid du Colombier 	lock(&iomap);
2817dd7cddfSDavid du Colombier 	for(l = &iomap.m; *l; l = &(*l)->next){
2827dd7cddfSDavid du Colombier 		if((*l)->start == port){
2837dd7cddfSDavid du Colombier 			m = *l;
2847dd7cddfSDavid du Colombier 			*l = m->next;
2857dd7cddfSDavid du Colombier 			m->next = iomap.free;
2867dd7cddfSDavid du Colombier 			iomap.free = m;
2877dd7cddfSDavid du Colombier 			break;
2887dd7cddfSDavid du Colombier 		}
2897dd7cddfSDavid du Colombier 		if((*l)->start > port)
2907dd7cddfSDavid du Colombier 			break;
2917dd7cddfSDavid du Colombier 	}
29280ee5cbfSDavid du Colombier 	archdir[0].qid.vers++;
2937dd7cddfSDavid du Colombier 	unlock(&iomap);
2947dd7cddfSDavid du Colombier }
2957dd7cddfSDavid du Colombier 
2967dd7cddfSDavid du Colombier int
iounused(int start,int end)2977dd7cddfSDavid du Colombier iounused(int start, int end)
2987dd7cddfSDavid du Colombier {
2997dd7cddfSDavid du Colombier 	IOMap *m;
3007dd7cddfSDavid du Colombier 
3017dd7cddfSDavid du Colombier 	for(m = iomap.m; m; m = m->next){
3027dd7cddfSDavid du Colombier 		if(start >= m->start && start < m->end
3037dd7cddfSDavid du Colombier 		|| start <= m->start && end > m->start)
3047dd7cddfSDavid du Colombier 			return 0;
3057dd7cddfSDavid du Colombier 	}
3067dd7cddfSDavid du Colombier 	return 1;
3077dd7cddfSDavid du Colombier }
3087dd7cddfSDavid du Colombier 
3097dd7cddfSDavid du Colombier static void
checkport(int start,int end)3107dd7cddfSDavid du Colombier checkport(int start, int end)
3117dd7cddfSDavid du Colombier {
3127dd7cddfSDavid du Colombier 	/* standard vga regs are OK */
3137dd7cddfSDavid du Colombier 	if(start >= 0x2b0 && end <= 0x2df+1)
3147dd7cddfSDavid du Colombier 		return;
3157dd7cddfSDavid du Colombier 	if(start >= 0x3c0 && end <= 0x3da+1)
3167dd7cddfSDavid du Colombier 		return;
3177dd7cddfSDavid du Colombier 
3187dd7cddfSDavid du Colombier 	if(iounused(start, end))
3197dd7cddfSDavid du Colombier 		return;
3207dd7cddfSDavid du Colombier 	error(Eperm);
3217dd7cddfSDavid du Colombier }
3227dd7cddfSDavid du Colombier 
3237dd7cddfSDavid du Colombier static Chan*
archattach(char * spec)3247dd7cddfSDavid du Colombier archattach(char* spec)
3257dd7cddfSDavid du Colombier {
3267dd7cddfSDavid du Colombier 	return devattach('P', spec);
3277dd7cddfSDavid du Colombier }
3287dd7cddfSDavid du Colombier 
3299a747e4fSDavid du Colombier Walkqid*
archwalk(Chan * c,Chan * nc,char ** name,int nname)3309a747e4fSDavid du Colombier archwalk(Chan* c, Chan *nc, char** name, int nname)
3317dd7cddfSDavid du Colombier {
3329a747e4fSDavid du Colombier 	return devwalk(c, nc, name, nname, archdir, narchdir, devgen);
3337dd7cddfSDavid du Colombier }
3347dd7cddfSDavid du Colombier 
3359a747e4fSDavid du Colombier static int
archstat(Chan * c,uchar * dp,int n)3369a747e4fSDavid du Colombier archstat(Chan* c, uchar* dp, int n)
3377dd7cddfSDavid du Colombier {
3389a747e4fSDavid du Colombier 	return devstat(c, dp, n, archdir, narchdir, devgen);
3397dd7cddfSDavid du Colombier }
3407dd7cddfSDavid du Colombier 
3417dd7cddfSDavid du Colombier static Chan*
archopen(Chan * c,int omode)3427dd7cddfSDavid du Colombier archopen(Chan* c, int omode)
3437dd7cddfSDavid du Colombier {
34480ee5cbfSDavid du Colombier 	return devopen(c, omode, archdir, narchdir, devgen);
3457dd7cddfSDavid du Colombier }
3467dd7cddfSDavid du Colombier 
3477dd7cddfSDavid du Colombier static void
archclose(Chan *)3487dd7cddfSDavid du Colombier archclose(Chan*)
3497dd7cddfSDavid du Colombier {
3507dd7cddfSDavid du Colombier }
3517dd7cddfSDavid du Colombier 
3527dd7cddfSDavid du Colombier enum
3537dd7cddfSDavid du Colombier {
3547dd7cddfSDavid du Colombier 	Linelen= 31,
3557dd7cddfSDavid du Colombier };
3567dd7cddfSDavid du Colombier 
3577dd7cddfSDavid du Colombier static long
archread(Chan * c,void * a,long n,vlong offset)3587dd7cddfSDavid du Colombier archread(Chan *c, void *a, long n, vlong offset)
3597dd7cddfSDavid du Colombier {
360ef9eff0bSDavid du Colombier 	char *buf, *p;
3617dd7cddfSDavid du Colombier 	int port;
3627dd7cddfSDavid du Colombier 	ushort *sp;
3637dd7cddfSDavid du Colombier 	ulong *lp;
36480ee5cbfSDavid du Colombier 	IOMap *m;
36580ee5cbfSDavid du Colombier 	Rdwrfn *fn;
3667dd7cddfSDavid du Colombier 
3679a747e4fSDavid du Colombier 	switch((ulong)c->qid.path){
3687dd7cddfSDavid du Colombier 
3697dd7cddfSDavid du Colombier 	case Qdir:
37080ee5cbfSDavid du Colombier 		return devdirread(c, a, n, archdir, narchdir, devgen);
3717dd7cddfSDavid du Colombier 
3727dd7cddfSDavid du Colombier 	case Qiob:
3737dd7cddfSDavid du Colombier 		port = offset;
3747dd7cddfSDavid du Colombier 		checkport(offset, offset+n);
3757dd7cddfSDavid du Colombier 		for(p = a; port < offset+n; port++)
3767dd7cddfSDavid du Colombier 			*p++ = inb(port);
3777dd7cddfSDavid du Colombier 		return n;
3787dd7cddfSDavid du Colombier 
3797dd7cddfSDavid du Colombier 	case Qiow:
3809a747e4fSDavid du Colombier 		if(n & 1)
3817dd7cddfSDavid du Colombier 			error(Ebadarg);
38280ee5cbfSDavid du Colombier 		checkport(offset, offset+n);
3837dd7cddfSDavid du Colombier 		sp = a;
3847dd7cddfSDavid du Colombier 		for(port = offset; port < offset+n; port += 2)
3857dd7cddfSDavid du Colombier 			*sp++ = ins(port);
3869a747e4fSDavid du Colombier 		return n;
3877dd7cddfSDavid du Colombier 
3887dd7cddfSDavid du Colombier 	case Qiol:
3899a747e4fSDavid du Colombier 		if(n & 3)
3907dd7cddfSDavid du Colombier 			error(Ebadarg);
39180ee5cbfSDavid du Colombier 		checkport(offset, offset+n);
3927dd7cddfSDavid du Colombier 		lp = a;
3937dd7cddfSDavid du Colombier 		for(port = offset; port < offset+n; port += 4)
3947dd7cddfSDavid du Colombier 			*lp++ = inl(port);
3959a747e4fSDavid du Colombier 		return n;
3967dd7cddfSDavid du Colombier 
3977dd7cddfSDavid du Colombier 	case Qioalloc:
3987dd7cddfSDavid du Colombier 		break;
3997dd7cddfSDavid du Colombier 
4007dd7cddfSDavid du Colombier 	default:
40180ee5cbfSDavid du Colombier 		if(c->qid.path < narchdir && (fn = readfn[c->qid.path]))
40280ee5cbfSDavid du Colombier 			return fn(c, a, n, offset);
4037dd7cddfSDavid du Colombier 		error(Eperm);
4047dd7cddfSDavid du Colombier 		break;
4057dd7cddfSDavid du Colombier 	}
4067dd7cddfSDavid du Colombier 
4076b6b9ac8SDavid du Colombier 	if((buf = malloc(n)) == nil)
408ef9eff0bSDavid du Colombier 		error(Enomem);
409ef9eff0bSDavid du Colombier 	p = buf;
4107dd7cddfSDavid du Colombier 	n = n/Linelen;
411ef9eff0bSDavid du Colombier 	offset = offset/Linelen;
412ef9eff0bSDavid du Colombier 
4137dd7cddfSDavid du Colombier 	lock(&iomap);
4147dd7cddfSDavid du Colombier 	for(m = iomap.m; n > 0 && m != nil; m = m->next){
4157dd7cddfSDavid du Colombier 		if(offset-- > 0)
4167dd7cddfSDavid du Colombier 			continue;
417*4e3613abSDavid du Colombier 		seprint(p, &buf[n], "%8lux %8lux %-12.12s\n", m->start,
418*4e3613abSDavid du Colombier 			m->end-1, m->tag);
4197dd7cddfSDavid du Colombier 		p += Linelen;
4207dd7cddfSDavid du Colombier 		n--;
4217dd7cddfSDavid du Colombier 	}
4227dd7cddfSDavid du Colombier 	unlock(&iomap);
4237dd7cddfSDavid du Colombier 
424ef9eff0bSDavid du Colombier 	n = p - buf;
425ef9eff0bSDavid du Colombier 	memmove(a, buf, n);
426ef9eff0bSDavid du Colombier 	free(buf);
427ef9eff0bSDavid du Colombier 
428ef9eff0bSDavid du Colombier 	return n;
4297dd7cddfSDavid du Colombier }
4307dd7cddfSDavid du Colombier 
4317dd7cddfSDavid du Colombier static long
archwrite(Chan * c,void * a,long n,vlong offset)4327dd7cddfSDavid du Colombier archwrite(Chan *c, void *a, long n, vlong offset)
4337dd7cddfSDavid du Colombier {
43480ee5cbfSDavid du Colombier 	char *p;
4357dd7cddfSDavid du Colombier 	int port;
4367dd7cddfSDavid du Colombier 	ushort *sp;
4377dd7cddfSDavid du Colombier 	ulong *lp;
43880ee5cbfSDavid du Colombier 	Rdwrfn *fn;
4397dd7cddfSDavid du Colombier 
4409a747e4fSDavid du Colombier 	switch((ulong)c->qid.path){
4417dd7cddfSDavid du Colombier 
4427dd7cddfSDavid du Colombier 	case Qiob:
4437dd7cddfSDavid du Colombier 		p = a;
4447dd7cddfSDavid du Colombier 		checkport(offset, offset+n);
4457dd7cddfSDavid du Colombier 		for(port = offset; port < offset+n; port++)
4467dd7cddfSDavid du Colombier 			outb(port, *p++);
4477dd7cddfSDavid du Colombier 		return n;
4487dd7cddfSDavid du Colombier 
4497dd7cddfSDavid du Colombier 	case Qiow:
4509a747e4fSDavid du Colombier 		if(n & 1)
4517dd7cddfSDavid du Colombier 			error(Ebadarg);
45280ee5cbfSDavid du Colombier 		checkport(offset, offset+n);
4537dd7cddfSDavid du Colombier 		sp = a;
4547dd7cddfSDavid du Colombier 		for(port = offset; port < offset+n; port += 2)
4557dd7cddfSDavid du Colombier 			outs(port, *sp++);
4569a747e4fSDavid du Colombier 		return n;
4577dd7cddfSDavid du Colombier 
4587dd7cddfSDavid du Colombier 	case Qiol:
4599a747e4fSDavid du Colombier 		if(n & 3)
4607dd7cddfSDavid du Colombier 			error(Ebadarg);
46180ee5cbfSDavid du Colombier 		checkport(offset, offset+n);
4627dd7cddfSDavid du Colombier 		lp = a;
4637dd7cddfSDavid du Colombier 		for(port = offset; port < offset+n; port += 4)
4647dd7cddfSDavid du Colombier 			outl(port, *lp++);
4659a747e4fSDavid du Colombier 		return n;
4667dd7cddfSDavid du Colombier 
4677dd7cddfSDavid du Colombier 	default:
46880ee5cbfSDavid du Colombier 		if(c->qid.path < narchdir && (fn = writefn[c->qid.path]))
46980ee5cbfSDavid du Colombier 			return fn(c, a, n, offset);
4707dd7cddfSDavid du Colombier 		error(Eperm);
4717dd7cddfSDavid du Colombier 		break;
4727dd7cddfSDavid du Colombier 	}
4737dd7cddfSDavid du Colombier 	return 0;
4747dd7cddfSDavid du Colombier }
4757dd7cddfSDavid du Colombier 
4767dd7cddfSDavid du Colombier Dev archdevtab = {
4777dd7cddfSDavid du Colombier 	'P',
4787dd7cddfSDavid du Colombier 	"arch",
4797dd7cddfSDavid du Colombier 
4807dd7cddfSDavid du Colombier 	devreset,
4817dd7cddfSDavid du Colombier 	devinit,
4829a747e4fSDavid du Colombier 	devshutdown,
4837dd7cddfSDavid du Colombier 	archattach,
4847dd7cddfSDavid du Colombier 	archwalk,
4857dd7cddfSDavid du Colombier 	archstat,
4867dd7cddfSDavid du Colombier 	archopen,
4877dd7cddfSDavid du Colombier 	devcreate,
4887dd7cddfSDavid du Colombier 	archclose,
4897dd7cddfSDavid du Colombier 	archread,
4907dd7cddfSDavid du Colombier 	devbread,
4917dd7cddfSDavid du Colombier 	archwrite,
4927dd7cddfSDavid du Colombier 	devbwrite,
4937dd7cddfSDavid du Colombier 	devremove,
4947dd7cddfSDavid du Colombier 	devwstat,
4957dd7cddfSDavid du Colombier };
4967dd7cddfSDavid du Colombier 
4977dd7cddfSDavid du Colombier /*
4987dd7cddfSDavid du Colombier  *  the following is a generic version of the
4997dd7cddfSDavid du Colombier  *  architecture specific stuff
5007dd7cddfSDavid du Colombier  */
5017dd7cddfSDavid du Colombier 
5027dd7cddfSDavid du Colombier static int
unimplemented(int)5037dd7cddfSDavid du Colombier unimplemented(int)
5047dd7cddfSDavid du Colombier {
5057dd7cddfSDavid du Colombier 	return 0;
5067dd7cddfSDavid du Colombier }
5077dd7cddfSDavid du Colombier 
5087dd7cddfSDavid du Colombier static void
nop(void)5097dd7cddfSDavid du Colombier nop(void)
5107dd7cddfSDavid du Colombier {
5117dd7cddfSDavid du Colombier }
5127dd7cddfSDavid du Colombier 
513c3ca4b29SDavid du Colombier static void
archreset(void)514c3ca4b29SDavid du Colombier archreset(void)
515c3ca4b29SDavid du Colombier {
516c3ca4b29SDavid du Colombier 	i8042reset();
517c3ca4b29SDavid du Colombier 
518c3ca4b29SDavid du Colombier 	/*
519c3ca4b29SDavid du Colombier 	 * Often the BIOS hangs during restart if a conventional 8042
520c3ca4b29SDavid du Colombier 	 * warm-boot sequence is tried. The following is Intel specific and
521c3ca4b29SDavid du Colombier 	 * seems to perform a cold-boot, but at least it comes back.
522c3ca4b29SDavid du Colombier 	 * And sometimes there is no keyboard...
523c3ca4b29SDavid du Colombier 	 *
524c3ca4b29SDavid du Colombier 	 * The reset register (0xcf9) is usually in one of the bridge
525c3ca4b29SDavid du Colombier 	 * chips. The actual location and sequence could be extracted from
526c3ca4b29SDavid du Colombier 	 * ACPI but why bother, this is the end of the line anyway.
527c3ca4b29SDavid du Colombier 	 */
528c3ca4b29SDavid du Colombier 	print("Takes a licking and keeps on ticking...\n");
529c3ca4b29SDavid du Colombier 	*(ushort*)KADDR(0x472) = 0x1234;	/* BIOS warm-boot flag */
530c3ca4b29SDavid du Colombier 	outb(0xcf9, 0x02);
531c3ca4b29SDavid du Colombier 	outb(0xcf9, 0x06);
532c3ca4b29SDavid du Colombier 
533c3ca4b29SDavid du Colombier 	for(;;)
534c3ca4b29SDavid du Colombier 		idle();
535c3ca4b29SDavid du Colombier }
536c3ca4b29SDavid du Colombier 
537fb7f0c93SDavid du Colombier /*
5383c2ddefeSDavid du Colombier  * 386 has no compare-and-swap instruction.
5393c2ddefeSDavid du Colombier  * Run it with interrupts turned off instead.
5403c2ddefeSDavid du Colombier  */
5413c2ddefeSDavid du Colombier static int
cmpswap386(long * addr,long old,long new)5423c2ddefeSDavid du Colombier cmpswap386(long *addr, long old, long new)
5433c2ddefeSDavid du Colombier {
5443c2ddefeSDavid du Colombier 	int r, s;
5453c2ddefeSDavid du Colombier 
5463c2ddefeSDavid du Colombier 	s = splhi();
5473c2ddefeSDavid du Colombier 	if(r = (*addr == old))
5483c2ddefeSDavid du Colombier 		*addr = new;
5493c2ddefeSDavid du Colombier 	splx(s);
5503c2ddefeSDavid du Colombier 	return r;
5513c2ddefeSDavid du Colombier }
5523c2ddefeSDavid du Colombier 
5533c2ddefeSDavid du Colombier /*
554fb7f0c93SDavid du Colombier  * On a uniprocessor, you'd think that coherence could be nop,
555ed250ae1SDavid du Colombier  * but it can't.  We still need a barrier when using coherence() in
556fb7f0c93SDavid du Colombier  * device drivers.
557fb7f0c93SDavid du Colombier  *
558fb7f0c93SDavid du Colombier  * On VMware, it's safe (and a huge win) to set this to nop.
559fb7f0c93SDavid du Colombier  * Aux/vmware does this via the #P/archctl file.
560fb7f0c93SDavid du Colombier  */
561ed250ae1SDavid du Colombier void (*coherence)(void) = nop;
5627dd7cddfSDavid du Colombier 
5633c2ddefeSDavid du Colombier int (*cmpswap)(long*, long, long) = cmpswap386;
5643c2ddefeSDavid du Colombier 
5657dd7cddfSDavid du Colombier PCArch* arch;
5667dd7cddfSDavid du Colombier extern PCArch* knownarch[];
5677dd7cddfSDavid du Colombier 
5687dd7cddfSDavid du Colombier PCArch archgeneric = {
569d9306527SDavid du Colombier .id=		"generic",
570d9306527SDavid du Colombier .ident=		0,
571c3ca4b29SDavid du Colombier .reset=		archreset,
572d9306527SDavid du Colombier .serialpower=	unimplemented,
573d9306527SDavid du Colombier .modempower=	unimplemented,
5747dd7cddfSDavid du Colombier 
575d9306527SDavid du Colombier .intrinit=	i8259init,
576d9306527SDavid du Colombier .intrenable=	i8259enable,
577d9306527SDavid du Colombier .intrvecno=	i8259vecno,
578d9306527SDavid du Colombier .intrdisable=	i8259disable,
5794de34a7eSDavid du Colombier .intron=	i8259on,
5804de34a7eSDavid du Colombier .introff=	i8259off,
5817dd7cddfSDavid du Colombier 
582d9306527SDavid du Colombier .clockenable=	i8253enable,
583d9306527SDavid du Colombier .fastclock=	i8253read,
584d9306527SDavid du Colombier .timerset=	i8253timerset,
5857dd7cddfSDavid du Colombier };
5867dd7cddfSDavid du Colombier 
587ed250ae1SDavid du Colombier typedef struct X86type X86type;
588ed250ae1SDavid du Colombier struct X86type {
5897dd7cddfSDavid du Colombier 	int	family;
5907dd7cddfSDavid du Colombier 	int	model;
5917dd7cddfSDavid du Colombier 	int	aalcycles;
5927dd7cddfSDavid du Colombier 	char*	name;
593ed250ae1SDavid du Colombier };
5947dd7cddfSDavid du Colombier 
595b4124be8SDavid du Colombier /* cpuid ax is 0x0ffMTFmS, where 0xffF is family, 0xMm is model */
5967dd7cddfSDavid du Colombier static X86type x86intel[] =
5977dd7cddfSDavid du Colombier {
5987dd7cddfSDavid du Colombier 	{ 4,	0,	22,	"486DX", },	/* known chips */
5997dd7cddfSDavid du Colombier 	{ 4,	1,	22,	"486DX50", },
6007dd7cddfSDavid du Colombier 	{ 4,	2,	22,	"486SX", },
6017dd7cddfSDavid du Colombier 	{ 4,	3,	22,	"486DX2", },
6027dd7cddfSDavid du Colombier 	{ 4,	4,	22,	"486SL", },
6037dd7cddfSDavid du Colombier 	{ 4,	5,	22,	"486SX2", },
6047dd7cddfSDavid du Colombier 	{ 4,	7,	22,	"DX2WB", },	/* P24D */
6057dd7cddfSDavid du Colombier 	{ 4,	8,	22,	"DX4", },	/* P24C */
6067dd7cddfSDavid du Colombier 	{ 4,	9,	22,	"DX4WB", },	/* P24CT */
6077dd7cddfSDavid du Colombier 	{ 5,	0,	23,	"P5", },
6087dd7cddfSDavid du Colombier 	{ 5,	1,	23,	"P5", },
6097dd7cddfSDavid du Colombier 	{ 5,	2,	23,	"P54C", },
6107dd7cddfSDavid du Colombier 	{ 5,	3,	23,	"P24T", },
6117dd7cddfSDavid du Colombier 	{ 5,	4,	23,	"P55C MMX", },
6127dd7cddfSDavid du Colombier 	{ 5,	7,	23,	"P54C VRT", },
6137dd7cddfSDavid du Colombier 	{ 6,	1,	16,	"PentiumPro", },/* trial and error */
6147dd7cddfSDavid du Colombier 	{ 6,	3,	16,	"PentiumII", },
6157dd7cddfSDavid du Colombier 	{ 6,	5,	16,	"PentiumII/Xeon", },
6167dd7cddfSDavid du Colombier 	{ 6,	6,	16,	"Celeron", },
6177dd7cddfSDavid du Colombier 	{ 6,	7,	16,	"PentiumIII/Xeon", },
6187dd7cddfSDavid du Colombier 	{ 6,	8,	16,	"PentiumIII/Xeon", },
6193ff48bf5SDavid du Colombier 	{ 6,	0xB,	16,	"PentiumIII/Xeon", },
620b4124be8SDavid du Colombier 	{ 6,	0xF,	16,	"Core 2/Xeon", },
621c39c2eb3SDavid du Colombier 	{ 6,	0x16,	16,	"Celeron", },
622c39c2eb3SDavid du Colombier 	{ 6,	0x17,	16,	"Core 2/Xeon", },
623c39c2eb3SDavid du Colombier 	{ 6,	0x1A,	16,	"Core i7/Xeon", },
624c39c2eb3SDavid du Colombier 	{ 6,	0x1C,	16,	"Atom", },
625c39c2eb3SDavid du Colombier 	{ 6,	0x1D,	16,	"Xeon MP", },
626b4124be8SDavid du Colombier 	{ 6,	0x1E,	16,	"Core i5/i7/Xeon", },
627b4124be8SDavid du Colombier 	{ 6,	0x1F,	16,	"Core i7/Xeon", },
628b4124be8SDavid du Colombier 	{ 6,	0x22,	16,	"Core i7", },
629b4124be8SDavid du Colombier 	{ 6,	0x25,	16,	"Core i3/i5/i7", },
630b4124be8SDavid du Colombier 	{ 6,	0x2A,	16,	"Core i7", },
631b4124be8SDavid du Colombier 	{ 6,	0x2C,	16,	"Core i7/Xeon", },
632b4124be8SDavid du Colombier 	{ 6,	0x2D,	16,	"Core i7", },
633b4124be8SDavid du Colombier 	{ 6,	0x2E,	16,	"Xeon MP", },
634b4124be8SDavid du Colombier 	{ 6,	0x2F,	16,	"Xeon MP", },
635b4124be8SDavid du Colombier 	{ 6,	0x3A,	16,	"Core i7", },
6369a747e4fSDavid du Colombier 	{ 0xF,	1,	16,	"P4", },	/* P4 */
637a30303efSDavid du Colombier 	{ 0xF,	2,	16,	"PentiumIV/Xeon", },
638c39c2eb3SDavid du Colombier 	{ 0xF,	6,	16,	"PentiumIV/Xeon", },
6397dd7cddfSDavid du Colombier 
6407dd7cddfSDavid du Colombier 	{ 3,	-1,	32,	"386", },	/* family defaults */
6417dd7cddfSDavid du Colombier 	{ 4,	-1,	22,	"486", },
6427dd7cddfSDavid du Colombier 	{ 5,	-1,	23,	"P5", },
6437dd7cddfSDavid du Colombier 	{ 6,	-1,	16,	"P6", },
6449a747e4fSDavid du Colombier 	{ 0xF,	-1,	16,	"P4", },	/* P4 */
6457dd7cddfSDavid du Colombier 
646282e677fSDavid du Colombier 	{ -1,	-1,	16,	"unknown", },	/* total default */
6477dd7cddfSDavid du Colombier };
6487dd7cddfSDavid du Colombier 
6497dd7cddfSDavid du Colombier /*
6507dd7cddfSDavid du Colombier  * The AMD processors all implement the CPUID instruction.
6517dd7cddfSDavid du Colombier  * The later ones also return the processor name via functions
6527dd7cddfSDavid du Colombier  * 0x80000002, 0x80000003 and 0x80000004 in registers AX, BX, CX
6537dd7cddfSDavid du Colombier  * and DX:
6547dd7cddfSDavid du Colombier  *	K5	"AMD-K5(tm) Processor"
6557dd7cddfSDavid du Colombier  *	K6	"AMD-K6tm w/ multimedia extensions"
6567dd7cddfSDavid du Colombier  *	K6 3D	"AMD-K6(tm) 3D processor"
6577dd7cddfSDavid du Colombier  *	K6 3D+	?
6587dd7cddfSDavid du Colombier  */
6597dd7cddfSDavid du Colombier static X86type x86amd[] =
6607dd7cddfSDavid du Colombier {
6617dd7cddfSDavid du Colombier 	{ 5,	0,	23,	"AMD-K5", },	/* guesswork */
6627dd7cddfSDavid du Colombier 	{ 5,	1,	23,	"AMD-K5", },	/* guesswork */
6637dd7cddfSDavid du Colombier 	{ 5,	2,	23,	"AMD-K5", },	/* guesswork */
6647dd7cddfSDavid du Colombier 	{ 5,	3,	23,	"AMD-K5", },	/* guesswork */
6650dd39f6eSDavid du Colombier 	{ 5,	4,	23,	"AMD Geode GX1", },	/* guesswork */
6660dd39f6eSDavid du Colombier 	{ 5,	5,	23,	"AMD Geode GX2", },	/* guesswork */
6677dd7cddfSDavid du Colombier 	{ 5,	6,	11,	"AMD-K6", },	/* trial and error */
6687dd7cddfSDavid du Colombier 	{ 5,	7,	11,	"AMD-K6", },	/* trial and error */
6697dd7cddfSDavid du Colombier 	{ 5,	8,	11,	"AMD-K6-2", },	/* trial and error */
6707dd7cddfSDavid du Colombier 	{ 5,	9,	11,	"AMD-K6-III", },/* trial and error */
6710dd39f6eSDavid du Colombier 	{ 5,	0xa,	23,	"AMD Geode LX", },	/* guesswork */
6727dd7cddfSDavid du Colombier 
6737dd7cddfSDavid du Colombier 	{ 6,	1,	11,	"AMD-Athlon", },/* trial and error */
6747dd7cddfSDavid du Colombier 	{ 6,	2,	11,	"AMD-Athlon", },/* trial and error */
6757dd7cddfSDavid du Colombier 
676c39c2eb3SDavid du Colombier 	{ 0x1F,	9,	11,	"AMD-K10 Opteron G34", },/* guesswork */
677c39c2eb3SDavid du Colombier 
6787dd7cddfSDavid du Colombier 	{ 4,	-1,	22,	"Am486", },	/* guesswork */
6797dd7cddfSDavid du Colombier 	{ 5,	-1,	23,	"AMD-K5/K6", },	/* guesswork */
6807dd7cddfSDavid du Colombier 	{ 6,	-1,	11,	"AMD-Athlon", },/* guesswork */
681c39c2eb3SDavid du Colombier 	{ 0xF,	-1,	11,	"AMD-K8", },	/* guesswork */
682c39c2eb3SDavid du Colombier 	{ 0x1F,	-1,	11,	"AMD-K10", },	/* guesswork */
6837dd7cddfSDavid du Colombier 
684282e677fSDavid du Colombier 	{ -1,	-1,	11,	"unknown", },	/* total default */
6857dd7cddfSDavid du Colombier };
6867dd7cddfSDavid du Colombier 
68759cc4ca5SDavid du Colombier /*
68859cc4ca5SDavid du Colombier  * WinChip 240MHz
68959cc4ca5SDavid du Colombier  */
69059cc4ca5SDavid du Colombier static X86type x86winchip[] =
69159cc4ca5SDavid du Colombier {
69259cc4ca5SDavid du Colombier 	{5,	4,	23,	"Winchip",},	/* guesswork */
69365fa3f8bSDavid du Colombier 	{6,	7,	23,	"Via C3 Samuel 2 or Ezra",},
69465fa3f8bSDavid du Colombier 	{6,	8,	23,	"Via C3 Ezra-T",},
69543f160e5SDavid du Colombier 	{6,	9,	23,	"Via C3 Eden-N",},
69659cc4ca5SDavid du Colombier 	{ -1,	-1,	23,	"unknown", },	/* total default */
69759cc4ca5SDavid du Colombier };
69859cc4ca5SDavid du Colombier 
699f5a5e725SDavid du Colombier /*
700f5a5e725SDavid du Colombier  * SiS 55x
701f5a5e725SDavid du Colombier  */
702f5a5e725SDavid du Colombier static X86type x86sis[] =
703f5a5e725SDavid du Colombier {
704f5a5e725SDavid du Colombier 	{5,	0,	23,	"SiS 55x",},	/* guesswork */
705f5a5e725SDavid du Colombier 	{ -1,	-1,	23,	"unknown", },	/* total default */
706f5a5e725SDavid du Colombier };
70759cc4ca5SDavid du Colombier 
7087dd7cddfSDavid du Colombier static X86type *cputype;
7097dd7cddfSDavid du Colombier 
710179dd269SDavid du Colombier static void	simplecycles(uvlong*);
711179dd269SDavid du Colombier void	(*cycles)(uvlong*) = simplecycles;
712179dd269SDavid du Colombier void	_cycles(uvlong*);	/* in l.s */
713179dd269SDavid du Colombier 
714179dd269SDavid du Colombier static void
simplecycles(uvlong * x)715179dd269SDavid du Colombier simplecycles(uvlong*x)
716179dd269SDavid du Colombier {
717179dd269SDavid du Colombier 	*x = m->ticks;
718179dd269SDavid du Colombier }
719179dd269SDavid du Colombier 
7207dd7cddfSDavid du Colombier void
cpuidprint(void)7217dd7cddfSDavid du Colombier cpuidprint(void)
7227dd7cddfSDavid du Colombier {
7237dd7cddfSDavid du Colombier 	int i;
7247dd7cddfSDavid du Colombier 	char buf[128];
7257dd7cddfSDavid du Colombier 
726*4e3613abSDavid du Colombier 	i = snprint(buf, sizeof buf, "cpu%d: %s%dMHz ", m->machno,
727*4e3613abSDavid du Colombier 		m->machno < 10? " ": "", m->cpumhz);
7287dd7cddfSDavid du Colombier 	if(m->cpuidid[0])
729061a3f44SDavid du Colombier 		i += sprint(buf+i, "%12.12s ", m->cpuidid);
730208510e1SDavid du Colombier 	seprint(buf+i, buf + sizeof buf - 1,
731208510e1SDavid du Colombier 		"%s (cpuid: AX 0x%4.4uX DX 0x%4.4uX)\n",
7327dd7cddfSDavid du Colombier 		m->cpuidtype, m->cpuidax, m->cpuiddx);
7337dd7cddfSDavid du Colombier 	print(buf);
7347dd7cddfSDavid du Colombier }
7357dd7cddfSDavid du Colombier 
7369a747e4fSDavid du Colombier /*
7379a747e4fSDavid du Colombier  *  figure out:
7389a747e4fSDavid du Colombier  *	- cpu type
7399a747e4fSDavid du Colombier  *	- whether or not we have a TSC (cycle counter)
7406b6b9ac8SDavid du Colombier  *	- whether or not it supports page size extensions
7419a747e4fSDavid du Colombier  *		(if so turn it on)
7426b6b9ac8SDavid du Colombier  *	- whether or not it supports machine check exceptions
7436b6b9ac8SDavid du Colombier  *		(if so turn it on)
7446b6b9ac8SDavid du Colombier  *	- whether or not it supports the page global flag
7459a747e4fSDavid du Colombier  *		(if so turn it on)
7469a747e4fSDavid du Colombier  */
7477dd7cddfSDavid du Colombier int
cpuidentify(void)7487dd7cddfSDavid du Colombier cpuidentify(void)
7497dd7cddfSDavid du Colombier {
75059cc4ca5SDavid du Colombier 	char *p;
75159cc4ca5SDavid du Colombier 	int family, model, nomce;
7529a747e4fSDavid du Colombier 	X86type *t, *tab;
7537dd7cddfSDavid du Colombier 	ulong cr4;
75426d1d1dfSDavid du Colombier 	ulong regs[4];
75559cc4ca5SDavid du Colombier 	vlong mca, mct;
7567dd7cddfSDavid du Colombier 
75726d1d1dfSDavid du Colombier 	cpuid(Highstdfunc, regs);
75826d1d1dfSDavid du Colombier 	memmove(m->cpuidid,   &regs[1], BY2WD);	/* bx */
75926d1d1dfSDavid du Colombier 	memmove(m->cpuidid+4, &regs[3], BY2WD);	/* dx */
76026d1d1dfSDavid du Colombier 	memmove(m->cpuidid+8, &regs[2], BY2WD);	/* cx */
76126d1d1dfSDavid du Colombier 	m->cpuidid[12] = '\0';
76226d1d1dfSDavid du Colombier 
76326d1d1dfSDavid du Colombier 	cpuid(Procsig, regs);
76426d1d1dfSDavid du Colombier 	m->cpuidax = regs[0];
76526d1d1dfSDavid du Colombier 	m->cpuiddx = regs[3];
76626d1d1dfSDavid du Colombier 
7670dd39f6eSDavid du Colombier 	if(strncmp(m->cpuidid, "AuthenticAMD", 12) == 0 ||
7680dd39f6eSDavid du Colombier 	   strncmp(m->cpuidid, "Geode by NSC", 12) == 0)
7699a747e4fSDavid du Colombier 		tab = x86amd;
77059cc4ca5SDavid du Colombier 	else if(strncmp(m->cpuidid, "CentaurHauls", 12) == 0)
7719a747e4fSDavid du Colombier 		tab = x86winchip;
772f5a5e725SDavid du Colombier 	else if(strncmp(m->cpuidid, "SiS SiS SiS ", 12) == 0)
773f5a5e725SDavid du Colombier 		tab = x86sis;
7747dd7cddfSDavid du Colombier 	else
7759a747e4fSDavid du Colombier 		tab = x86intel;
7769a747e4fSDavid du Colombier 
7777dd7cddfSDavid du Colombier 	family = X86FAMILY(m->cpuidax);
7787dd7cddfSDavid du Colombier 	model = X86MODEL(m->cpuidax);
7799a747e4fSDavid du Colombier 	for(t=tab; t->name; t++)
7807dd7cddfSDavid du Colombier 		if((t->family == family && t->model == model)
7817dd7cddfSDavid du Colombier 		|| (t->family == family && t->model == -1)
7827dd7cddfSDavid du Colombier 		|| (t->family == -1))
7837dd7cddfSDavid du Colombier 			break;
7849a747e4fSDavid du Colombier 
7857dd7cddfSDavid du Colombier 	m->cpuidtype = t->name;
7869a747e4fSDavid du Colombier 
7879a747e4fSDavid du Colombier 	/*
7889a747e4fSDavid du Colombier 	 *  if there is one, set tsc to a known value
7899a747e4fSDavid du Colombier 	 */
790b1707c5dSDavid du Colombier 	if(m->cpuiddx & Tsc){
791f5a5e725SDavid du Colombier 		m->havetsc = 1;
792179dd269SDavid du Colombier 		cycles = _cycles;
793b1707c5dSDavid du Colombier 		if(m->cpuiddx & Cpumsr)
7949a747e4fSDavid du Colombier 			wrmsr(0x10, 0);
795f5a5e725SDavid du Colombier 	}
7969a747e4fSDavid du Colombier 
7979a747e4fSDavid du Colombier 	/*
7989a747e4fSDavid du Colombier 	 *  use i8253 to guess our cpu speed
7999a747e4fSDavid du Colombier 	 */
8009a747e4fSDavid du Colombier 	guesscpuhz(t->aalcycles);
8017dd7cddfSDavid du Colombier 
8027dd7cddfSDavid du Colombier 	/*
8036b6b9ac8SDavid du Colombier 	 * If machine check exception, page size extensions or page global bit
8046b6b9ac8SDavid du Colombier 	 * are supported enable them in CR4 and clear any other set extensions.
8057dd7cddfSDavid du Colombier 	 * If machine check was enabled clear out any lingering status.
8067dd7cddfSDavid du Colombier 	 */
80761fd6f66SDavid du Colombier 	if(m->cpuiddx & (Pge|Mce|Pse)){
8087dd7cddfSDavid du Colombier 		cr4 = 0;
80961fd6f66SDavid du Colombier 		if(m->cpuiddx & Pse)
8107dd7cddfSDavid du Colombier 			cr4 |= 0x10;		/* page size extensions */
81159cc4ca5SDavid du Colombier 		if(p = getconf("*nomce"))
81259cc4ca5SDavid du Colombier 			nomce = strtoul(p, 0, 0);
81359cc4ca5SDavid du Colombier 		else
81459cc4ca5SDavid du Colombier 			nomce = 0;
815b1707c5dSDavid du Colombier 		if((m->cpuiddx & Mce) && !nomce){
8167dd7cddfSDavid du Colombier 			cr4 |= 0x40;		/* machine check enable */
81759cc4ca5SDavid du Colombier 			if(family == 5){
81859cc4ca5SDavid du Colombier 				rdmsr(0x00, &mca);
81959cc4ca5SDavid du Colombier 				rdmsr(0x01, &mct);
82059cc4ca5SDavid du Colombier 			}
82159cc4ca5SDavid du Colombier 		}
8227dd7cddfSDavid du Colombier 
8239a747e4fSDavid du Colombier 		/*
8249a747e4fSDavid du Colombier 		 * Detect whether the chip supports the global bit
8259a747e4fSDavid du Colombier 		 * in page directory and page table entries.  When set
8269a747e4fSDavid du Colombier 		 * in a particular entry, it means ``don't bother removing
8279a747e4fSDavid du Colombier 		 * this from the TLB when CR3 changes.''
8289a747e4fSDavid du Colombier 		 *
8299a747e4fSDavid du Colombier 		 * We flag all kernel pages with this bit.  Doing so lessens the
8309a747e4fSDavid du Colombier 		 * overhead of switching processes on bare hardware,
8319a747e4fSDavid du Colombier 		 * even more so on VMware.  See mmu.c:/^memglobal.
8329a747e4fSDavid du Colombier 		 *
8339a747e4fSDavid du Colombier 		 * For future reference, should we ever need to do a
8349a747e4fSDavid du Colombier 		 * full TLB flush, it can be accomplished by clearing
8359a747e4fSDavid du Colombier 		 * the PGE bit in CR4, writing to CR3, and then
8369a747e4fSDavid du Colombier 		 * restoring the PGE bit.
8379a747e4fSDavid du Colombier 		 */
838b1707c5dSDavid du Colombier 		if(m->cpuiddx & Pge){
8399a747e4fSDavid du Colombier 			cr4 |= 0x80;		/* page global enable bit */
8409a747e4fSDavid du Colombier 			m->havepge = 1;
8419a747e4fSDavid du Colombier 		}
8429a747e4fSDavid du Colombier 
8436b6b9ac8SDavid du Colombier 		putcr4(cr4);
844b1707c5dSDavid du Colombier 		if(m->cpuiddx & Mce)
8456b6b9ac8SDavid du Colombier 			rdmsr(0x01, &mct);
8466b6b9ac8SDavid du Colombier 	}
8476b6b9ac8SDavid du Colombier 
84891e577b2SDavid du Colombier 	if(m->cpuiddx & Fxsr){			/* have sse fp? */
84991e577b2SDavid du Colombier 		fpsave = fpssesave;
85091e577b2SDavid du Colombier 		fprestore = fpsserestore;
85191e577b2SDavid du Colombier 		putcr4(getcr4() | CR4Osfxsr);
85291e577b2SDavid du Colombier 	} else {
85391e577b2SDavid du Colombier 		fpsave = fpx87save;
85491e577b2SDavid du Colombier 		fprestore = fpx87restore;
85591e577b2SDavid du Colombier 	}
85691e577b2SDavid du Colombier 
8577dd7cddfSDavid du Colombier 	cputype = t;
8587dd7cddfSDavid du Colombier 	return t->family;
8597dd7cddfSDavid du Colombier }
8607dd7cddfSDavid du Colombier 
8617dd7cddfSDavid du Colombier static long
cputyperead(Chan *,void * a,long n,vlong offset)86280ee5cbfSDavid du Colombier cputyperead(Chan*, void *a, long n, vlong offset)
8637dd7cddfSDavid du Colombier {
8647dd7cddfSDavid du Colombier 	char str[32];
8657dd7cddfSDavid du Colombier 	ulong mhz;
8667dd7cddfSDavid du Colombier 
8677dd7cddfSDavid du Colombier 	mhz = (m->cpuhz+999999)/1000000;
8687dd7cddfSDavid du Colombier 
8697dd7cddfSDavid du Colombier 	snprint(str, sizeof(str), "%s %lud\n", cputype->name, mhz);
8707dd7cddfSDavid du Colombier 	return readstr(offset, a, n, str);
8717dd7cddfSDavid du Colombier }
8727dd7cddfSDavid du Colombier 
8739a747e4fSDavid du Colombier static long
archctlread(Chan *,void * a,long nn,vlong offset)874fb7f0c93SDavid du Colombier archctlread(Chan*, void *a, long nn, vlong offset)
8759a747e4fSDavid du Colombier {
876fb7f0c93SDavid du Colombier 	int n;
877e4ac449cSDavid du Colombier 	char *buf, *p, *ep;
8789a747e4fSDavid du Colombier 
879e4ac449cSDavid du Colombier 	p = buf = malloc(READSTR);
880aa72973aSDavid du Colombier 	if(p == nil)
881aa72973aSDavid du Colombier 		error(Enomem);
882e4ac449cSDavid du Colombier 	ep = p + READSTR;
883e4ac449cSDavid du Colombier 	p = seprint(p, ep, "cpu %s %lud%s\n",
884fb7f0c93SDavid du Colombier 		cputype->name, (ulong)(m->cpuhz+999999)/1000000,
885fb7f0c93SDavid du Colombier 		m->havepge ? " pge" : "");
886e4ac449cSDavid du Colombier 	p = seprint(p, ep, "pge %s\n", getcr4()&0x80 ? "on" : "off");
887e4ac449cSDavid du Colombier 	p = seprint(p, ep, "coherence ");
888ed250ae1SDavid du Colombier 	if(coherence == mb386)
889e4ac449cSDavid du Colombier 		p = seprint(p, ep, "mb386\n");
890ed250ae1SDavid du Colombier 	else if(coherence == mb586)
891e4ac449cSDavid du Colombier 		p = seprint(p, ep, "mb586\n");
892b1707c5dSDavid du Colombier 	else if(coherence == mfence)
893e4ac449cSDavid du Colombier 		p = seprint(p, ep, "mfence\n");
894ed250ae1SDavid du Colombier 	else if(coherence == nop)
895e4ac449cSDavid du Colombier 		p = seprint(p, ep, "nop\n");
896ed250ae1SDavid du Colombier 	else
897e4ac449cSDavid du Colombier 		p = seprint(p, ep, "0x%p\n", coherence);
898e4ac449cSDavid du Colombier 	p = seprint(p, ep, "cmpswap ");
8993c2ddefeSDavid du Colombier 	if(cmpswap == cmpswap386)
900e4ac449cSDavid du Colombier 		p = seprint(p, ep, "cmpswap386\n");
9013c2ddefeSDavid du Colombier 	else if(cmpswap == cmpswap486)
902e4ac449cSDavid du Colombier 		p = seprint(p, ep, "cmpswap486\n");
9033c2ddefeSDavid du Colombier 	else
904e4ac449cSDavid du Colombier 		p = seprint(p, ep, "0x%p\n", cmpswap);
905e4ac449cSDavid du Colombier 	p = seprint(p, ep, "i8253set %s\n", doi8253set ? "on" : "off");
906e4ac449cSDavid du Colombier 	n = p - buf;
907e4ac449cSDavid du Colombier 	n += mtrrprint(p, ep - p);
908e4ac449cSDavid du Colombier 	buf[n] = '\0';
909e4ac449cSDavid du Colombier 
910e4ac449cSDavid du Colombier 	n = readstr(offset, a, nn, buf);
911e4ac449cSDavid du Colombier 	free(buf);
912e4ac449cSDavid du Colombier 	return n;
9139a747e4fSDavid du Colombier }
914fb7f0c93SDavid du Colombier 
915fb7f0c93SDavid du Colombier enum
916fb7f0c93SDavid du Colombier {
917fb7f0c93SDavid du Colombier 	CMpge,
918fb7f0c93SDavid du Colombier 	CMcoherence,
919fb7f0c93SDavid du Colombier 	CMi8253set,
92026d1d1dfSDavid du Colombier 	CMcache,
921fb7f0c93SDavid du Colombier };
922fb7f0c93SDavid du Colombier 
923fb7f0c93SDavid du Colombier static Cmdtab archctlmsg[] =
924fb7f0c93SDavid du Colombier {
925fb7f0c93SDavid du Colombier 	CMpge,		"pge",		2,
926fb7f0c93SDavid du Colombier 	CMcoherence,	"coherence",	2,
927fb7f0c93SDavid du Colombier 	CMi8253set,	"i8253set",	2,
92826d1d1dfSDavid du Colombier 	CMcache,		"cache",		4,
929fb7f0c93SDavid du Colombier };
9309a747e4fSDavid du Colombier 
9319a747e4fSDavid du Colombier static long
archctlwrite(Chan *,void * a,long n,vlong)932fb7f0c93SDavid du Colombier archctlwrite(Chan*, void *a, long n, vlong)
9339a747e4fSDavid du Colombier {
934e4ac449cSDavid du Colombier 	uvlong base, size;
935fb7f0c93SDavid du Colombier 	Cmdbuf *cb;
936fb7f0c93SDavid du Colombier 	Cmdtab *ct;
93726d1d1dfSDavid du Colombier 	char *ep;
938fb7f0c93SDavid du Colombier 
939fb7f0c93SDavid du Colombier 	cb = parsecmd(a, n);
940fb7f0c93SDavid du Colombier 	if(waserror()){
941fb7f0c93SDavid du Colombier 		free(cb);
942fb7f0c93SDavid du Colombier 		nexterror();
943fb7f0c93SDavid du Colombier 	}
944fb7f0c93SDavid du Colombier 	ct = lookupcmd(cb, archctlmsg, nelem(archctlmsg));
945fb7f0c93SDavid du Colombier 	switch(ct->index){
946fb7f0c93SDavid du Colombier 	case CMpge:
947fb7f0c93SDavid du Colombier 		if(!m->havepge)
948fb7f0c93SDavid du Colombier 			error("processor does not support pge");
949fb7f0c93SDavid du Colombier 		if(strcmp(cb->f[1], "on") == 0)
950fb7f0c93SDavid du Colombier 			putcr4(getcr4() | 0x80);
951fb7f0c93SDavid du Colombier 		else if(strcmp(cb->f[1], "off") == 0)
952fb7f0c93SDavid du Colombier 			putcr4(getcr4() & ~0x80);
953fb7f0c93SDavid du Colombier 		else
954fb7f0c93SDavid du Colombier 			cmderror(cb, "invalid pge ctl");
955fb7f0c93SDavid du Colombier 		break;
956fb7f0c93SDavid du Colombier 	case CMcoherence:
957ed250ae1SDavid du Colombier 		if(strcmp(cb->f[1], "mb386") == 0)
958ed250ae1SDavid du Colombier 			coherence = mb386;
959ed250ae1SDavid du Colombier 		else if(strcmp(cb->f[1], "mb586") == 0){
960ed250ae1SDavid du Colombier 			if(X86FAMILY(m->cpuidax) < 5)
961ed250ae1SDavid du Colombier 				error("invalid coherence ctl on this cpu family");
962ed250ae1SDavid du Colombier 			coherence = mb586;
963b1707c5dSDavid du Colombier 		}else if(strcmp(cb->f[1], "mfence") == 0){
964b1707c5dSDavid du Colombier 			if((m->cpuiddx & Sse2) == 0)
965b1707c5dSDavid du Colombier 				error("invalid coherence ctl on this cpu family");
966b1707c5dSDavid du Colombier 			coherence = mfence;
967b1707c5dSDavid du Colombier 		}else if(strcmp(cb->f[1], "nop") == 0){
968fb7f0c93SDavid du Colombier 			/* only safe on vmware */
969fb7f0c93SDavid du Colombier 			if(conf.nmach > 1)
970fb7f0c93SDavid du Colombier 				error("cannot disable coherence on a multiprocessor");
971fb7f0c93SDavid du Colombier 			coherence = nop;
972fb7f0c93SDavid du Colombier 		}else
973fb7f0c93SDavid du Colombier 			cmderror(cb, "invalid coherence ctl");
974fb7f0c93SDavid du Colombier 		break;
975fb7f0c93SDavid du Colombier 	case CMi8253set:
976fb7f0c93SDavid du Colombier 		if(strcmp(cb->f[1], "on") == 0)
977ed250ae1SDavid du Colombier 			doi8253set = 1;
978dc5a79c1SDavid du Colombier 		else if(strcmp(cb->f[1], "off") == 0){
979ed250ae1SDavid du Colombier 			doi8253set = 0;
980dc5a79c1SDavid du Colombier 			(*arch->timerset)(0);
981dc5a79c1SDavid du Colombier 		}else
982fb7f0c93SDavid du Colombier 			cmderror(cb, "invalid i2853set ctl");
983fb7f0c93SDavid du Colombier 		break;
98426d1d1dfSDavid du Colombier 	case CMcache:
985e4ac449cSDavid du Colombier 		base = strtoull(cb->f[1], &ep, 0);
98626d1d1dfSDavid du Colombier 		if(*ep)
98726d1d1dfSDavid du Colombier 			error("cache: parse error: base not a number?");
988e4ac449cSDavid du Colombier 		size = strtoull(cb->f[2], &ep, 0);
98926d1d1dfSDavid du Colombier 		if(*ep)
99026d1d1dfSDavid du Colombier 			error("cache: parse error: size not a number?");
99126d1d1dfSDavid du Colombier 		mtrr(base, size, cb->f[3]);
99226d1d1dfSDavid du Colombier 		break;
993fb7f0c93SDavid du Colombier 	}
994fb7f0c93SDavid du Colombier 	free(cb);
995fb7f0c93SDavid du Colombier 	poperror();
9969a747e4fSDavid du Colombier 	return n;
9979a747e4fSDavid du Colombier }
9989a747e4fSDavid du Colombier 
9997dd7cddfSDavid du Colombier void
archinit(void)10007dd7cddfSDavid du Colombier archinit(void)
10017dd7cddfSDavid du Colombier {
10027dd7cddfSDavid du Colombier 	PCArch **p;
10037dd7cddfSDavid du Colombier 
10047dd7cddfSDavid du Colombier 	arch = 0;
10057dd7cddfSDavid du Colombier 	for(p = knownarch; *p; p++){
10067dd7cddfSDavid du Colombier 		if((*p)->ident && (*p)->ident() == 0){
10077dd7cddfSDavid du Colombier 			arch = *p;
10087dd7cddfSDavid du Colombier 			break;
10097dd7cddfSDavid du Colombier 		}
10107dd7cddfSDavid du Colombier 	}
10117dd7cddfSDavid du Colombier 	if(arch == 0)
10127dd7cddfSDavid du Colombier 		arch = &archgeneric;
10137dd7cddfSDavid du Colombier 	else{
10147dd7cddfSDavid du Colombier 		if(arch->id == 0)
10157dd7cddfSDavid du Colombier 			arch->id = archgeneric.id;
10167dd7cddfSDavid du Colombier 		if(arch->reset == 0)
10177dd7cddfSDavid du Colombier 			arch->reset = archgeneric.reset;
10187dd7cddfSDavid du Colombier 		if(arch->serialpower == 0)
10197dd7cddfSDavid du Colombier 			arch->serialpower = archgeneric.serialpower;
10207dd7cddfSDavid du Colombier 		if(arch->modempower == 0)
10217dd7cddfSDavid du Colombier 			arch->modempower = archgeneric.modempower;
10227dd7cddfSDavid du Colombier 		if(arch->intrinit == 0)
10237dd7cddfSDavid du Colombier 			arch->intrinit = archgeneric.intrinit;
10247dd7cddfSDavid du Colombier 		if(arch->intrenable == 0)
10257dd7cddfSDavid du Colombier 			arch->intrenable = archgeneric.intrenable;
10267dd7cddfSDavid du Colombier 	}
10277dd7cddfSDavid du Colombier 
10287dd7cddfSDavid du Colombier 	/*
10297dd7cddfSDavid du Colombier 	 *  Decide whether to use copy-on-reference (386 and mp).
10309a747e4fSDavid du Colombier 	 *  We get another chance to set it in mpinit() for a
10319a747e4fSDavid du Colombier 	 *  multiprocessor.
10327dd7cddfSDavid du Colombier 	 */
10339a747e4fSDavid du Colombier 	if(X86FAMILY(m->cpuidax) == 3)
10347dd7cddfSDavid du Colombier 		conf.copymode = 1;
10357dd7cddfSDavid du Colombier 
10363c2ddefeSDavid du Colombier 	if(X86FAMILY(m->cpuidax) >= 4)
10373c2ddefeSDavid du Colombier 		cmpswap = cmpswap486;
10383c2ddefeSDavid du Colombier 
1039ed250ae1SDavid du Colombier 	if(X86FAMILY(m->cpuidax) >= 5)
1040ed250ae1SDavid du Colombier 		coherence = mb586;
1041ed250ae1SDavid du Colombier 
1042b1707c5dSDavid du Colombier 	if(m->cpuiddx & Sse2)
1043b1707c5dSDavid du Colombier 		coherence = mfence;
1044b1707c5dSDavid du Colombier 
104580ee5cbfSDavid du Colombier 	addarchfile("cputype", 0444, cputyperead, nil);
1046fb7f0c93SDavid du Colombier 	addarchfile("archctl", 0664, archctlread, archctlwrite);
10477dd7cddfSDavid du Colombier }
10487dd7cddfSDavid du Colombier 
1049abfa367dSDavid du Colombier void
archrevert(void)1050abfa367dSDavid du Colombier archrevert(void)
1051abfa367dSDavid du Colombier {
1052abfa367dSDavid du Colombier 	arch = &archgeneric;
1053abfa367dSDavid du Colombier }
1054abfa367dSDavid du Colombier 
10557dd7cddfSDavid du Colombier /*
10569a747e4fSDavid du Colombier  *  call either the pcmcia or pccard device setup
10577dd7cddfSDavid du Colombier  */
10589a747e4fSDavid du Colombier int
pcmspecial(char * idstr,ISAConf * isa)10599a747e4fSDavid du Colombier pcmspecial(char *idstr, ISAConf *isa)
10607dd7cddfSDavid du Colombier {
10619a747e4fSDavid du Colombier 	return (_pcmspecial != nil)? _pcmspecial(idstr, isa): -1;
10627dd7cddfSDavid du Colombier }
10637dd7cddfSDavid du Colombier 
10649a747e4fSDavid du Colombier /*
10659a747e4fSDavid du Colombier  *  call either the pcmcia or pccard device teardown
10669a747e4fSDavid du Colombier  */
10679a747e4fSDavid du Colombier void
pcmspecialclose(int a)10689a747e4fSDavid du Colombier pcmspecialclose(int a)
10699a747e4fSDavid du Colombier {
10709a747e4fSDavid du Colombier 	if (_pcmspecialclose != nil)
10719a747e4fSDavid du Colombier 		_pcmspecialclose(a);
10729a747e4fSDavid du Colombier }
10739a747e4fSDavid du Colombier 
10749a747e4fSDavid du Colombier /*
10759a747e4fSDavid du Colombier  *  return value and speed of timer set in arch->clockenable
10769a747e4fSDavid du Colombier  */
10779a747e4fSDavid du Colombier uvlong
fastticks(uvlong * hz)10787dd7cddfSDavid du Colombier fastticks(uvlong *hz)
10797dd7cddfSDavid du Colombier {
10807dd7cddfSDavid du Colombier 	return (*arch->fastclock)(hz);
10817dd7cddfSDavid du Colombier }
10829a747e4fSDavid du Colombier 
1083208510e1SDavid du Colombier ulong
s(void)1084208510e1SDavid du Colombier µs(void)
1085208510e1SDavid du Colombier {
1086208510e1SDavid du Colombier 	return fastticks2us((*arch->fastclock)(nil));
1087208510e1SDavid du Colombier }
1088208510e1SDavid du Colombier 
10899a747e4fSDavid du Colombier /*
10909a747e4fSDavid du Colombier  *  set next timer interrupt
10919a747e4fSDavid du Colombier  */
10929a747e4fSDavid du Colombier void
timerset(Tval x)1093ea58ad6fSDavid du Colombier timerset(Tval x)
10949a747e4fSDavid du Colombier {
1095ed250ae1SDavid du Colombier 	if(doi8253set)
10969a747e4fSDavid du Colombier 		(*arch->timerset)(x);
10979a747e4fSDavid du Colombier }
1098