git: 9front

Download patch

ref: 5159113d7c39dc5e9b3d3685577b7eb6f1717ebe
parent: 3bd0341e0d0b8084dcfa702dee67736b893143a4
author: cinap_lenrek <cinap_lenrek@gmx.de>
date: Fri Sep 6 12:48:27 EDT 2013

libaml: new io interface, add amlnew()/amltake()/amldrop(), late binding names, FindSetLeftBit/FindSetRightBit

new io interface was added. user defines amlmapio() and amlunmapio() functions
that will fill out Amlio structure with function pointers to read/write
routines for a particular region.

amlnew() function added allowing the creation of aml objects like buffers
or packages. these can be passed to amleval() with b, p or * format.

amltake()/amldrop() exclude an aml object from garbage collection.

on load, names are not always resolvable until the whole table is loaded.
for this, we create n objects that are just name strings. after load, we
recursively traverse the namespace and resolve them (see fixnames()).

the FindSetLeftBit and FindSetRightBit opcodes got implemened.

--- a/sys/include/aml.h
+++ b/sys/include/aml.h
@@ -4,6 +4,7 @@
 /*
  *	b	uchar*	buffer		amllen() returns number of bytes
  *	s	char*	string		amllen() is strlen()
+ *	n	char*	undefined name	amllen() is strlen()
  *	i	uvlong*	integer
  *	p	void**	package		amllen() is # of elements
  *	r	void*	region
@@ -17,6 +18,8 @@
 uvlong		amlint(void *);
 int		amllen(void *);
 
+void*		amlnew(char tag, int len);
+
 void		amlinit(void);
 void		amlexit(void);
 
@@ -25,6 +28,12 @@
 int		amleval(void *dot, char *fmt, ...);
 void		amlenum(void *dot, char *seg, int (*proc)(void *, void *), void *arg);
 
+/*
+ * exclude from garbage collection
+ */
+void		amltake(void *);
+void		amldrop(void *);
+
 void*		amlroot;
 int		amldebug;
 
@@ -34,3 +43,31 @@
 /* to be provided by operating system */
 extern void*	amlalloc(int);
 extern void	amlfree(void*);
+
+enum {
+	MemSpace	= 0x00,
+	IoSpace		= 0x01,
+	PcicfgSpace	= 0x02,
+	EbctlSpace	= 0x03,
+	SmbusSpace	= 0x04,
+	CmosSpace	= 0x05,
+	PcibarSpace	= 0x06,
+	IpmiSpace	= 0x07,
+};
+
+typedef struct Amlio Amlio;
+struct Amlio
+{
+	int	space;
+	uvlong	off;
+	uvlong	len;
+	void	*name;
+	uchar	*va;
+
+	void	*aux;
+	int	(*read)(Amlio *io, void *data, int len, int off);
+	int	(*write)(Amlio *io, void *data, int len, int off);
+};
+
+extern int	amlmapio(Amlio *io);
+extern void	amlunmapio(Amlio *io);
--- a/sys/src/libaml/aml.c
+++ b/sys/src/libaml/aml.c
@@ -6,7 +6,6 @@
 typedef struct Frame Frame;
 typedef struct Heap Heap;
 
-typedef struct Package Package;
 typedef struct Method Method;
 typedef struct Region Region;
 typedef struct Field Field;
@@ -28,17 +27,6 @@
 #define TAG(d)	D2H(d)->tag
 #define SIZE(d)	D2H(d)->size
 
-enum {
-	MemSpace	= 0x00,
-	IoSpace		= 0x01,
-	PcicfgSpace	= 0x02,
-	EbctlSpace	= 0x03,
-	SmbusSpace	= 0x04,
-	CmosSpace	= 0x05,
-	PcibarSpace	= 0x06,
-	IpmiSpace	= 0x07,
-};
-
 static char *spacename[] = {
 	"Mem", 
 	"Io",
@@ -68,11 +56,6 @@
 	UpdateMask	= 0x60,
 };
 
