shithub: riscv

Download patch

ref: 9cca88895e31c73d4d0793dd83f76ebd24456cdd
parent: 97de3f67c230a34d95778cc16a8c1003148f0b4b
parent: 0ba91ae22a06af3a7561db15973dd98f715cc9eb
author: cinap_lenrek <[email protected]>
date: Tue Nov 3 15:47:14 EST 2020

merge

--- a/sys/src/9/mtx/devarch.c
+++ b/sys/src/9/mtx/devarch.c
@@ -6,28 +6,8 @@
 #include "io.h"
 #include "../port/error.h"
 
-typedef struct IOMap IOMap;
-struct IOMap
-{
-	IOMap	*next;
-	char	tag[13];
-	ulong	start;
-	ulong	end;
-};
-
-static struct
-{
-	Lock;
-	IOMap	*m;
-	IOMap	*free;
-	IOMap	maps[32];		// some initial free maps
-
-	QLock	ql;			// lock for reading map
-} iomap;
-
 enum {
 	Qdir = 0,
-	Qioalloc = 1,
 	Qiob,
 	Qiow,
 	Qiol,
@@ -43,7 +23,6 @@
 
 static Dirtab archdir[] = {
 	".",	{ Qdir, 0, QTDIR },	0,	0555,
-	"ioalloc",	{ Qioalloc, 0 },	0,	0444,
 	"iob",		{ Qiob, 0 },		0,	0660,
 	"iow",		{ Qiow, 0 },		0,	0660,
 	"iol",		{ Qiol, 0 },		0,	0660,
@@ -95,111 +74,12 @@
 void
 ioinit(void)
 {
-	int i;
+	iomapinit(IOSIZE-1);
 
-	for(i = 0; i < nelem(iomap.maps)-1; i++)
-		iomap.maps[i].next = &iomap.maps[i+1];
-	iomap.maps[i].next = nil;
-	iomap.free = iomap.maps;
-
 	// a dummy entry at 2^17
 	ioalloc(0x20000, 1, 0, "dummy");
 }
 
-//
-//	alloc some io port space and remember who it was
-//	alloced to.  if port < 0, find a free region.
-//
-int
-ioalloc(int port, int size, int align, char *tag)
-{
-	IOMap *m, **l;
-	int i;
-
-	lock(&iomap);
-	if(port < 0){
-		// find a free port above 0x400 and below 0x1000
-		port = 0x400;
-		for(l = &iomap.m; *l; l = &(*l)->next){
-			m = *l;
-			i = m->start - port;
-			if(i > size)
-				break;
-			if(align > 0)
-				port = ((port+align-1)/align)*align;
-			else
-				port = m->end;
-		}
-		if(*l == nil){
-			unlock(&iomap);
-			return -1;
-		}
-	} else {
-		// see if the space clashes with previously allocated ports
-		for(l = &iomap.m; *l; l = &(*l)->next){
-			m = *l;
-			if(m->end <= port)
-				continue;
-			if(m->start >= port+size)
-				break;
-			unlock(&iomap);
-			return -1;
-		}
-	}
-	m = iomap.free;
-	if(m == nil){
-		print("ioalloc: out of maps");
-		unlock(&iomap);
-		return port;
-	}
-	iomap.free = m->next;
-	m->next = *l;
-	m->start = port;
-	m->end = port + size;
-	strncpy(m->tag, tag, sizeof(m->tag));
-	m->tag[sizeof(m->tag)-1] = 0;
-	*l = m;
-
-	archdir[0].qid.vers++;
-
-	unlock(&iomap);
-	return m->start;
-}
-
-void
-iofree(int port)
-{
-	IOMap *m, **l;
-
-	lock(&iomap);
-	for(l = &iomap.m; *l; l = &(*l)->next){
-		if((*l)->start == port){
-			m = *l;
-			*l = m->next;
-			m->next = iomap.free;
-			iomap.free = m;
-			break;
-		}
-		if((*l)->start > port)
-			break;
-	}
-	archdir[0].qid.vers++;
-	unlock(&iomap);
-}
-
-int
-iounused(int start, int end)
-{
-	IOMap *m;
-
-	for(m = iomap.m; m; m = m->next){
-		if(start >= m->start && start < m->end
-		|| start <= m->start && end > m->start)
-			return 0; 
-	}
-	return 1;
-}
-
 static void
 checkport(int start, int end)
 {
@@ -243,16 +123,11 @@
 {
 }
 
-enum
-{
-	Linelen= 31,
-};
-
 static long
 archread(Chan *c, void *a, long n, vlong offset)
 {
-	char buf[Linelen+1], *p;
 	int port;
+	uchar *cp;
 	ushort *sp;
 	ulong *lp;
 	IOMap *m;
@@ -266,8 +141,8 @@
 	case Qiob:
 		port = offset;
 		checkport(offset, offset+n);
-		for(p = a; port < offset+n; port++)
-			*p++ = inb(port);
+		for(cp = a; port < offset+n; port++)
+			*cp++ = inb(port);
 		return n;
 
 	case Qiow:
@@ -290,9 +165,6 @@
 			*lp++ = inl(port);
 		return n*4;
 
-	case Qioalloc:
-		break;
-
 	default:
 		if(c->qid.path < narchdir && (fn = readfn[c->qid.path]))
 			return fn(c, a, n, offset);
@@ -299,31 +171,14 @@
 		error(Eperm);
 		break;
 	}
-
-	offset = offset/Linelen;
-	n = n/Linelen;
-	p = a;
-	lock(&iomap);
-	for(m = iomap.m; n > 0 && m != nil; m = m->next){
-		if(offset-- > 0)
-			continue;
-		if(strcmp(m->tag, "dummy") == 0)
-			break;
-		sprint(buf, "%8lux %8lux %-12.12s\n", m->start, m->end-1, m->tag);
-		memmove(p, buf, Linelen);
-		p += Linelen;
-		n--;
-	}
-	unlock(&iomap);
-
-	return p - (char*)a;
+	return 0;
 }
 
 static long
 archwrite(Chan *c, void *a, long n, vlong offset)
 {
-	char *p;
 	int port;
+	uchar *cp;
 	ushort *sp;
 	ulong *lp;
 	Rdwrfn *fn;
@@ -331,10 +186,10 @@
 	switch((ulong)c->qid.path){
 
 	case Qiob:
-		p = a;
+		cp = a;
 		checkport(offset, offset+n);
 		for(port = offset; port < offset+n; port++)
-			outb(port, *p++);
+			outb(port, *cp++);
 		return n;
 
 	case Qiow:
--- a/sys/src/9/mtx/fns.h
+++ b/sys/src/9/mtx/fns.h
@@ -44,8 +44,6 @@
 void	insl(int, void*, int);
 void	intr(Ureg*);
 void	intrenable(int, void (*)(Ureg*, void*), void*, int, char*);
-int	ioalloc(int, int, int, char*);
-void	iofree(int);
 void	ioinit(void);
 int	iprint(char*, ...);
 int	isaconfig(char*, int, ISAConf*);
--- a/sys/src/9/mtx/mkfile
+++ b/sys/src/9/mtx/mkfile
@@ -17,6 +17,7 @@
 	dev.$O\
 	edf.$O\
 	fault.$O\
+	iomap.$O\
 	log.$O\
 	mul64fract.$O\
 	rebootcmd.$O\
--- a/sys/src/9/mtx/pcimtx.c
+++ b/sys/src/9/mtx/pcimtx.c
@@ -115,17 +115,13 @@
 int
 pcicfgrw8(int tbdf, int rno, int data, int read)
 {
-	int o, type, x;
+	int o, x;
 
-	if(BUSBNO(tbdf))
-		type = 0x01;
-	else
-		type = 0x00;
 	switch(pcicfgmode){
 	case 1:
 		o = rno & 0x03;
 		rno &= ~0x03;
-		outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
+		outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno);
 		if(read)
 			data = inb(PciDATA+o);
 		else
@@ -151,17 +147,13 @@
 int
 pcicfgrw16(int tbdf, int rno, int data, int read)
 {
-	int o, type;
+	int o;
 
-	if(BUSBNO(tbdf))
-		type = 0x01;
-	else
-		type = 0x00;
 	switch(pcicfgmode){
 	case 1:
 		o = rno & 0x02;
 		rno &= ~0x03;
-		outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
+		outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno);
 		if(read)
 			data = ins(PciDATA+o);
 		else
@@ -186,16 +178,10 @@
 int
 pcicfgrw32(int tbdf, int rno, int data, int read)
 {
-	int type;
-
-	if(BUSBNO(tbdf))
-		type = 0x01;
-	else
-		type = 0x00;
 	switch(pcicfgmode){
 	case 1:
 		rno &= ~0x03;
-		outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
+		outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno);
 		if(read)
 			data = inl(PciDATA);
 		else
--- a/sys/src/9/pc/devarch.c
+++ b/sys/src/9/pc/devarch.c
@@ -7,29 +7,8 @@
 #include "ureg.h"
 #include "../port/error.h"
 
-typedef struct IOMap IOMap;
-struct IOMap
-{
-	IOMap	*next;
-	int	reserved;
-	char	tag[13];
-	ulong	start;
-	ulong	end;
-};
-
-static struct
-{
-	Lock;
-	IOMap	*m;
-	IOMap	*free;
-	IOMap	maps[32];	/* some initial free maps */
-
-	QLock	ql;		/* lock for reading map */
-} iomap;
-
 enum {
 	Qdir = 0,
-	Qioalloc = 1,
 	Qiob,
 	Qiow,
 	Qiol,
@@ -61,7 +40,6 @@
 
 static Dirtab archdir[Qmax] = {
 	".",		{ Qdir, 0, QTDIR },	0,	0555,
-	"ioalloc",	{ Qioalloc, 0 },	0,	0444,
 	"iob",		{ Qiob, 0 },		0,	0660,
 	"iow",		{ Qiow, 0 },		0,	0660,
 	"iol",		{ Qiol, 0 },		0,	0660,
@@ -116,12 +94,8 @@
 ioinit(void)
 {
 	char *excluded;
-	int i;
 
-	for(i = 0; i < nelem(iomap.maps)-1; i++)
-		iomap.maps[i].next = &iomap.maps[i+1];
-	iomap.maps[i].next = nil;
-	iomap.free = iomap.maps;
+	iomapinit(0xffff);
 
 	/*
 	 * This is necessary to make the IBM X20 boot.
@@ -155,160 +129,8 @@
 	}
 }
 
-/*
- * Reserve a range to be ioalloced later.
- * This is in particular useful for exchangable cards, such
- * as pcmcia and cardbus cards.
- */
-int
-ioreserve(int, int size, int align, char *tag)
-{
-	IOMap *m, **l;
-	int i, port;
-
-	lock(&iomap);
-	/* find a free port above 0x400 and below 0x1000 */
-	port = 0x400;
-	for(l = &iomap.m; *l; l = &(*l)->next){
-		m = *l;
-		if (m->start < 0x400) continue;
-		i = m->start - port;
-		if(i > size)
-			break;
-		if(align > 0)
-			port = ((port+align-1)/align)*align;
-		else
-			port = m->end;
-	}
-	if(*l == nil){
-		unlock(&iomap);
-		return -1;
-	}
-	m = iomap.free;
-	if(m == nil){
-		print("ioalloc: out of maps");
-		unlock(&iomap);
-		return port;
-	}
-	iomap.free = m->next;
-	m->next = *l;
-	m->start = port;
-	m->end = port + size;
-	m->reserved = 1;
-	strncpy(m->tag, tag, sizeof(m->tag)-1);
-	m->tag[sizeof(m->tag)-1] = 0;
-	*l = m;
-
-	archdir[0].qid.vers++;
-
-	unlock(&iomap);
-	return m->start;
-}
-
-/*
- *	alloc some io port space and remember who it was
- *	alloced to.  if port < 0, find a free region.
- */
-int
-ioalloc(int port, int size, int align, char *tag)
-{
-	IOMap *m, **l;
-	int i;
-
-	lock(&iomap);
-	if(port < 0){
-		/* find a free port above 0x400 and below 0x1000 */
-		port = 0x400;
-		for(l = &iomap.m; (m = *l) != nil; l = &m->next){
-			if (m->start < 0x400) continue;
-			i = m->start - port;
-			if(i > size)
-				break;
-			if(align > 0)
-				port = ((port+align-1)/align)*align;
-			else
-				port = m->end;
-		}
-		if(m == nil){
-			unlock(&iomap);
-			return -1;
-		}
-	} else {
-		/* Only 64KB I/O space on the x86. */
-		if((port+size) > 0x10000){
-			unlock(&iomap);
-			return -1;
-		}
-		/* see if the space clashes with previously allocated ports */
-		for(l = &iomap.m; (m = *l) != nil; l = &m->next){
-			if(m->end <= port)
-				continue;
-			if(m->reserved && m->start == port && m->end >= port + size) {
-				m->reserved = 0;
-				unlock(&iomap);
-				return m->start;
-			}
-			if(m->start >= port+size)
-				break;
-			unlock(&iomap);
-			return -1;
-		}
-	}
-	m = iomap.free;
-	if(m == nil){
-		print("ioalloc: out of maps");
-		unlock(&iomap);
-		return port;
-	}
-	iomap.free = m->next;
-	m->next = *l;
-	m->start = port;
-	m->end = port + size;
-	strncpy(m->tag, tag, sizeof(m->tag)-1);
-	m->tag[sizeof(m->tag)-1] = 0;
-	*l = m;
-
-	archdir[0].qid.vers++;
-
-	unlock(&iomap);
-	return m->start;
-}
-
-void
-iofree(int port)
-{
-	IOMap *m, **l;
-
-	lock(&iomap);
-	for(l = &iomap.m; (m = *l) != nil; l = &m->next){
-		if(m->start == port){
-			*l = m->next;
-			m->next = iomap.free;
-			iomap.free = m;
-			break;
-		}
-		if(m->start > port)
-			break;
-	}
-	archdir[0].qid.vers++;
-	unlock(&iomap);
-}
-
-int
-iounused(int start, int end)
-{
-	IOMap *m;
-
-	for(m = iomap.m; m != nil; m = m->next){
-		if(start >= m->start && start < m->end
-		|| start <= m->start && end > m->start)
-			return 0;
-	}
-	return 1;
-}
-
 static void
-checkport(uint start, uint end)
+checkport(ulong start, ulong end)
 {
 	if(end < start || end > 0x10000)
 		error(Ebadarg);
@@ -356,14 +178,12 @@
 static long
 archread(Chan *c, void *a, long n, vlong offset)
 {
-	char buf[32], *p;
-	uint port, end;
+	ulong port, end;
+	uchar *cp;
 	ushort *sp;
 	ulong *lp;
 	vlong *vp;
-	IOMap *m;
 	Rdwrfn *fn;
-	int i;
 
 	port = offset;
 	end = port+n;
@@ -373,8 +193,8 @@
 
 	case Qiob:
 		checkport(port, end);
-		for(p = a; port < end; port++)
-			*p++ = inb(port);
+		for(cp = a; port < end; port++)
+			*cp++ = inb(port);
 		return n;
 
 	case Qiow:
@@ -396,7 +216,7 @@
 	case Qmsr:
 		if(n & 7)
 			error(Ebadarg);
-		if((uint)n/8 > -port)
+		if((ulong)n/8 > -port)
 			error(Ebadarg);
 		end = port+(n/8);
 		for(vp = a; port != end; port++)
@@ -404,25 +224,6 @@
 				error(Ebadarg);
 		return n;
 
-	case Qioalloc:
-		lock(&iomap);
-		i = 0;
-		for(m = iomap.m; m != nil; m = m->next){
-			i = snprint(buf, sizeof(buf), "%8lux %8lux %-12.12s\n",
-				m->start, m->end-1, m->tag);
-			offset -= i;
-			if(offset < 0)
-				break;
-		}
-		unlock(&iomap);
-		if(offset >= 0)
-			return 0;
-		if(n > -offset)
-			n = -offset;
-		offset += i;
-		memmove(a, buf+offset, n);
-		return n;
-
 	default:
 		if(c->qid.path < narchdir && (fn = readfn[c->qid.path]))
 			return fn(c, a, n, offset);
@@ -434,8 +235,8 @@
 static long
 archwrite(Chan *c, void *a, long n, vlong offset)
 {
-	uint port, end;
-	char *p;
+	ulong port, end;
+	uchar *cp;
 	ushort *sp;
 	ulong *lp;
 	vlong *vp;
@@ -446,8 +247,8 @@
 	switch((ulong)c->qid.path){
 	case Qiob:
 		checkport(port, end);
-		for(p = a; port < end; port++)
-			outb(port, *p++);
+		for(cp = a; port < end; port++)
+			outb(port, *cp++);
 		return n;
 
 	case Qiow:
@@ -469,7 +270,7 @@
 	case Qmsr:
 		if(n & 7)
 			error(Ebadarg);
-		if((uint)n/8 > -port)
+		if((ulong)n/8 > -port)
 			error(Ebadarg);
 		end = port+(n/8);
 		for(vp = a; port != end; port++)
--- a/sys/src/9/pc/devpccard.c
+++ b/sys/src/9/pc/devpccard.c
@@ -816,7 +816,7 @@
 
 	if(iolen < 512)
 		iolen = 512;
-	iobase = ioreserve(~0, iolen, 0, "cardbus");
+	iobase = ioreserve(-1, iolen, 0, "cardbus");
 	if(iobase == -1)
 		return;
 
--- a/sys/src/9/pc/fns.h
+++ b/sys/src/9/pc/fns.h
@@ -85,11 +85,7 @@
 void	introff(void);
 void	intron(void);
 void	invlpg(ulong);
-void	iofree(int);
 void	ioinit(void);
-int	iounused(int, int);
-int	ioalloc(int, int, int, char*);
-int	ioreserve(int, int, int, char*);
 int	iprint(char*, ...);
 int	isaconfig(char*, int, ISAConf*);
 void*	kaddr(ulong);
--- a/sys/src/9/pc/mkfile
+++ b/sys/src/9/pc/mkfile
@@ -24,6 +24,8 @@
 	dev.$O\
 	edf.$O\
 	fault.$O\
+	iomap.$O\
+	memmap.$O\
 	page.$O\
 	parse.$O\
 	pgrp.$O\
@@ -35,7 +37,6 @@
 	random.$O\
 	rdb.$O\
 	rebootcmd.$O\
-	memmap.$O\
 	segment.$O\
 	syscallfmt.$O\
 	sysfile.$O\
--- a/sys/src/9/pc/pcipc.c
+++ b/sys/src/9/pc/pcipc.c
@@ -528,59 +528,78 @@
 }
 
 static void
-pcireservemem(void)
+pcireserve(void)
 {
+	char tag[64];
 	Pcidev *p;
 	uvlong pa;
+	ulong io;
 	int i;
 
 	/*
-	 * mark all valid physical address space claimed by pci devices
-	 * as in use, so that upaalloc doesn't give it out.
+	 * mark all valid io/mem address space claimed by pci devices
+	 * so that ioreserve/upaalloc doesn't give it out.
 	 */
 	for(p=pciroot; p != nil; p=p->list){
+		snprint(tag, sizeof(tag), "%T", p->tbdf);
 		for(i=0; i<nelem(p->mem); i++){
 			if(p->mem[i].size == 0)
 				continue;
-			if(p->mem[i].bar & 1)
-				continue;
-			if((p->mem[i].bar & ~0xFULL) == 0)
-				continue;
-			upaalloc(p->mem[i].bar&~0xFULL, p->mem[i].size, 0);
+			if(p->mem[i].bar & 1){
+				io = p->mem[i].bar & ~3ULL;
+				if(io == 0)
+					continue;
+				ioreserve(io, p->mem[i].size, 0, tag);
+			} else {
+				pa = p->mem[i].bar & ~0xFULL;
+				if(pa == 0)
+					continue;
+				upaalloc(pa, p->mem[i].size, 0);
+			}
 		}
 	}
 
 	/*
-	 * allocate physical address space for unassigned membars.
+	 * allocate io/mem address space for unassigned membars.
 	 */
 	for(p=pciroot; p != nil; p=p->list){
+		snprint(tag, sizeof(tag), "%T", p->tbdf);
 		for(i=0; i<nelem(p->mem); i++){
 			if(p->mem[i].size == 0)
 				continue;
-			if(p->mem[i].bar & ~0xEULL)
-				continue;
-
-			if(p->parent == nil){
-				pa = upaalloc(-1ULL,
-					p->mem[i].size, p->mem[i].size);
-			} else if(p->mem[i].bar & 8){
-				pa = upaallocwin(p->parent->prefa.bar, p->parent->prefa.size,
-					p->mem[i].size, p->mem[i].size);
-				if(pa == -1ULL)
-					goto Mem;
+			if(p->mem[i].bar & 1){
+				if(p->mem[i].bar & ~0x3ULL)
+					continue;
+				if(p->parent == nil){
+					io = ioreserve(-1, p->mem[i].size, p->mem[i].size, tag);
+				} else {
+					io = ioreservewin(p->parent->ioa.bar, p->parent->ioa.size,
+						p->mem[i].size, p->mem[i].size, tag);
+				}
+				if(io == -1)
+					continue;
+				p->mem[i].bar |= io;
 			} else {
-			Mem:
-				pa = upaallocwin(p->parent->mema.bar, p->parent->mema.size,
-					p->mem[i].size, p->mem[i].size);
+				if(p->mem[i].bar & ~0xFULL)
+					continue;
+				if(p->parent == nil){
+					pa = upaalloc(-1ULL, p->mem[i].size, p->mem[i].size);
+				} else if(p->mem[i].bar & 8){
+					pa = upaallocwin(p->parent->prefa.bar, p->parent->prefa.size,
+						p->mem[i].size, p->mem[i].size);
+					if(pa == -1ULL)
+						goto Mem;
+				} else {
+				Mem:
+					pa = upaallocwin(p->parent->mema.bar, p->parent->mema.size,
+						p->mem[i].size, p->mem[i].size);
+				}
+				if(pa == -1ULL)
+					continue;
+				p->mem[i].bar |= pa;
 			}
-			if(pa == -1ULL)
-				continue;
-
-			p->mem[i].bar |= pa;
 			pcisetbar(p, PciBAR0 + i*4, p->mem[i].bar);
-
-			DBG("%T: bar%d: fixed %.8lluX %d\n",
-				p->tbdf, i, p->mem[i].bar, p->mem[i].size);
+			DBG("%s: bar%d: fixed %.8lluX %d\n", tag, i, p->mem[i].bar, p->mem[i].size);
 		}
 	}
 }
@@ -620,6 +639,9 @@
 			outl(PciADDR, 0x80000000);
 			outb(PciADDR+3, 0);
 			if(inl(PciADDR) & 0x80000000){
+				ioalloc(PciADDR, 4, 0, "pcicfg.addr");
+				ioalloc(PciDATA, 4, 0, "pcicfg.data");
+
 				pcicfgmode = 1;
 				pcimaxdno = 31;
 			}
@@ -634,6 +656,10 @@
 			if(!(n & 0xF0)){
 				outb(PciCSE, 0x0E);
 				if(inb(PciCSE) == 0x0E){
+					ioalloc(PciCSE, 1, 0, "pcicfg.cse");
+					ioalloc(PciFORWARD, 1, 0, "pcicfg.forward");
+					ioalloc(0xC000, 0x1000, 0, "pcicfg.io");
+
 					pcicfgmode = 2;
 					pcimaxdno = 15;
 				}
@@ -705,9 +731,12 @@
 		 */
 		mema = upaalloc(-1ULL, mema, mema);
 		if(mema == -1ULL)
-			panic("pcicfginit: can't allocate pci window");
+			panic("pcicfginit: can't allocate pci mem window");
 
-		ioa = 0x1000;
+		ioa = ioreserve(-1, ioa, ioa, "pci");
+		if(ioa == -1UL)
+			panic("pcicfginit: can't allocate pci io window");
+
 		DBG("Base:  mem=%.8llux io=%lux\n", mema, ioa);
 		pcibusmap(pciroot, &mema, &ioa, 1);
 		DBG("Limit: mem=%.8llux io=%lux\n", mema, ioa);
@@ -714,7 +743,7 @@
 		goto out;
 	}
 
-	pcireservemem();
+	pcireserve();
 
 	if(!nopcirouting)
 		pcirouting();
--- a/sys/src/9/pc64/fns.h
+++ b/sys/src/9/pc64/fns.h
@@ -83,11 +83,7 @@
 void	introff(void);
 void	intron(void);
 void	invlpg(uintptr);
-void	iofree(int);
 void	ioinit(void);
-int	iounused(int, int);
-int	ioalloc(int, int, int, char*);
-int	ioreserve(int, int, int, char*);
 int	iprint(char*, ...);
 int	isaconfig(char*, int, ISAConf*);
 void*	kaddr(uintptr);
--- a/sys/src/9/pc64/mkfile
+++ b/sys/src/9/pc64/mkfile
@@ -22,6 +22,7 @@
 	dev.$O\
 	edf.$O\
 	fault.$O\
+	iomap.$O\
 	memmap.$O\
 	page.$O\
 	parse.$O\
--- /dev/null
+++ b/sys/src/9/port/iomap.c
@@ -1,0 +1,243 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+
+typedef struct IOMap IOMap;
+struct IOMap
+{
+	IOMap	*next;
+	ulong	start;
+	ulong	end;
+	char	reserved;
+	char	tag[13];
+};
+
+static struct
+{
+	Lock;
+	IOMap	*m;
+	IOMap	*free;
+	IOMap	maps[32];	/* some initial free maps */
+
+	ulong	mask;
+} iomap;
+
+static void
+insert(IOMap **l, ulong start, ulong end, char *tag, int reserved)
+{
+	IOMap *m;
+
+	m = iomap.free;
+	if(m != nil)
+		iomap.free = m->next;
+	else
+		m = malloc(sizeof(IOMap));
+	if(m == nil)
+		panic("ioalloc: out of memory");
+
+	m->next = *l;
+	m->start = start;
+	m->end = end;
+	m->reserved = reserved;
+
+	strncpy(m->tag, tag, sizeof(m->tag)-1);
+	m->tag[sizeof(m->tag)-1] = 0;
+
+	*l = m;
+}
+
+/*
+ * Reserve a range to be ioalloced later.
+ * If port is -1, look for a free range above 0x400.
+ */
+int
+ioreserve(ulong port, ulong size, ulong align, char *tag)
+{
+	if(port == -1)
+		return ioreservewin(0x400, -0x400 & iomap.mask, size, align, tag);
+	else
+		return ioreservewin(port, size, size, align, tag);
+}
+
+/*
+ * Find a free region of length "size" within the window [port, port+win)
+ * and reserve it to be ioalloced later.
+ */
+int
+ioreservewin(ulong port, ulong win, ulong size, ulong align, char *tag)
+{
+	IOMap *m, **l;
+
+	if(win == 0 || port & ~iomap.mask || (~port & iomap.mask) < (win-1 & iomap.mask))
+		return -1;
+
+	size = (size + ~iomap.mask) & iomap.mask;
+	if(size == 0 || size > win)
+		return -1;
+
+	if(align){
+		if((align & (align-1)) != 0)
+			return -1;
+		align--;
+	}
+
+	win += port;
+	port = (port+align) & ~align;
+	if(port >= win || win - port < size)
+		return -1;
+
+	lock(&iomap);
+	for(l = &iomap.m; (m = *l) != nil; l = &m->next){
+		if(m->end <= port)
+			continue;
+		if(m->start > port && m->start - port >= size)
+			break;
+		port = m->end;
+		port = (port+align) & ~align;
+		if(port >= win || win - port < size){
+			unlock(&iomap);
+			return -1;
+		}
+	}
+	insert(l, port, port + size, tag, 1);
+	unlock(&iomap);
+
+	return port;
+}
+
+/*
+ * Alloc some io port space and remember who it was
+ * alloced to. If port == -1, find a free region.
+ */
+int
+ioalloc(ulong port, ulong size, ulong align, char *tag)
+{
+	IOMap *m, **l;
+
+	if(port == -1)
+		port = ioreserve(port, size, align, tag);
+
+	size = (size + ~iomap.mask) & iomap.mask;
+	if(size == 0 || port & ~iomap.mask || (~port & iomap.mask) < (size-1 & iomap.mask))
+		return -1;
+
+	lock(&iomap);
+	for(l = &iomap.m; (m = *l) != nil; l = &m->next){
+		if(m->end <= port)
+			continue;
+		if(m->start > port && m->start - port >= size)
+			break;
+		if(m->reserved && m->start <= port && m->end - port >= size){
+			if(m->end - port > size)
+				insert(&m->next, port + size, m->end, m->tag, 1);
+			if(m->start < port){
+				insert(l, m->start, port, m->tag, 1);
+				l = &(*l)->next;
+			}
+			*l = m->next;
+			m->next = iomap.free;
+			iomap.free = m;
+			break;
+		}
+		print("ioalloc: %lux - %lux %s: clashes with: %lux - %lux %s\n",
+			port, port+size-1, tag,
+			m->start, m->end-1, m->tag);
+		unlock(&iomap);
+		return -1;
+	}
+	insert(l, port, port + size, tag, 0);
+	unlock(&iomap);
+
+	return port;
+}
+
+void
+iofree(ulong port)
+{
+	IOMap *m, **l;
+
+	if(port & ~iomap.mask)
+		return;
+
+	lock(&iomap);
+	for(l = &iomap.m; (m = *l) != nil; l = &m->next){
+		if(m->start == port){
+			*l = m->next;
+			m->next = iomap.free;
+			iomap.free = m;
+			break;
+		}
+		if(m->start > port)
+			break;
+	}
+	unlock(&iomap);
+}
+
+int
+iounused(ulong start, ulong end)
+{
+	IOMap *m;
+
+	if(start & ~iomap.mask || end < start)
+		return 0;
+
+	for(m = iomap.m; m != nil; m = m->next){
+		if(m->end <= start)
+			continue;
+		if(m->start >= end)
+			break;
+		if(!m->reserved)
+			return 0;
+	}
+	return 1;
+}
+
+static long
+iomapread(Chan*, void *a, long n, vlong offset)
+{
+	char buf[32];
+	IOMap *m;
+	int i;
+
+	lock(&iomap);
+	i = 0;
+	for(m = iomap.m; m != nil; m = m->next){
+		i = snprint(buf, sizeof(buf), "%8lux %8lux %-12.12s\n",
+			m->start, m->end-1, m->tag);
+		offset -= i;
+		if(offset < 0)
+			break;
+	}
+	unlock(&iomap);
+	if(offset >= 0)
+		return 0;
+	if(n > -offset)
+		n = -offset;
+	offset += i;
+	memmove(a, buf+offset, n);
+	return n;
+}
+
+/*
+ * Initialize the io space port map.
+ * The mask argument defines the valid bits of
+ * a port address, so different architectures
+ * might have different sizes and alignments.
+ */
+void
+iomapinit(ulong mask)
+{
+	int i;
+
+	assert(mask != 0 && (mask >> 31) == 0);
+
+	for(i = 0; i < nelem(iomap.maps)-1; i++)
+		iomap.maps[i].next = &iomap.maps[i+1];
+	iomap.maps[i].next = nil;
+	iomap.free = iomap.maps;
+	iomap.mask = mask;
+
+	addarchfile("ioalloc", 0444, iomapread, nil);
+}
--- a/sys/src/9/port/portfns.h
+++ b/sys/src/9/port/portfns.h
@@ -138,6 +138,12 @@
 long		incref(Ref*);
 void		init0(void);
 void		initseg(void);
+int		ioalloc(ulong, ulong, ulong, char*);
+void		iofree(ulong);
+void		iomapinit(ulong);
+int		ioreserve(ulong, ulong, ulong, char*);
+int		ioreservewin(ulong, ulong, ulong, ulong, char*);
+int		iounused(ulong, ulong);
 int		iprint(char*, ...);
 void		isdir(Chan*);
 int		iseve(void);
--- a/sys/src/9/ppc/fns.h
+++ b/sys/src/9/ppc/fns.h
@@ -50,8 +50,6 @@
 void	intr(Ureg*);
 void	intrenable(int, void (*)(Ureg*, void*), void*, char*);
 void	intrdisable(int, void (*)(Ureg*, void*), void*, char*);
-int	ioalloc(int, int, int, char*);
-void	iofree(int);
 int	iprint(char*, ...);
 int	isaconfig(char*, int, ISAConf*);
 void	kfpinit(void);
--- a/sys/src/9/xen/fns.h
+++ b/sys/src/9/xen/fns.h
@@ -56,7 +56,6 @@
 void	insl(int, void*, int);
 void	intrdisable(int, void (*)(Ureg *, void *), void*, int, char*);
 void	intrenable(int, void (*)(Ureg*, void*), void*, int, char*);
-int	ioalloc(int, int, int, char*);
 void	ioinit(void);
 int	isaconfig(char*, int, ISAConf*);
 void	kbdenable(void);
--- a/sys/src/9/xen/mkfile
+++ b/sys/src/9/xen/mkfile
@@ -22,6 +22,7 @@
 	dev.$O\
 	edf.$O\
 	fault.$O\
+	iomap.$O\
 	page.$O\
 	parse.$O\
 	pgrp.$O\