xref: /plan9-contrib/sys/src/9k/k10/devarch.c (revision 6c88371c8bad86eb867bc4823251f9f00b69c946)
19ef1f84bSDavid du Colombier #include "u.h"
29ef1f84bSDavid du Colombier #include "../port/lib.h"
39ef1f84bSDavid du Colombier #include "mem.h"
49ef1f84bSDavid du Colombier #include "dat.h"
59ef1f84bSDavid du Colombier #include "fns.h"
69ef1f84bSDavid du Colombier #include "../port/error.h"
79ef1f84bSDavid du Colombier 
89ef1f84bSDavid du Colombier #include "ureg.h"
99ef1f84bSDavid du Colombier 
109ef1f84bSDavid du Colombier typedef struct IOMap IOMap;
119ef1f84bSDavid du Colombier struct IOMap
129ef1f84bSDavid du Colombier {
139ef1f84bSDavid du Colombier 	IOMap	*next;
149ef1f84bSDavid du Colombier 	int	reserved;
159ef1f84bSDavid du Colombier 	char	tag[13];
169ef1f84bSDavid du Colombier 	ulong	start;
179ef1f84bSDavid du Colombier 	ulong	end;
189ef1f84bSDavid du Colombier };
199ef1f84bSDavid du Colombier 
209ef1f84bSDavid du Colombier static struct
219ef1f84bSDavid du Colombier {
229ef1f84bSDavid du Colombier 	Lock;
239ef1f84bSDavid du Colombier 	IOMap	*map;
249ef1f84bSDavid du Colombier 	IOMap	*free;
259ef1f84bSDavid du Colombier 	IOMap	maps[32];		// some initial free maps
269ef1f84bSDavid du Colombier 
279ef1f84bSDavid du Colombier 	QLock	ql;			// lock for reading map
289ef1f84bSDavid du Colombier } iomap;
299ef1f84bSDavid du Colombier 
309ef1f84bSDavid du Colombier enum {
319ef1f84bSDavid du Colombier 	Qdir = 0,
329ef1f84bSDavid du Colombier 	Qioalloc = 1,
339ef1f84bSDavid du Colombier 	Qiob,
349ef1f84bSDavid du Colombier 	Qiow,
359ef1f84bSDavid du Colombier 	Qiol,
369ef1f84bSDavid du Colombier 	Qbase,
379ef1f84bSDavid du Colombier 
389ef1f84bSDavid du Colombier 	Qmax = 16,
399ef1f84bSDavid du Colombier };
409ef1f84bSDavid du Colombier 
419ef1f84bSDavid du Colombier typedef long Rdwrfn(Chan*, void*, long, vlong);
429ef1f84bSDavid du Colombier 
439ef1f84bSDavid du Colombier static Rdwrfn *readfn[Qmax];
449ef1f84bSDavid du Colombier static Rdwrfn *writefn[Qmax];
459ef1f84bSDavid du Colombier 
469ef1f84bSDavid du Colombier static Dirtab archdir[Qmax] = {
479ef1f84bSDavid du Colombier 	".",		{ Qdir, 0, QTDIR },	0,	0555,
489ef1f84bSDavid du Colombier 	"ioalloc",	{ Qioalloc, 0 },	0,	0444,
499ef1f84bSDavid du Colombier 	"iob",		{ Qiob, 0 },		0,	0660,
509ef1f84bSDavid du Colombier 	"iow",		{ Qiow, 0 },		0,	0660,
519ef1f84bSDavid du Colombier 	"iol",		{ Qiol, 0 },		0,	0660,
529ef1f84bSDavid du Colombier };
539ef1f84bSDavid du Colombier Lock archwlock;	/* the lock is only for changing archdir */
549ef1f84bSDavid du Colombier int narchdir = Qbase;
559ef1f84bSDavid du Colombier 
569ef1f84bSDavid du Colombier /*
579ef1f84bSDavid du Colombier  * Add a file to the #P listing.  Once added, you can't delete it.
589ef1f84bSDavid du Colombier  * You can't add a file with the same name as one already there,
599ef1f84bSDavid du Colombier  * and you get a pointer to the Dirtab entry so you can do things
609ef1f84bSDavid du Colombier  * like change the Qid version.  Changing the Qid path is disallowed.
619ef1f84bSDavid du Colombier  */
629ef1f84bSDavid du Colombier Dirtab*
addarchfile(char * name,int perm,Rdwrfn * rdfn,Rdwrfn * wrfn)639ef1f84bSDavid du Colombier addarchfile(char *name, int perm, Rdwrfn *rdfn, Rdwrfn *wrfn)
649ef1f84bSDavid du Colombier {
659ef1f84bSDavid du Colombier 	int i;
669ef1f84bSDavid du Colombier 	Dirtab d;
679ef1f84bSDavid du Colombier 	Dirtab *dp;
689ef1f84bSDavid du Colombier 
699ef1f84bSDavid du Colombier 	memset(&d, 0, sizeof d);
709ef1f84bSDavid du Colombier 	strcpy(d.name, name);
719ef1f84bSDavid du Colombier 	d.perm = perm;
729ef1f84bSDavid du Colombier 
739ef1f84bSDavid du Colombier 	lock(&archwlock);
749ef1f84bSDavid du Colombier 	if(narchdir >= Qmax){
759ef1f84bSDavid du Colombier 		unlock(&archwlock);
769ef1f84bSDavid du Colombier 		return nil;
779ef1f84bSDavid du Colombier 	}
789ef1f84bSDavid du Colombier 
799ef1f84bSDavid du Colombier 	for(i=0; i<narchdir; i++)
809ef1f84bSDavid du Colombier 		if(strcmp(archdir[i].name, name) == 0){
819ef1f84bSDavid du Colombier 			unlock(&archwlock);
829ef1f84bSDavid du Colombier 			return nil;
839ef1f84bSDavid du Colombier 		}
849ef1f84bSDavid du Colombier 
859ef1f84bSDavid du Colombier 	d.qid.path = narchdir;
869ef1f84bSDavid du Colombier 	archdir[narchdir] = d;
879ef1f84bSDavid du Colombier 	readfn[narchdir] = rdfn;
889ef1f84bSDavid du Colombier 	writefn[narchdir] = wrfn;
899ef1f84bSDavid du Colombier 	dp = &archdir[narchdir++];
909ef1f84bSDavid du Colombier 	unlock(&archwlock);
919ef1f84bSDavid du Colombier 
929ef1f84bSDavid du Colombier 	return dp;
939ef1f84bSDavid du Colombier }
949ef1f84bSDavid du Colombier 
959ef1f84bSDavid du Colombier void
ioinit(void)969ef1f84bSDavid du Colombier ioinit(void)
979ef1f84bSDavid du Colombier {
989ef1f84bSDavid du Colombier 	char *excluded;
999ef1f84bSDavid du Colombier 	int i;
1009ef1f84bSDavid du Colombier 
1019ef1f84bSDavid du Colombier 	for(i = 0; i < nelem(iomap.maps)-1; i++)
1029ef1f84bSDavid du Colombier 		iomap.maps[i].next = &iomap.maps[i+1];
1039ef1f84bSDavid du Colombier 	iomap.maps[i].next = nil;
1049ef1f84bSDavid du Colombier 	iomap.free = iomap.maps;
1059ef1f84bSDavid du Colombier 
1069ef1f84bSDavid du Colombier 	/*
1079ef1f84bSDavid du Colombier 	 * Someone needs to explain why this was here...
1089ef1f84bSDavid du Colombier 	 */
1099ef1f84bSDavid du Colombier 	ioalloc(0x0fff, 1, 0, "dummy");	// i82557 is at 0x1000, the dummy
1109ef1f84bSDavid du Colombier 					// entry is needed for swappable devs.
1119ef1f84bSDavid du Colombier 
1129ef1f84bSDavid du Colombier 	if ((excluded = getconf("ioexclude")) != nil) {
1139ef1f84bSDavid du Colombier 		char *s;
1149ef1f84bSDavid du Colombier 
1159ef1f84bSDavid du Colombier 		s = excluded;
1169ef1f84bSDavid du Colombier 		while (s && *s != '\0' && *s != '\n') {
1179ef1f84bSDavid du Colombier 			char *ends;
1189ef1f84bSDavid du Colombier 			int io_s, io_e;
1199ef1f84bSDavid du Colombier 
1209ef1f84bSDavid du Colombier 			io_s = (int)strtol(s, &ends, 0);
1219ef1f84bSDavid du Colombier 			if (ends == nil || ends == s || *ends != '-') {
1229ef1f84bSDavid du Colombier 				print("ioinit: cannot parse option string\n");
1239ef1f84bSDavid du Colombier 				break;
1249ef1f84bSDavid du Colombier 			}
1259ef1f84bSDavid du Colombier 			s = ++ends;
1269ef1f84bSDavid du Colombier 
1279ef1f84bSDavid du Colombier 			io_e = (int)strtol(s, &ends, 0);
1289ef1f84bSDavid du Colombier 			if (ends && *ends == ',')
1299ef1f84bSDavid du Colombier 				*ends++ = '\0';
1309ef1f84bSDavid du Colombier 			s = ends;
1319ef1f84bSDavid du Colombier 
1329ef1f84bSDavid du Colombier 			ioalloc(io_s, io_e - io_s + 1, 0, "pre-allocated");
1339ef1f84bSDavid du Colombier 		}
1349ef1f84bSDavid du Colombier 	}
1359ef1f84bSDavid du Colombier 
1369ef1f84bSDavid du Colombier }
1379ef1f84bSDavid du Colombier 
1389ef1f84bSDavid du Colombier // Reserve a range to be ioalloced later.
1399ef1f84bSDavid du Colombier // This is in particular useful for exchangable cards, such
1409ef1f84bSDavid du Colombier // as pcmcia and cardbus cards.
1419ef1f84bSDavid du Colombier int
ioreserve(int,int size,int align,char * tag)1429ef1f84bSDavid du Colombier ioreserve(int, int size, int align, char *tag)
1439ef1f84bSDavid du Colombier {
1449ef1f84bSDavid du Colombier 	IOMap *map, **l;
1459ef1f84bSDavid du Colombier 	int i, port;
1469ef1f84bSDavid du Colombier 
1479ef1f84bSDavid du Colombier 	lock(&iomap);
1489ef1f84bSDavid du Colombier 	// find a free port above 0x400 and below 0x1000
1499ef1f84bSDavid du Colombier 	port = 0x400;
1509ef1f84bSDavid du Colombier 	for(l = &iomap.map; *l; l = &(*l)->next){
1519ef1f84bSDavid du Colombier 		map = *l;
1529ef1f84bSDavid du Colombier 		if (map->start < 0x400)
1539ef1f84bSDavid du Colombier 			continue;
1549ef1f84bSDavid du Colombier 		i = map->start - port;
1559ef1f84bSDavid du Colombier 		if(i > size)
1569ef1f84bSDavid du Colombier 			break;
1579ef1f84bSDavid du Colombier 		if(align > 0)
1589ef1f84bSDavid du Colombier 			port = ((port+align-1)/align)*align;
1599ef1f84bSDavid du Colombier 		else
1609ef1f84bSDavid du Colombier 			port = map->end;
1619ef1f84bSDavid du Colombier 	}
1629ef1f84bSDavid du Colombier 	if(*l == nil){
1639ef1f84bSDavid du Colombier 		unlock(&iomap);
1649ef1f84bSDavid du Colombier 		return -1;
1659ef1f84bSDavid du Colombier 	}
1669ef1f84bSDavid du Colombier 	map = iomap.free;
1679ef1f84bSDavid du Colombier 	if(map == nil){
1689ef1f84bSDavid du Colombier 		print("ioalloc: out of maps");
1699ef1f84bSDavid du Colombier 		unlock(&iomap);
1709ef1f84bSDavid du Colombier 		return port;
1719ef1f84bSDavid du Colombier 	}
1729ef1f84bSDavid du Colombier 	iomap.free = map->next;
1739ef1f84bSDavid du Colombier 	map->next = *l;
1749ef1f84bSDavid du Colombier 	map->start = port;
1759ef1f84bSDavid du Colombier 	map->end = port + size;
1769ef1f84bSDavid du Colombier 	map->reserved = 1;
1779ef1f84bSDavid du Colombier 	strncpy(map->tag, tag, sizeof(map->tag));
1789ef1f84bSDavid du Colombier 	map->tag[sizeof(map->tag)-1] = 0;
1799ef1f84bSDavid du Colombier 	*l = map;
1809ef1f84bSDavid du Colombier 
1819ef1f84bSDavid du Colombier 	archdir[0].qid.vers++;
1829ef1f84bSDavid du Colombier 
1839ef1f84bSDavid du Colombier 	unlock(&iomap);
1849ef1f84bSDavid du Colombier 	return map->start;
1859ef1f84bSDavid du Colombier }
1869ef1f84bSDavid du Colombier 
1879ef1f84bSDavid du Colombier //
1889ef1f84bSDavid du Colombier //	alloc some io port space and remember who it was
1899ef1f84bSDavid du Colombier //	alloced to.  if port < 0, find a free region.
1909ef1f84bSDavid du Colombier //
1919ef1f84bSDavid du Colombier int
ioalloc(int port,int size,int align,char * tag)1929ef1f84bSDavid du Colombier ioalloc(int port, int size, int align, char *tag)
1939ef1f84bSDavid du Colombier {
1949ef1f84bSDavid du Colombier 	IOMap *map, **l;
1959ef1f84bSDavid du Colombier 	int i;
1969ef1f84bSDavid du Colombier 
1979ef1f84bSDavid du Colombier 	lock(&iomap);
1989ef1f84bSDavid du Colombier 	if(port < 0){
1999ef1f84bSDavid du Colombier 		// find a free port above 0x400 and below 0x1000
2009ef1f84bSDavid du Colombier 		port = 0x400;
2019ef1f84bSDavid du Colombier 		for(l = &iomap.map; *l; l = &(*l)->next){
2029ef1f84bSDavid du Colombier 			map = *l;
2039ef1f84bSDavid du Colombier 			if (map->start < 0x400)
2049ef1f84bSDavid du Colombier 				continue;
2059ef1f84bSDavid du Colombier 			i = map->start - port;
2069ef1f84bSDavid du Colombier 			if(i > size)
2079ef1f84bSDavid du Colombier 				break;
2089ef1f84bSDavid du Colombier 			if(align > 0)
2099ef1f84bSDavid du Colombier 				port = ((port+align-1)/align)*align;
2109ef1f84bSDavid du Colombier 			else
2119ef1f84bSDavid du Colombier 				port = map->end;
2129ef1f84bSDavid du Colombier 		}
2139ef1f84bSDavid du Colombier 		if(*l == nil){
2149ef1f84bSDavid du Colombier 			unlock(&iomap);
2159ef1f84bSDavid du Colombier 			return -1;
2169ef1f84bSDavid du Colombier 		}
2179ef1f84bSDavid du Colombier 	} else {
2189ef1f84bSDavid du Colombier 		// Only 64KB I/O space on the x86.
2199ef1f84bSDavid du Colombier 		if((port+size) > 0x10000){
2209ef1f84bSDavid du Colombier 			unlock(&iomap);
2219ef1f84bSDavid du Colombier 			return -1;
2229ef1f84bSDavid du Colombier 		}
2239ef1f84bSDavid du Colombier 		// see if the space clashes with previously allocated ports
2249ef1f84bSDavid du Colombier 		for(l = &iomap.map; *l; l = &(*l)->next){
2259ef1f84bSDavid du Colombier 			map = *l;
2269ef1f84bSDavid du Colombier 			if(map->end <= port)
2279ef1f84bSDavid du Colombier 				continue;
2289ef1f84bSDavid du Colombier 			if(map->reserved && map->start == port && map->end == port + size) {
2299ef1f84bSDavid du Colombier 				map->reserved = 0;
2309ef1f84bSDavid du Colombier 				unlock(&iomap);
2319ef1f84bSDavid du Colombier 				return map->start;
2329ef1f84bSDavid du Colombier 			}
2339ef1f84bSDavid du Colombier 			if(map->start >= port+size)
2349ef1f84bSDavid du Colombier 				break;
2359ef1f84bSDavid du Colombier 			unlock(&iomap);
2369ef1f84bSDavid du Colombier 			return -1;
2379ef1f84bSDavid du Colombier 		}
2389ef1f84bSDavid du Colombier 	}
2399ef1f84bSDavid du Colombier 	map = iomap.free;
2409ef1f84bSDavid du Colombier 	if(map == nil){
2419ef1f84bSDavid du Colombier 		print("ioalloc: out of maps");
2429ef1f84bSDavid du Colombier 		unlock(&iomap);
2439ef1f84bSDavid du Colombier 		return port;
2449ef1f84bSDavid du Colombier 	}
2459ef1f84bSDavid du Colombier 	iomap.free = map->next;
2469ef1f84bSDavid du Colombier 	map->next = *l;
2479ef1f84bSDavid du Colombier 	map->start = port;
2489ef1f84bSDavid du Colombier 	map->end = port + size;
2499ef1f84bSDavid du Colombier 	strncpy(map->tag, tag, sizeof(map->tag));
2509ef1f84bSDavid du Colombier 	map->tag[sizeof(map->tag)-1] = 0;
2519ef1f84bSDavid du Colombier 	*l = map;
2529ef1f84bSDavid du Colombier 
2539ef1f84bSDavid du Colombier 	archdir[0].qid.vers++;
2549ef1f84bSDavid du Colombier 
2559ef1f84bSDavid du Colombier 	unlock(&iomap);
2569ef1f84bSDavid du Colombier 	return map->start;
2579ef1f84bSDavid du Colombier }
2589ef1f84bSDavid du Colombier 
2599ef1f84bSDavid du Colombier void
iofree(int port)2609ef1f84bSDavid du Colombier iofree(int port)
2619ef1f84bSDavid du Colombier {
2629ef1f84bSDavid du Colombier 	IOMap *map, **l;
2639ef1f84bSDavid du Colombier 
2649ef1f84bSDavid du Colombier 	lock(&iomap);
2659ef1f84bSDavid du Colombier 	for(l = &iomap.map; *l; l = &(*l)->next){
2669ef1f84bSDavid du Colombier 		if((*l)->start == port){
2679ef1f84bSDavid du Colombier 			map = *l;
2689ef1f84bSDavid du Colombier 			*l = map->next;
2699ef1f84bSDavid du Colombier 			map->next = iomap.free;
2709ef1f84bSDavid du Colombier 			iomap.free = map;
2719ef1f84bSDavid du Colombier 			break;
2729ef1f84bSDavid du Colombier 		}
2739ef1f84bSDavid du Colombier 		if((*l)->start > port)
2749ef1f84bSDavid du Colombier 			break;
2759ef1f84bSDavid du Colombier 	}
2769ef1f84bSDavid du Colombier 	archdir[0].qid.vers++;
2779ef1f84bSDavid du Colombier 	unlock(&iomap);
2789ef1f84bSDavid du Colombier }
2799ef1f84bSDavid du Colombier 
2809ef1f84bSDavid du Colombier int
iounused(int start,int end)2819ef1f84bSDavid du Colombier iounused(int start, int end)
2829ef1f84bSDavid du Colombier {
2839ef1f84bSDavid du Colombier 	IOMap *map;
2849ef1f84bSDavid du Colombier 
2859ef1f84bSDavid du Colombier 	for(map = iomap.map; map; map = map->next){
2869ef1f84bSDavid du Colombier 		if(start >= map->start && start < map->end
2879ef1f84bSDavid du Colombier 		|| start <= map->start && end > map->start)
2889ef1f84bSDavid du Colombier 			return 0;
2899ef1f84bSDavid du Colombier 	}
2909ef1f84bSDavid du Colombier 	return 1;
2919ef1f84bSDavid du Colombier }
2929ef1f84bSDavid du Colombier 
2939ef1f84bSDavid du Colombier static void
checkport(int start,int end)2949ef1f84bSDavid du Colombier checkport(int start, int end)
2959ef1f84bSDavid du Colombier {
2969ef1f84bSDavid du Colombier 	/* standard vga regs are OK */
2979ef1f84bSDavid du Colombier 	if(start >= 0x2b0 && end <= 0x2df+1)
2989ef1f84bSDavid du Colombier 		return;
2999ef1f84bSDavid du Colombier 	if(start >= 0x3c0 && end <= 0x3da+1)
3009ef1f84bSDavid du Colombier 		return;
3019ef1f84bSDavid du Colombier 
3029ef1f84bSDavid du Colombier 	if(iounused(start, end))
3039ef1f84bSDavid du Colombier 		return;
3049ef1f84bSDavid du Colombier 	error(Eperm);
3059ef1f84bSDavid du Colombier }
3069ef1f84bSDavid du Colombier 
3079ef1f84bSDavid du Colombier static Chan*
archattach(char * spec)3089ef1f84bSDavid du Colombier archattach(char* spec)
3099ef1f84bSDavid du Colombier {
3109ef1f84bSDavid du Colombier 	return devattach('P', spec);
3119ef1f84bSDavid du Colombier }
3129ef1f84bSDavid du Colombier 
3139ef1f84bSDavid du Colombier Walkqid*
archwalk(Chan * c,Chan * nc,char ** name,int nname)3149ef1f84bSDavid du Colombier archwalk(Chan* c, Chan *nc, char** name, int nname)
3159ef1f84bSDavid du Colombier {
3169ef1f84bSDavid du Colombier 	return devwalk(c, nc, name, nname, archdir, narchdir, devgen);
3179ef1f84bSDavid du Colombier }
3189ef1f84bSDavid du Colombier 
3199ef1f84bSDavid du Colombier static long
archstat(Chan * c,uchar * dp,long n)3209ef1f84bSDavid du Colombier archstat(Chan* c, uchar* dp, long n)
3219ef1f84bSDavid du Colombier {
3229ef1f84bSDavid du Colombier 	return devstat(c, dp, n, archdir, narchdir, devgen);
3239ef1f84bSDavid du Colombier }
3249ef1f84bSDavid du Colombier 
3259ef1f84bSDavid du Colombier static Chan*
archopen(Chan * c,int omode)3269ef1f84bSDavid du Colombier archopen(Chan* c, int omode)
3279ef1f84bSDavid du Colombier {
3289ef1f84bSDavid du Colombier 	return devopen(c, omode, archdir, narchdir, devgen);
3299ef1f84bSDavid du Colombier }
3309ef1f84bSDavid du Colombier 
3319ef1f84bSDavid du Colombier static void
archclose(Chan *)3329ef1f84bSDavid du Colombier archclose(Chan*)
3339ef1f84bSDavid du Colombier {
3349ef1f84bSDavid du Colombier }
3359ef1f84bSDavid du Colombier 
3369ef1f84bSDavid du Colombier enum
3379ef1f84bSDavid du Colombier {
3389ef1f84bSDavid du Colombier 	Linelen= 31,
3399ef1f84bSDavid du Colombier };
3409ef1f84bSDavid du Colombier 
3419ef1f84bSDavid du Colombier static long
archread(Chan * c,void * a,long n,vlong offset)3429ef1f84bSDavid du Colombier archread(Chan *c, void *a, long n, vlong offset)
3439ef1f84bSDavid du Colombier {
3449ef1f84bSDavid du Colombier 	char *buf, *p;
3459ef1f84bSDavid du Colombier 	int port;
3469ef1f84bSDavid du Colombier 	ushort *sp;
3479ef1f84bSDavid du Colombier 	ulong *lp;
3489ef1f84bSDavid du Colombier 	IOMap *map;
3499ef1f84bSDavid du Colombier 	Rdwrfn *fn;
3509ef1f84bSDavid du Colombier 
3519ef1f84bSDavid du Colombier 	switch((ulong)c->qid.path){
3529ef1f84bSDavid du Colombier 
3539ef1f84bSDavid du Colombier 	case Qdir:
3549ef1f84bSDavid du Colombier 		return devdirread(c, a, n, archdir, narchdir, devgen);
3559ef1f84bSDavid du Colombier 
3569ef1f84bSDavid du Colombier 	case Qiob:
3579ef1f84bSDavid du Colombier 		port = offset;
3589ef1f84bSDavid du Colombier 		checkport(offset, offset+n);
3599ef1f84bSDavid du Colombier 		for(p = a; port < offset+n; port++)
3609ef1f84bSDavid du Colombier 			*p++ = inb(port);
3619ef1f84bSDavid du Colombier 		return n;
3629ef1f84bSDavid du Colombier 
3639ef1f84bSDavid du Colombier 	case Qiow:
3649ef1f84bSDavid du Colombier 		if(n & 1)
3659ef1f84bSDavid du Colombier 			error(Ebadarg);
3669ef1f84bSDavid du Colombier 		checkport(offset, offset+n);
3679ef1f84bSDavid du Colombier 		sp = a;
3689ef1f84bSDavid du Colombier 		for(port = offset; port < offset+n; port += 2)
3699ef1f84bSDavid du Colombier 			*sp++ = ins(port);
3709ef1f84bSDavid du Colombier 		return n;
3719ef1f84bSDavid du Colombier 
3729ef1f84bSDavid du Colombier 	case Qiol:
3739ef1f84bSDavid du Colombier 		if(n & 3)
3749ef1f84bSDavid du Colombier 			error(Ebadarg);
3759ef1f84bSDavid du Colombier 		checkport(offset, offset+n);
3769ef1f84bSDavid du Colombier 		lp = a;
3779ef1f84bSDavid du Colombier 		for(port = offset; port < offset+n; port += 4)
3789ef1f84bSDavid du Colombier 			*lp++ = inl(port);
3799ef1f84bSDavid du Colombier 		return n;
3809ef1f84bSDavid du Colombier 
3819ef1f84bSDavid du Colombier 	case Qioalloc:
3829ef1f84bSDavid du Colombier 		break;
3839ef1f84bSDavid du Colombier 
3849ef1f84bSDavid du Colombier 	default:
3859ef1f84bSDavid du Colombier 		if(c->qid.path < narchdir && (fn = readfn[c->qid.path]))
3869ef1f84bSDavid du Colombier 			return fn(c, a, n, offset);
3879ef1f84bSDavid du Colombier 		error(Eperm);
3889ef1f84bSDavid du Colombier 		break;
3899ef1f84bSDavid du Colombier 	}
3909ef1f84bSDavid du Colombier 
3919ef1f84bSDavid du Colombier 	if((buf = malloc(n)) == nil)
3929ef1f84bSDavid du Colombier 		error(Enomem);
3939ef1f84bSDavid du Colombier 	p = buf;
3949ef1f84bSDavid du Colombier 	n = n/Linelen;
3959ef1f84bSDavid du Colombier 	offset = offset/Linelen;
3969ef1f84bSDavid du Colombier 
3979ef1f84bSDavid du Colombier 	lock(&iomap);
3989ef1f84bSDavid du Colombier 	for(map = iomap.map; n > 0 && map != nil; map = map->next){
3999ef1f84bSDavid du Colombier 		if(offset-- > 0)
4009ef1f84bSDavid du Colombier 			continue;
4019ef1f84bSDavid du Colombier 		sprint(p, "%#8lux %#8lux %-12.12s\n", map->start, map->end-1, map->tag);
4029ef1f84bSDavid du Colombier 		p += Linelen;
4039ef1f84bSDavid du Colombier 		n--;
4049ef1f84bSDavid du Colombier 	}
4059ef1f84bSDavid du Colombier 	unlock(&iomap);
4069ef1f84bSDavid du Colombier 
4079ef1f84bSDavid du Colombier 	n = p - buf;
4089ef1f84bSDavid du Colombier 	memmove(a, buf, n);
4099ef1f84bSDavid du Colombier 	free(buf);
4109ef1f84bSDavid du Colombier 
4119ef1f84bSDavid du Colombier 	return n;
4129ef1f84bSDavid du Colombier }
4139ef1f84bSDavid du Colombier 
4149ef1f84bSDavid du Colombier static long
archwrite(Chan * c,void * a,long n,vlong offset)4159ef1f84bSDavid du Colombier archwrite(Chan *c, void *a, long n, vlong offset)
4169ef1f84bSDavid du Colombier {
4179ef1f84bSDavid du Colombier 	char *p;
4189ef1f84bSDavid du Colombier 	int port;
4199ef1f84bSDavid du Colombier 	ushort *sp;
4209ef1f84bSDavid du Colombier 	ulong *lp;
4219ef1f84bSDavid du Colombier 	Rdwrfn *fn;
4229ef1f84bSDavid du Colombier 
4239ef1f84bSDavid du Colombier 	switch((ulong)c->qid.path){
4249ef1f84bSDavid du Colombier 
4259ef1f84bSDavid du Colombier 	case Qiob:
4269ef1f84bSDavid du Colombier 		p = a;
4279ef1f84bSDavid du Colombier 		checkport(offset, offset+n);
4289ef1f84bSDavid du Colombier 		for(port = offset; port < offset+n; port++)
4299ef1f84bSDavid du Colombier 			outb(port, *p++);
4309ef1f84bSDavid du Colombier 		return n;
4319ef1f84bSDavid du Colombier 
4329ef1f84bSDavid du Colombier 	case Qiow:
4339ef1f84bSDavid du Colombier 		if(n & 1)
4349ef1f84bSDavid du Colombier 			error(Ebadarg);
4359ef1f84bSDavid du Colombier 		checkport(offset, offset+n);
4369ef1f84bSDavid du Colombier 		sp = a;
4379ef1f84bSDavid du Colombier 		for(port = offset; port < offset+n; port += 2)
4389ef1f84bSDavid du Colombier 			outs(port, *sp++);
4399ef1f84bSDavid du Colombier 		return n;
4409ef1f84bSDavid du Colombier 
4419ef1f84bSDavid du Colombier 	case Qiol:
4429ef1f84bSDavid du Colombier 		if(n & 3)
4439ef1f84bSDavid du Colombier 			error(Ebadarg);
4449ef1f84bSDavid du Colombier 		checkport(offset, offset+n);
4459ef1f84bSDavid du Colombier 		lp = a;
4469ef1f84bSDavid du Colombier 		for(port = offset; port < offset+n; port += 4)
4479ef1f84bSDavid du Colombier 			outl(port, *lp++);
4489ef1f84bSDavid du Colombier 		return n;
4499ef1f84bSDavid du Colombier 
4509ef1f84bSDavid du Colombier 	default:
4519ef1f84bSDavid du Colombier 		if(c->qid.path < narchdir && (fn = writefn[c->qid.path]))
4529ef1f84bSDavid du Colombier 			return fn(c, a, n, offset);
4539ef1f84bSDavid du Colombier 		error(Eperm);
4549ef1f84bSDavid du Colombier 		break;
4559ef1f84bSDavid du Colombier 	}
4569ef1f84bSDavid du Colombier 	return 0;
4579ef1f84bSDavid du Colombier }
4589ef1f84bSDavid du Colombier 
4599ef1f84bSDavid du Colombier Dev archdevtab = {
4609ef1f84bSDavid du Colombier 	'P',
4619ef1f84bSDavid du Colombier 	"arch",
4629ef1f84bSDavid du Colombier 
4639ef1f84bSDavid du Colombier 	devreset,
4649ef1f84bSDavid du Colombier 	devinit,
4659ef1f84bSDavid du Colombier 	devshutdown,
4669ef1f84bSDavid du Colombier 	archattach,
4679ef1f84bSDavid du Colombier 	archwalk,
4689ef1f84bSDavid du Colombier 	archstat,
4699ef1f84bSDavid du Colombier 	archopen,
4709ef1f84bSDavid du Colombier 	devcreate,
4719ef1f84bSDavid du Colombier 	archclose,
4729ef1f84bSDavid du Colombier 	archread,
4739ef1f84bSDavid du Colombier 	devbread,
4749ef1f84bSDavid du Colombier 	archwrite,
4759ef1f84bSDavid du Colombier 	devbwrite,
4769ef1f84bSDavid du Colombier 	devremove,
4779ef1f84bSDavid du Colombier 	devwstat,
4789ef1f84bSDavid du Colombier };
4799ef1f84bSDavid du Colombier 
4809ef1f84bSDavid du Colombier /*
4819ef1f84bSDavid du Colombier  */
4829ef1f84bSDavid du Colombier void
nop(void)4839ef1f84bSDavid du Colombier nop(void)
4849ef1f84bSDavid du Colombier {
4859ef1f84bSDavid du Colombier }
4869ef1f84bSDavid du Colombier 
4879ef1f84bSDavid du Colombier void (*coherence)(void) = mfence;
4889ef1f84bSDavid du Colombier 
4899ef1f84bSDavid du Colombier static long
cputyperead(Chan *,void * a,long n,vlong off)4909ef1f84bSDavid du Colombier cputyperead(Chan*, void *a, long n, vlong off)
4919ef1f84bSDavid du Colombier {
4929ef1f84bSDavid du Colombier 	char str[32];
4939ef1f84bSDavid du Colombier 
4949ef1f84bSDavid du Colombier 	snprint(str, sizeof(str), "%s %ud\n", "AMD64", m->cpumhz);
4959ef1f84bSDavid du Colombier 	return readstr(off, a, n, str);
4969ef1f84bSDavid du Colombier }
4979ef1f84bSDavid du Colombier 
4989ef1f84bSDavid du Colombier void
archinit(void)4999ef1f84bSDavid du Colombier archinit(void)
5009ef1f84bSDavid du Colombier {
5019ef1f84bSDavid du Colombier 	addarchfile("cputype", 0444, cputyperead, nil);
5029ef1f84bSDavid du Colombier }
5039ef1f84bSDavid du Colombier 
5049ef1f84bSDavid du Colombier void
archreset(void)5059ef1f84bSDavid du Colombier archreset(void)
5069ef1f84bSDavid du Colombier {
5079ef1f84bSDavid du Colombier 	int i;
5089ef1f84bSDavid du Colombier 
5099ef1f84bSDavid du Colombier 	/*
5109ef1f84bSDavid du Colombier 	 * And sometimes there is no keyboard...
5119ef1f84bSDavid du Colombier 	 *
5129ef1f84bSDavid du Colombier 	 * The reset register (0xcf9) is usually in one of the bridge
5139ef1f84bSDavid du Colombier 	 * chips. The actual location and sequence could be extracted from
5149ef1f84bSDavid du Colombier 	 * ACPI but why bother, this is the end of the line anyway.
5159ef1f84bSDavid du Colombier 	print("Takes a licking and keeps on ticking...\n");
5169ef1f84bSDavid du Colombier 	 */
5179ef1f84bSDavid du Colombier 	i = inb(0xcf9);					/* ICHx reset control */
5189ef1f84bSDavid du Colombier 	i &= 0x06;
5199ef1f84bSDavid du Colombier 	outb(0xcf9, i|0x02);				/* SYS_RST */
5209ef1f84bSDavid du Colombier 	millidelay(1);
5219ef1f84bSDavid du Colombier 	outb(0xcf9, i|0x06);				/* RST_CPU transition */
5229ef1f84bSDavid du Colombier 
5239ef1f84bSDavid du Colombier 	for(;;)
524*6c88371cSDavid du Colombier 		pause();
5259ef1f84bSDavid du Colombier }
5269ef1f84bSDavid du Colombier 
5279ef1f84bSDavid du Colombier /*
5289ef1f84bSDavid du Colombier  *  return value and speed of timer
5299ef1f84bSDavid du Colombier  */
5309ef1f84bSDavid du Colombier uvlong
fastticks(uvlong * hz)5319ef1f84bSDavid du Colombier fastticks(uvlong* hz)
5329ef1f84bSDavid du Colombier {
5339ef1f84bSDavid du Colombier 	if(hz != nil)
5349ef1f84bSDavid du Colombier 		*hz = m->cpuhz;
5359ef1f84bSDavid du Colombier 	return rdtsc();
5369ef1f84bSDavid du Colombier }
5379ef1f84bSDavid du Colombier 
5389ef1f84bSDavid du Colombier ulong
s(void)5399ef1f84bSDavid du Colombier µs(void)
5409ef1f84bSDavid du Colombier {
5419ef1f84bSDavid du Colombier 	return fastticks2us(rdtsc());
5429ef1f84bSDavid du Colombier }
5439ef1f84bSDavid du Colombier 
5449ef1f84bSDavid du Colombier /*
5459ef1f84bSDavid du Colombier  *  set next timer interrupt
5469ef1f84bSDavid du Colombier  */
5479ef1f84bSDavid du Colombier void
timerset(uvlong x)5489ef1f84bSDavid du Colombier timerset(uvlong x)
5499ef1f84bSDavid du Colombier {
5509ef1f84bSDavid du Colombier 	extern void apictimerset(uvlong);
5519ef1f84bSDavid du Colombier 
5529ef1f84bSDavid du Colombier 	apictimerset(x);
5539ef1f84bSDavid du Colombier }
5549ef1f84bSDavid du Colombier 
5559ef1f84bSDavid du Colombier void
cycles(uvlong * t)5569ef1f84bSDavid du Colombier cycles(uvlong* t)
5579ef1f84bSDavid du Colombier {
5589ef1f84bSDavid du Colombier 	*t = rdtsc();
5599ef1f84bSDavid du Colombier }
5609ef1f84bSDavid du Colombier 
5619ef1f84bSDavid du Colombier void
delay(int millisecs)5629ef1f84bSDavid du Colombier delay(int millisecs)
5639ef1f84bSDavid du Colombier {
5649ef1f84bSDavid du Colombier 	u64int r, t;
5659ef1f84bSDavid du Colombier 
5669ef1f84bSDavid du Colombier 	if(millisecs <= 0)
5679ef1f84bSDavid du Colombier 		millisecs = 1;
5689ef1f84bSDavid du Colombier 	r = rdtsc();
5699ef1f84bSDavid du Colombier 	for(t = r + m->cpumhz*1000ull*millisecs; r < t; r = rdtsc())
5709ef1f84bSDavid du Colombier 		;
5719ef1f84bSDavid du Colombier }
5729ef1f84bSDavid du Colombier 
5739ef1f84bSDavid du Colombier /*
5749ef1f84bSDavid du Colombier  *  performance measurement ticks.  must be low overhead.
5759ef1f84bSDavid du Colombier  *  doesn't have to count over a second.
5769ef1f84bSDavid du Colombier  */
5779ef1f84bSDavid du Colombier ulong
perfticks(void)5789ef1f84bSDavid du Colombier perfticks(void)
5799ef1f84bSDavid du Colombier {
5809ef1f84bSDavid du Colombier 	uvlong x;
5819ef1f84bSDavid du Colombier 
5829ef1f84bSDavid du Colombier //	if(m->havetsc)
5839ef1f84bSDavid du Colombier 		cycles(&x);
5849ef1f84bSDavid du Colombier //	else
5859ef1f84bSDavid du Colombier //		x = 0;
5869ef1f84bSDavid du Colombier 	return x;
5879ef1f84bSDavid du Colombier }
588