-struct Package {
-	int	n;
-	void	*a[];
-};
-
 struct Method {
 	Name	*name;
 	int	narg;
@@ -82,11 +65,8 @@
 };
 
 struct Region {
-	Name	*name;
-	int	space;
-	uvlong	off;
-	uvlong	len;
-	uchar	*va;	/* non nil when mapped */
+	Amlio;
+	char	mapped;
 };
 
 struct Field {
@@ -162,7 +142,7 @@
 	Oreg, Ofld, Oxfld, Opkg, Ovpkg, Oenv, Obuf, Omet, 
 	Odev, Ocpu, Othz, Oprc,
 	Oadd, Osub, Omod, Omul, Odiv, Oshl, Oshr, Oand, Onand, Oor,
-	Onor, Oxor, Onot, Oinc, Odec,
+	Onor, Oxor, Onot, Olbit, Orbit, Oinc, Odec,
 	Oland, Olor, Olnot, Oleq, Olgt, Ollt,
 	Oindex, Omutex, Oevent,
 	Ocfld, Ocfld0, Ocfld1, Ocfld2, Ocfld4, Ocfld8,
@@ -191,14 +171,13 @@
 	Field *f;
 	Heap *h;
 	Name *n, *d;
-	Package *a;
 
 	if(p == nil)
 		return;
 	h = D2H(p);
-	if(h->mark)
+	if(h->mark & 1)
 		return;
-	h->mark = 1;
+	h->mark |= 1;
 	switch(h->tag){
 	case 'E':
 		e = p;
@@ -221,9 +200,8 @@
 		gcmark(n->up);
 		break;
 	case 'p':
-		a = p;
-		for(i=0; i<a->n; i++)
-			gcmark(a->a[i]);
+		for(i=0; i<(SIZE(p)/sizeof(void*)); i++)
+			gcmark(((void**)p)[i]);
 		break;
 	case 'r':
 		gcmark(((Region*)p)->name);
@@ -249,8 +227,12 @@
 	Frame *f;
 
 	for(h = hp; h; h = h->link)
-		h->mark = 0;
+		h->mark &= ~1;
 
+	for(h = hp; h; h = h->link)
+		if(h->mark & 2)
+			gcmark(H2D(h));
+
 	for(f = FP; f >= FB; f--){
 		for(i=0; i<f->narg; i++)
 			gcmark(f->arg[i]);
@@ -271,8 +253,17 @@
 		*hh = h->link;
 		if(h->tag == 'r'){
 			Region *r = (void*)H2D(h);
-
-			/* TODO: unmap region */
+			if(r->mapped > 0){
+				if(amldebug)
+					print("\namlunmapio(%N): %-8s %llux - %llux\n", 
+						(Name*)r->name, spacename[r->space],
+						r->off, r->off + r->len);
+				amlunmapio(r);
+			}
+			r->mapped = 0;
+			r->write = nil;
+			r->read = nil;
+			r->aux = nil;
 			r->va = nil;
 		}
 		memset(h, ~0, sizeof(Heap)+h->size);
@@ -439,12 +430,57 @@
 	return dot;
 }
 
+static int
+fixnames(void *dot, void *arg)
+{
+	void **r, *v;
+	int i;
+
+	if(arg == nil)
+		r = &((Name*)dot)->v;
+	else
+		r = arg;
+	v = *r;
+	if(v == nil || v == dot)
+		return 0;
+	if(TAG(v) == 'p'){
+		r = (void**)v;
+		for(i=0; i<(SIZE(r)/sizeof(void*)); i++)
+			fixnames(dot, r+i);
+		return 0;
+	}
+	if(TAG(v) == 'n' && (v = getname(dot, v, 0)) != nil)
+		*r = v;
+	return 0;
+}
+
 static uvlong
+getle(uchar *p, int len)
+{
+	uvlong v;
+	int i;
+
+	for(i=0; i<len; i++)
+		v |= ((uvlong)p[i]) << i*8;
+	return v;
+}
+
+static void
+putle(uchar *p, int len, uvlong v)
+{
+	int i;
+
+	for(i=0; i<len; i++){
+		p[i] = v;
+		v >>= 8;
+	}
+}
+
+static uvlong
 rwreg(void *reg, int off, int len, uvlong v, int write)
 {
+	uchar buf[8], *p;
 	Region *r;
-	uchar *p;
-	int i;
 
 	switch(TAG(reg)){
 	case 'b':
@@ -451,33 +487,61 @@
 		p = reg;
 		if((off+len) > SIZE(p))
 			break;
-	RWMem:
-		if(write){
-			for(i=0; i<len; i++){
-				p[off+i] = v & 0xFF;
-				v >>= 8;
-			}
-		} else {
-			for(i=0; i<len; i++)
-				v |= ((uvlong)p[off+i]) << i*8;
-		}
+		p += off;
+		if(write)
+			putle(p, len, v);
+		else
+			v = getle(p, len);
 		return v;
+
 	case 'r':
 		r = reg;
 		if((off+len) > r->len)
 			break;
-		if(amldebug){
-			print("\nrwreg: %s %-8s [%llux+%x]/%d %llux\n", 
-				write ? "W" : "R", 
-				spacename[r->space],
-				r->off, off, len, v);
+		if(r->mapped == 0){
+			if(amldebug)
+				print("\namlmapio(%N): %-8s %llux - %llux\n", 
+					(Name*)r->name, spacename[r->space],
+					r->off, r->off + r->len);
+			r->mapped = 1;
+			if(amlmapio(r) < 0)
+				r->mapped = -1;
 		}
-		/* TODO: map region */
-		if(r->va != nil){
+		if(r->mapped <= 0)
+			break;
+
+		if(r->va != nil)
 			p = r->va + off;
-			goto RWMem;
+		else {
+			if(len > sizeof(buf))
+				break;
+			p = buf;
 		}
-		break;
+
+		if(write){
+			if(amldebug)
+				print("\nrwreg(%N): %-8s [%llux+%x]/%d <- %llux\n", 
+					(Name*)r->name, spacename[r->space],
+					r->off, off, len, v);
+			putle(p, len, v);
+			if(r->write != nil){
+				if((*r->write)(r, p, len, off) != len)
+					break;
+			} else if(p == buf)
+				break;
+		} else {
+			if(r->read != nil){
+				if((*r->read)(r, p, len, off) != len)
+					break;
+			} else if(p == buf)
+				break;
+			v = getle(p, len);
+			if(amldebug)
+				print("\nrwreg(%N): %-8s [%llux+%x]/%d -> %llux\n", 
+					(Name*)r->name, spacename[r->space],
+					r->off, off, len, v);
+		}
+		return v;
 	}
 
 	return ~0;
@@ -549,10 +613,7 @@
 		} else {
 			w = ival(v);
 			b = mk('b', (blen+7)/8);
-			for(i=0; i<SIZE(b); i++){
-				b[i] = w & 0xFF;
-				w >>= 8;
-			}
+			putle(b, SIZE(b), w);
 		}
 	} else
 		b = mk('b', (blen+7)/8);
@@ -568,10 +629,10 @@
 			w = 0;
 			for(i = 0; i < wl; i++, boff++)
 				if(b[boff/8] & (1<<(boff%8)))
-					w |= 1LL<<i;
+					w |= 1ULL<<i;
 			w <<= ws;
 			if(wl != wd){
-				m = ((1LL<<wl)-1) << ws;
+				m = ((1ULL<<wl)-1) << ws;
 				w |= rwreg(reg, wo*wa, wa, 0, 0) & ~m;
 			}
 			rwreg(reg, wo*wa, wa, w, 1);
@@ -587,10 +648,7 @@
 		return nil;
 	if(blen > 64)
 		return b;
-
-	w = 0;
-	for(i=0; i<SIZE(b); i++)
-		w |= ((uvlong)b[i]) << i*8;
+	w = getle(b, SIZE(b));
 	return mki(w);
 }
 
@@ -755,7 +813,6 @@
 	Field *l;
 	Name *nm;
 	Method *m;
-	Package *a;
 	Region *g;
 	Ref *r;
 
@@ -777,17 +834,19 @@
 			return fmtprint(f, "Arg%ld=%V", r->ptr - e->arg, *r->ptr);
 		if(c == 'L')
 			return fmtprint(f, "Local%ld=%V", r->ptr - e->loc, *r->ptr);
+	case 'n':
+		return fmtprint(f, "%s", (char*)p);
 	case 's':
 		return fmtprint(f, "\"%s\"", (char*)p);
 	case 'i':
 		return fmtprint(f, "%#llux", *((uvlong*)p));
 	case 'p':
-		a = p;
-		fmtprint(f, "Package(%d){", a->n);
-		for(i=0; i<a->n; i++){
+		n = SIZE(p)/sizeof(void*);
+		fmtprint(f, "Package(%d){", n);
+		for(i=0; i<n; i++){
 			if(i > 0)
 				fmtprint(f, ", ");
-			fmtprint(f, "%V", a->a[i]);
+			fmtprint(f, "%V", ((void**)p)[i]);
 		}
 		fmtprint(f, "}");
 		return 0;
@@ -1015,7 +1074,7 @@
 		}
 		if(FP < FB){
 			if(pret){
-				if(amldebug) print(" => %V\n", r);
+				if(amldebug) print(" -> %V\n", r);
 				*pret = r;
 			}
 			return 0;
@@ -1031,23 +1090,25 @@
 static void*
 evalnamec(void)
 {
-	int s, c, new;
-	Name *x, *dot;
+	static char name[1024];
+	char *d;
+	void *r;
+	int c;
 
-	dot = FP->dot;
-	new = FP->tag == 'N';
-	s = !new;
 	c = 1;
+	d = name;
 	PC = FP->start;
-	if(*PC == '\\'){
-		PC++;
-		dot = rootname(dot);
-		s = 0;
-	}
+	if(*PC == '\\')
+		*d++ = *PC++;
 	while(*PC == '^'){
-		PC++;
-		dot = dot->up;
-		s = 0;
+		if(d >= &name[sizeof(name)-1]){
+		Toolong:
+			*d = 0;
+			print("aml: name too long: %s\n", name);
+			PC = FP->end;
+			return nil;
+		}
+		*d++ = *PC++;
 	}
 	if(*PC == '.'){
 		PC++;
@@ -1058,23 +1119,25 @@
 	} else if(*PC == 0){
 		PC++;
 		c = 0;
-	} else if(s){
-		for(;;){
-			if(x = getseg(dot, PC, 0))
-				break;
-			if(dot == dot->up)
-				break;
-			dot = dot->up;
-		}
-		PC += 4;
-		return x;
 	}
 	while(c > 0){
-		dot = getseg(dot, PC, new);
-		PC += 4;
-		c--;
+		if(d >= &name[sizeof(name)-5])
+			goto Toolong;
+		*d++ = *PC++;
+		*d++ = *PC++;
+		*d++ = *PC++;
+		*d++ = *PC++;
+		while((d > &name[0]) && (d[-1] == '_' || d[-1] == 0))
+			d--;
+		if(--c > 0)
+			*d++ = '.';
 	}
-	return dot;
+	*d = 0;
+	if((r = getname(FP->dot, name, FP->tag == 'N')) == nil){
+		r = mks(name);
+		D2H(r)->tag = 'n';	/* unresolved name */
+	}
+	return r;
 }
 
 static void*
@@ -1114,13 +1177,12 @@
 static void*
 evalpkg(void)
 {
-	Package *p;
-	void **x;
+	void **p, **x;
 	int n;
 
 	if((p = FP->ref) != nil){
 		x = FP->aux;
-		if(x >= &p->a[0] && x < &p->a[p->n]){
+		if(x >= p && x < (p+(SIZE(p)/sizeof(void*)))){
 			*x++ = FP->arg[0];
 			FP->aux = x;
 		}
@@ -1127,9 +1189,8 @@
 	}else {
 		n = ival(FP->arg[0]);
 		if(n < 0) n = 0;
-		p = mk('p', sizeof(Package) + n*sizeof(void*));
-		p->n = n;
-		FP->aux = p->a;
+		p = mk('p', n*sizeof(void*));
+		FP->aux = p;
 		FP->ref = p;
 	}
 	return p;
@@ -1176,7 +1237,7 @@
 	Name *n;
 	Method *m;
 
-	if(n = FP->arg[0]){
+	if((n = FP->arg[0]) != nil){
 		m = mk('m', sizeof(Method));
 		m->narg = ival(FP->arg[1]) & 7;
 		m->start = PC;
@@ -1568,7 +1629,7 @@
 		store(f, FP->arg[2]);
 		return f;
 	case 'p':
-		if(x < 0 || x >= ((Package*)p)->n)
+		if(x < 0 || x >= (SIZE(p)/sizeof(void*)))
 			break;
 		if(TAG(FP->arg[0]) == 'A' || TAG(FP->arg[0]) == 'L')
 			r = mk(TAG(FP->arg[0]), sizeof(Ref));
@@ -1575,7 +1636,7 @@
 		else
 			r = mk('R', sizeof(Ref));
 		r->ref = p;
-		r->ptr = &((Package*)p)->a[x];
+		r->ptr = ((void**)p) + x;
 		store(r, FP->arg[2]);
 		return r;
 	}
@@ -1604,7 +1665,7 @@
 	void *p;
 
 	if(p = FP->arg[0]){
-		if(TAG(p) == 's')
+		if(TAG(p) == 's' || TAG(p) == 'n')
 			p = getname(FP->dot, (char*)p, 0);
 		p = deref(p);
 	}
@@ -1616,6 +1677,7 @@
 {
 	uvlong v, d;
 	void *r;
+	int i;
 
 	r = nil;
 	switch(FP->op - optab){
@@ -1668,6 +1730,22 @@
 		r = mki(~ival(FP->arg[0]));
 		store(r, FP->arg[1]);
 		return r;
+	case Olbit:
+		v = ival(FP->arg[0]);
+		if(v == 0)
+			break;
+		for(i=0; (v & 1) == 0; i++)
+			v >>= 1;
+		r = mki(i+1);
+		break;
+	case Orbit:
+		v = ival(FP->arg[0]);
+		if(v == 0)
+			break;
+		for(i=0; v != 0; i++)
+			v >>= 1;
+		r = mki(i);
+		break;
 	case Oland:
 		return mki(ival(FP->arg[0]) && ival(FP->arg[1]));
 	case Olor:
@@ -1700,7 +1778,7 @@
 	tid = nil;
 	if(FP->aux){
 		if(PC >= FP->end){
-			PC = FP->aux;	/* restore */
+			amlenum(amlroot, nil, fixnames, nil);
 			FP->aux = nil;
 			FP->end = PC;
 			tid = mki(1);	/* fake */
@@ -1724,9 +1802,8 @@
 			break;
 		case 'r':
 			r = FP->ref;
-			if(r->len < l || r->va == nil)
+			if(r->len < l || r->va == nil || r->mapped <= 0)
 				return nil;
-			/* assuming rwreg() has mapped the region */
 			PC = (uchar*)r->va + HdrLen;
 			break;
 		default:
@@ -1795,6 +1872,9 @@
 	[Oxor]		"Xor",			"ii@",		evalarith,
 	[Onot]		"Not",			"i@",		evalarith,
 
+	[Olbit]		"FindSetLeftBit",	"i@",		evalarith,
+	[Orbit]		"FindSetRightBit",	"i@",		evalarith,
+
 	[Oinc]		"Increment",		"@",		evalarith,
 	[Odec]		"Decrement",		"@",		evalarith,
 
@@ -1849,7 +1929,7 @@
 /* 68 */	Oenv,	Oenv,	Oenv,	Oenv,	Oenv,	Oenv,	Oenv,	Obad,
 /* 70 */	Ostore,	Oref,	Oadd,	Ocat,	Osub,	Oinc,	Odec,	Omul,
 /* 78 */	Odiv,	Oshl,	Oshr,	Oand,	Onand,	Oor,	Onor,	Oxor,
-/* 80 */	Onot,	Obad,	Obad,	Oderef,	Obad,	Omod,	Obad,	Osize,
+/* 80 */	Onot,	Olbit,	Orbit,	Oderef,	Obad,	Omod,	Obad,	Osize,
 /* 88 */	Oindex,	Obad,	Ocfld4,	Ocfld2,	Ocfld1,	Ocfld0,	Obad,	Ocfld8,
 /* 90 */	Oland,	Olor,	Olnot,	Oleq,	Olgt,	Ollt,	Obad,	Obad,
 /* 98 */	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,
@@ -1911,10 +1991,7 @@
 void*
 amlval(void *p)
 {
-	p = deref(p);
-	if(p && TAG(p) == 'p')
-		p = ((Package*)p)->a;
-	return p;
+	return deref(p);
 }
 
 uvlong
@@ -1931,10 +2008,11 @@
 		case 'R':
 			p = *((Ref*)p)->ptr;
 			continue;
+		case 'n':
 		case 's':
 			return strlen((char*)p);
 		case 'p':
-			return ((Package*)p)->n;
+			return SIZE(p)/sizeof(void*);
 		default:
 			return SIZE(p);
 		}
@@ -1942,6 +2020,22 @@
 	return 0;
 }
 
+void*
+amlnew(char tag, int len)
+{
+	switch(tag){
+	case 'i':
+		return mki(0);
+	case 'n':
+	case 's':
+		return mk(tag, len + 1);
+	case 'p':
+		return mk(tag, len * sizeof(void*));
+	default:
+		return mk(tag, len);
+	}
+}
+
 void
 amlinit(void)
 {
@@ -1988,7 +2082,11 @@
 int
 amlload(uchar *data, int len)
 {
-	return xec(data, data+len, amlroot, nil, nil);
+	int ret;
+
+	ret = xec(data, data+len, amlroot, nil, nil);
+	amlenum(amlroot, nil, fixnames, nil);
+	return ret;
 }
 
 void*
@@ -2029,6 +2127,8 @@
 	e = mk('E', sizeof(Env));
 	for(i=0;*fmt;fmt++){
 		switch(*fmt){
+		default:
+			return -1;
 		case 's':
 			e->arg[i++] = mks(va_arg(a, char*));
 			break;
@@ -2038,6 +2138,11 @@
 		case 'I':
 			e->arg[i++] = mki(va_arg(a, uvlong));
 			break;
+		case 'b':
+		case 'p':
+		case '*':
+			e->arg[i++] = va_arg(a, void*);
+			break;
 		}
 	}
 	r = va_arg(a, void**);
@@ -2052,4 +2157,18 @@
 	if(r != nil)
 		*r = dot;
 	return 0;
+}
+
+void
+amltake(void *p)
+{
+	if(p != nil)
+		D2H(p)->mark |= 2;
+}
+
+void
+amldrop(void *p)
+{
+	if(p != nil)
+		D2H(p)->mark &= ~2;
 }
--- /dev/null
+++ b/sys/src/libaml/amlalloc.c
@@ -1,0 +1,15 @@
+#include <u.h>
+#include <libc.h>
+#include <aml.h>
+
+void*
+amlalloc(int n)
+{
+	return mallocz(n, 1);
+}
+
+void
+amlfree(void *p)
+{
+	free(p);
+}
--- /dev/null
+++ b/sys/src/libaml/amlmapio.c
@@ -1,0 +1,9 @@
+#include <u.h>
+#include <libc.h>
+#include <aml.h>
+
+int
+amlmapio(Amlio*)
+{
+	return -1;
+}
--- /dev/null
+++ b/sys/src/libaml/amlunmapio.c
@@ -1,0 +1,8 @@
+#include <u.h>
+#include <libc.h>
+#include <aml.h>
+
+void
+amlunmapio(Amlio*)
+{
+}
--- a/sys/src/libaml/mkfile
+++ b/sys/src/libaml/mkfile
@@ -3,6 +3,9 @@
 LIB=/$objtype/lib/libaml.a
 OFILES=\
 	aml.$O\
+	amlmapio.$O\
+	amlunmapio.$O\
+	amlalloc.$O\
 
 HFILES=/sys/include/aml.h
 
--