Plan 9 from Bell Labs’s /usr/web/sources/contrib/yk/dist/9legacy/applied/libaml.diff

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


--- /sys/man/2/aml	Fri Nov 13 00:00:00 2015
+++ /sys/man/2/aml	Fri Nov 13 00:00:00 2015
@@ -0,0 +1,287 @@
+.TH AML 2
+.SH NAME
+amltag, amlval, amlint, amllen, amlnew, amlinit, amlexit, amlload, amlwalk, amleval, amlenum, amltake, amldrop - ACPI machine language interpreter
+.SH SYNOPSIS
+.\" .ta 0.75i 1.5i 2.25i 3i 3.75i 4.5i
+.ta 0.7i +0.7i +0.7i +0.7i +0.7i +0.7i +0.7i
+.EX
+#include <u.h>
+#include <libc.h>
+#include <aml.h>
+
+int	amltag(void *);
+void*	amlval(void *);
+uvlong	amlint(void *);
+int	amllen(void *);
+
+void*	amlnew(char tag, int len);
+
+void	amlinit(void);
+void	amlexit(void);
+
+int	amlload(uchar *data, int len);
+void*	amlwalk(void *dot, char *name);
+int	amleval(void *dot, char *fmt, ...);
+void	amlenum(void *dot, char *seg, int (*proc)(void *, void *), void *arg);
+
+void	amltake(void *);
+void	amldrop(void *);
+
+void*	amlroot;
+int	amldebug;
+.EE
+.SH DESCRIPTION
+The aml library implements an interpreter for the ACPI machine language
+byte code.
+.TP
+\f5amlinit() \f5amlexit()
+The interpreter runtime state is initialized by calling
+.I amlinit
+and frees all the resources when
+.I amlexit
+is called.
+The runtime state consists of objects organized in a global
+namespace. The name object referred to by
+.I amlroot
+is the root of that namespace.
+.TP
+.BI amlload( data , len )
+.I Amlload
+populates the namespace with objects parsed from the
+definition block of 
+.I len
+byte size read from
+.IR data .
+The pc kernel provides access to the ACPI tables through the
+.B /dev/acpitbls
+file (see
+.IR arch (3)
+for further details).
+.TP
+.BI amltag( p )
+Objects are dynamically allocated and typed and are passed as
+.B void*
+pointers. The type tag of an object can be determined with the
+.I amltag
+function. The following table shows the defined tags and ther
+underlying type:
+.EX
+/*
+ *	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
+ *	f	void*	field
+ *	u	void*	bufferfield
+ *	N	void*	name
+ *	R	void*	reference
+ */
+.EE
+.TP
+.BI amlwalk( dot , name )
+.I Amlwalk
+takes a path string (relative to
+.IR dot )
+in
+.I name
+and returns the final name object of the walk; or
+.B nil
+if not found.
+.TP
+\f5amlenum(\fIdot\f5,\fIseg\f5,\fIproc\f5,\fIarg\f5)
+.I Amlenum
+recursively enumerates all child name objects of
+.I dot
+that have
+.I seg
+as name; or any name if
+.I seg
+is
+.BR nil ;
+calling
+.I proc
+for each one passing
+.IR dot .
+When
+.I proc
+returns zero, enumeration will continue recursively down
+for the current dot.
+.TP
+.BI amlval( p )
+.I Amlval
+returns the value of a name, reference or field object.
+Calling
+.I amlval
+on any other object yields the same object.
+.TP
+.BI amllen( p )
+.I Amllen
+is defined for variable length objects like buffers, strings and packages.
+For strings, the number of characters (not including the terminating null byte)
+is returned. For buffers, the size of the buffer in bytes is returned.
+For packages (arrays), the number of elements is returned. For any other
+object types, the return value is undefined.
+.TP
+.BI amlint( p )
+.I Amlint
+returns the integer value of an object. For strings, the string is interpreted
+as an hexadecimal number. For buffers and buffer fields, the binary value is returned.
+Integers just return their value. Any other object types yield zero.
+.TP
+.BI amlnew( tag , len )
+Integer, buffer, string and package objects can be created with the
+.I amlnew
+function. The 
+.I tag
+specific definition of the
+.I len
+parameter is the same as in
+.I amllen
+(see above).
+.TP
+\f5amleval(\fIdot\f5,\fIfmt\f5,\fI...\f5)
+.I Amleval
+evaluates the name object
+.IR dot .
+For method evaluation, the
+.I fmt
+string parameter describes the arguments passed to the evaluated
+method. Each character in
+.I fmt
+represents a tag for an method argument taken from the
+variable argument list of
+.I amleval
+and passed to the method.
+The fmt tags
+.BR I ,
+.B i
+and
+.B s
+take
+.BR uvlong ,
+.B int
+and
+.B char*
+from the variable argument list and create object copies to
+be passed.
+The tags
+.BR b ,
+.B p
+and
+.B *
+take
+.B void*
+from the variable argument list and pass them as objects
+by reference (without conversion or copies).
+The last variable argument is a pointer to the result
+object location. When the last parameter is
+.B nil
+the result is discarded.
+.TP
+\f5amltake(\fIp\f5) \f5amldrop(\fIp\f5)
+Objects returned by
+.IR amlval ,
+.I amleval
+and
+.I amlnew
+are subject to garbage collection during method evaluation
+unless previously maked to be excluded from collection with
+.IR amltake .
+To remark an object for collection,
+.I amldrop
+needs be called.
+Objects stay valid as long as they are reachable from
+.IR amlroot .
+.bp
+.PP
+The aml library can be linked into userspace programs
+and the kernel which have different means of hardware access
+and memory constraints.
+.PP
+The
+.I Amlio
+data structure defines access to a hardware space.
+.EX
+
+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);
+};
+
+.EE
+The
+members
+.IR space ,
+.IR off ,
+.I len
+and
+.I name
+are initialized by the interpreter and describe the I/O region
+it needs access to. For memory regions,
+.I va
+can to be set to the virtual address mapping base by the
+mapping function.
+The interpreter will call the
+.I read
+and
+.I write
+function pointers with a relative offset to the regions
+base offset.
+The
+.I aux
+pointer can be used freely by the map function to attach its own
+resources to the I/O region and allows it to free these resources
+on
+.IR amlunmapio .
+.TP
+\f5amlmapio(\fIio\f5) \f5amlunmapio(\fIio\f5)
+The interpreter calls
+.I amlmapio
+with a
+.I Amlio
+data structure that is to be filled out. When finished, the
+interpreter calls
+.I amlunmapio
+with the same data structure to allow freeing resources.
+.TP
+.BI amldelay( µs )
+.I Amldelay
+is called by the interpreter with the number of microseconds
+to sleep.
+.TP
+\f5amlalloc(\fIn\f5) \f5amlfree(\fIp\f5)
+.I Amlalloc
+and
+.I amlfree
+can be optionally defined to control dynamic memory allocation 
+providing a way to limit or pool the memory allocated by acpi.
+If not provided, the library will use the functions
+defined in
+.IR malloc (2)
+for dynamic allocation.
+.SH SOURCE
+.B /sys/src/libaml
+.SH "SEE ALSO"
+.IR arch (3)
--- /sys/include/aml.h	Fri Nov 13 00:00:00 2015
+++ /sys/include/aml.h	Fri Nov 13 00:00:00 2015
@@ -0,0 +1,76 @@
+#pragma	lib	"libaml.a"
+#pragma	src	"/sys/src/libaml"
+
+/*
+ *	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
+ *	f	void*	field
+ *	u	void*	bufferfield
+ *	N	void*	name
+ *	R	void*	reference
+ */
+int		amltag(void *);
+void*		amlval(void *);
+uvlong		amlint(void *);
+int		amllen(void *);
+
+void*		amlnew(char tag, int len);
+
+void		amlinit(void);
+void		amlexit(void);
+
+int		amlload(uchar *data, int len);
+void*		amlwalk(void *dot, char *name);
+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;
+
+#pragma	varargck	type	"V"	void*
+#pragma	varargck	type	"N"	void*
+
+/* to be provided by operating system */
+extern void*	amlalloc(int);
+extern void	amlfree(void*);
+
+extern void	amldelay(int);	/* microseconds */
+
+enum {
+	MemSpace	= 0x00,
+	IoSpace		= 0x01,
+	PcicfgSpace	= 0x02,
+	EbctlSpace	= 0x03,
+	SmbusSpace	= 0x04,
+	CmosSpace	= 0x05,
+	PcibarSpace	= 0x06,
+	FixedhwSpace	= 0x08,
+	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);
diff -Nru /sys/src/libaml/aml.c /sys/src/libaml/aml.c
--- /sys/src/libaml/aml.c	Thu Jan  1 00:00:00 1970
+++ /sys/src/libaml/aml.c	Fri Nov 13 00:00:00 2015
@@ -0,0 +1,2219 @@
+#include <u.h>
+#include <libc.h>
+#include <aml.h>
+
+typedef struct Interp Interp;
+typedef struct Frame Frame;
+typedef struct Heap Heap;
+
+typedef struct Method Method;
+typedef struct Region Region;
+typedef struct Field Field;
+
+typedef struct Name Name;
+typedef struct Ref Ref;
+typedef struct Env Env;
+typedef struct Op Op;
+
+struct Heap {
+	Heap	*link;
+	short	size;
+	uchar	mark;
+	char	tag;
+};
+
+#define H2D(h)	(((Heap*)(h))+1)
+#define D2H(d)	(((Heap*)(d))-1)
+#define TAG(d)	D2H(d)->tag
+#define SIZE(d)	D2H(d)->size
+
+static char *spacename[] = {
+	"Mem", 
+	"Io",
+	"Pcicfg",
+	"Ebctl",
+	"Smbus",
+	"Cmos",
+	"Pcibar",
+	"Ipmi",
+};
+
+/* field flags */
+enum {
+	AnyAcc		= 0x00,
+	ByteAcc		= 0x01,
+	WordAcc		= 0x02,
+	DWordAcc	= 0x03,
+	QWordAcc	= 0x04,
+	BufferAcc	= 0x05,
+	AccMask		= 0x07,
+
+	NoLock		= 0x10,
+
+	Preserve	= 0x00,
+	WriteAsOnes	= 0x20,
+	WriteAsZeros	= 0x40,
+	UpdateMask	= 0x60,
+};
+
+struct Method {
+	Name	*name;
+	int	narg;
+	void*	(*eval)(void);
+	uchar	*start;
+	uchar	*end;
+};
+
+struct Region {
+	Amlio;
+	char	mapped;
+};
+
+struct Field {
+	void	*reg;	/* Buffer or Region */
+	Field	*index;
+	void	*indexv;
+	int	flags;
+	int	bitoff;
+	int	bitlen;
+};
+
+struct Name {
+	void	*v;
+
+	Name	*up;
+	Name	*next;
+	Name	*fork;
+	Name	*down;
+
+	char	seg[4];
+};
+
+struct Ref {
+	void	*ref;
+	void	**ptr;
+};
+
+struct Env {
+	void	*loc[8];
+	void	*arg[8];
+};
+
+struct Op {
+	char	*name;
+	char	*sequence;
+	void*	(*eval)(void);
+};
+
+struct Frame {
+	int	tag;
+	int	cond;
+	char	*phase;
+	uchar	*start;
+	uchar	*end;
+	Op	*op;
+	Env	*env;
+	Name	*dot;
+	void	*ref;
+	void	*aux;
+	int	narg;
+	void	*arg[8];
+};
+
+struct Interp {
+	uchar	*pc;
+	Frame	*fp;
+};
+
+static Interp	interp;
+static Frame	stack[32];
+
+#define PC	interp.pc
+#define	FP	interp.fp
+#define FB	stack
+#define FT	&stack[nelem(stack)]
+
+static Heap *hp;
+
+enum {
+	Obad, Onop, Odebug,
+	Ostr, Obyte, Oword, Odword, Oqword, Oconst,
+	Onamec, Oname, Oscope, Oalias,
+	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, Olbit, Orbit, Oinc, Odec,
+	Oland, Olor, Olnot, Oleq, Olgt, Ollt,
+	Oindex, Omutex, Oevent,
+	Ocfld, Ocfld0, Ocfld1, Ocfld2, Ocfld4, Ocfld8,
+	Oif, Oelse, Owhile, Obreak, Oret, Ocall, 
+	Ostore, Oderef, Osize, Oref, Ocref, Ocat,
+	Oacq, Orel, Ostall, Osleep, Oload, Ounload,
+};
+
+static Op optab[];
+static uchar octab1[];
+static uchar octab2[];
+
+static Name*
+rootname(Name *dot)
+{
+	while(dot != dot->up)
+		dot = dot->up;
+	return dot;
+}
+
+static void
+gcmark(void *p)
+{
+	int i;
+	Env *e;
+	Field *f;
+	Heap *h;
+	Name *n, *d;
+
+	if(p == nil)
+		return;
+	h = D2H(p);
+	if(h->mark & 1)
+		return;
+	h->mark |= 1;
+	switch(h->tag){
+	case 'E':
+		e = p;
+		for(i=0; i<nelem(e->loc); i++)
+			gcmark(e->loc[i]);
+		for(i=0; i<nelem(e->arg); i++)
+			gcmark(e->arg[i]);
+		break;
+	case 'R':
+	case 'A':
+	case 'L':
+		gcmark(((Ref*)p)->ref);
+		break;
+	case 'N':
+		n = p;
+		gcmark(n->v);
+		for(d = n->down; d; d = d->next)
+			gcmark(d);
+		gcmark(n->fork);
+		gcmark(n->up);
+		break;
+	case 'p':
+		for(i=0; i<(SIZE(p)/sizeof(void*)); i++)
+			gcmark(((void**)p)[i]);
+		break;
+	case 'r':
+		gcmark(((Region*)p)->name);
+		break;
+	case 'm':
+		gcmark(((Method*)p)->name);
+		break;
+	case 'f':
+	case 'u':
+		f = p;
+		gcmark(f->reg);
+		gcmark(f->index);
+		gcmark(f->indexv);
+		break;
+	}
+}
+
+static int
+gc(void)
+{
+	int i;
+	Heap *h, **hh;
+	Frame *f;
+
+	for(h = hp; h; h = h->link)
+		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]);
+		gcmark(f->env);
+		gcmark(f->dot);
+		gcmark(f->ref);
+	}
+
+	gcmark(amlroot);
+
+	i = 0;
+	hh = &hp;
+	while(h = *hh){
+		if(h->mark){
+			hh = &h->link;
+			continue;
+		}
+		*hh = h->link;
+		if(h->tag == 'r'){
+			Region *r = (void*)H2D(h);
+			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);
+		amlfree(h);
+		i++;
+	}
+
+	return i;
+}
+
+static void*
+mk(int tag, int size)
+{
+	Heap *h;
+	int a;
+
+	a = sizeof(Heap) + size;
+	h = amlalloc(a);
+	h->size = size;
+	h->tag = tag;
+	h->link = hp;
+	hp = h;
+	return h+1;
+}
+
+static uvlong*
+mki(uvlong i)
+{
+	uvlong *v;
+
+	v = mk('i', sizeof(uvlong));
+	*v = i;
+	return v;
+}
+
+static char*
+mks(char *s)
+{
+	char *r = mk('s', strlen(s)+1);
+	strcpy(r, s);
+	return r;
+}
+
+static int
+pkglen(uchar *p, uchar *e, uchar **np)
+{
+	ulong n;
+	uchar b;
+
+	if(p >= e)
+		return -1;
+	b = *p++;
+	if(b <= 0x3F)
+		n = b;
+	else {
+		n = b & 0xF;
+		if(p >= e)
+			return -1;
+		n += *p++ << 4;
+		if(b >= 0x80){
+			if(p >= e)
+				return -1;
+			n += *p++ << 12;
+		}
+		if(b >= 0xC0){
+			if(p >= e)
+				return -1;
+			n += *p++ << 20;
+		}
+	}
+	if(np)
+		*np = p;
+	return n;
+}
+
+static Name*
+forkname(Name *dot)
+{
+	Name *n;
+
+	n = mk('N', sizeof(Name));
+	*n = *dot;
+	n->fork = dot;
+	n->next = n->down = nil;
+	if(dot->v == dot)
+		n->v = n;
+	if(dot->up == dot)
+		n->up = n;
+	else {
+		if(n->up = forkname(dot->up))
+			n->up->down = n;
+	}
+	return n;
+}
+
+static Name*
+getseg(Name *dot, void *seg, int new)
+{
+	Name *n, *l;
+
+	for(n = l = nil; dot; dot = dot->fork){
+		for(n = dot->down; n; n = n->next){
+			if(memcmp(seg, n->seg, 4) == 0)
+				return n;
+			l = n;
+		}
+		if(new){
+			n = mk('N', sizeof(Name));
+			memmove(n->seg, seg, sizeof(n->seg));
+			n->up = dot;
+			if(l == nil)
+				dot->down = n;
+			else
+				l->next = n;
+			n->v = n;
+			break;
+		}
+	}
+	return n;
+}
+
+Name*
+getname(Name *dot, char *path, int new)
+{
+	char seg[4];
+	int i, s;
+	Name *x;
+
+	s = !new;
+	if(*path == '\\'){
+		path++;
+		dot = rootname(dot);
+		s = 0;
+	}
+	while(*path == '^'){
+		path++;
+		dot = dot->up;
+		s = 0;
+	}
+	do {
+		for(i=0; i<4; i++){
+			if(*path == 0 || *path == '.')
+				break;
+			seg[i] = *path++;
+		}
+		if(i == 0)
+			break;
+		while(i < 4)
+			seg[i++] = '_';
+		if(s && *path == 0){
+			for(;;){
+				if(x = getseg(dot, seg, 0))
+					break;
+				if(dot == dot->up)
+					break;
+				dot = dot->up;
+			}
+			return x;
+		}
+		s = 0;
+		dot = getseg(dot, seg, new);
+	} while(*path++ == '.');
+
+	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;
+
+	v = 0ULL;
+	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;
+
+	switch(TAG(reg)){
+	case 'b':
+		p = reg;
+		if((off+len) > SIZE(p))
+			break;
+		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(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;
+		}
+		if(r->mapped <= 0)
+			break;
+
+		if(r->va != nil)
+			p = r->va + off;
+		else {
+			if(len > sizeof(buf))
+				break;
+			p = buf;
+		}
+
+		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;
+}
+
+static uvlong
+ival(void *p)
+{
+	int n;
+
+	if(p != nil){
+		switch(TAG(p)){
+		case 'i':
+			return *((uvlong*)p);
+		case 's':
+			if(*((char*)p) == 0)
+				break;
+			return strtoull((char*)p, 0, 16);
+		case 'b':
+			n = SIZE(p);
+			if(n > 0){
+				if(n > 8) n = 8;
+				return rwreg(p, 0, n, 0, 0);
+			}
+		}
+	}
+	return 0;
+}
+
+static void *deref(void *p);
+static void *store(void *s, void *d);
+
+static int
+fieldalign(int flags)
+{
+	switch(flags & AccMask){
+	default:
+	case AnyAcc:
+	case ByteAcc:
+	case BufferAcc:
+		return 1;
+	case WordAcc:
+		return 2;
+	case DWordAcc:
+		return 4;
+	case QWordAcc:
+		return 8;
+	}
+}
+
+static void*
+rwfield(Field *f, void *v, int write)
+{
+	int boff, blen, wo, ws, wl, wa, wd, i;
+	uvlong w, m;
+	void *reg;
+	uchar *b;
+
+	if(f == nil || (reg = deref(f->reg)) == nil)
+		return nil;
+	if(f->index)
+		store(f->indexv, f->index);
+	blen = f->bitlen;
+	if(write){
+		if(v && TAG(v) == 'b'){
+			b = v;
+			if(SIZE(b)*8 < blen)
+				blen = SIZE(b)*8;
+		} else {
+			w = ival(v);
+			b = mk('b', (blen+7)/8);
+			putle(b, SIZE(b), w);
+		}
+	} else
+		b = mk('b', (blen+7)/8);
+	wa = fieldalign(f->flags);
+	wd = wa*8;
+	boff = 0;
+	while((wl = (blen-boff)) > 0){
+		wo = (f->bitoff+boff) / wd;
+		ws = (f->bitoff+boff) % wd;
+		if(wl > (wd - ws))
+			wl = wd - ws;
+		if(write){
+			w = 0;
+			for(i = 0; i < wl; i++, boff++)
+				if(b[boff/8] & (1<<(boff%8)))
+					w |= 1ULL<<i;
+			w <<= ws;
+			if(wl != wd){
+				m = ((1ULL<<wl)-1) << ws;
+				w |= rwreg(reg, wo*wa, wa, 0, 0) & ~m;
+			}
+			rwreg(reg, wo*wa, wa, w, 1);
+		} else {
+			w = rwreg(reg, wo*wa, wa, 0, 0) >> ws;
+			for(i = 0; i < wl; i++, boff++){
+				b[boff/8] |= (w&1)<<(boff%8);
+				w >>= 1;
+			}
+		}
+	}
+	if(write)
+		return nil;
+	if(blen > 64)
+		return b;
+	w = getle(b, SIZE(b));
+	return mki(w);
+}
+
+static void*
+deref(void *p)
+{
+	if(p) switch(TAG(p)){
+	case 'N':
+		return ((Name*)p)->v;
+	case 'R': case 'A': case 'L':
+		return *((Ref*)p)->ptr;
+	case 'f': case 'u':
+		return rwfield(p, nil, 0);
+	}
+	return p;
+}
+
+static void*
+copy(int tag, void *s)
+{
+	static char hex[] = "0123456789ABCDEF";
+	uvlong v;
+	void *d;
+	int i, n;
+
+	if(tag == 0){
+		if(s == nil)
+			return nil;
+		tag = TAG(s);
+	}
+	if(s == nil || TAG(s) == 'i'){
+		n = 4;
+		v = ival(s);
+		if(v > 0xFFFFFFFFULL)
+			n <<= 1;
+		switch(tag){
+		case 'b':
+			d = mk(tag, n);
+			rwreg(d, 0, n, v, 1);
+			return d;
+		case 's':
+			n <<= 1;
+			d = mk(tag, n+1);
+			((char*)d)[n] = 0;
+			while(n > 0){
+				((char*)d)[--n] = hex[v & 0xF];
+				v >>= 4;
+			}
+			return d;
+		case 'i':
+			if(v == 0ULL)
+				return nil;
+			return mki(v);
+		}
+	} else {
+		n = SIZE(s);
+		switch(tag){
+		case 's':
+			if(TAG(s) == 'b'){
+				d = mk(tag, n*3 + 1);
+				for(i=0; i<n; i++){
+					((char*)d)[i*3 + 0] = hex[((uchar*)s)[i] >> 4];
+					((char*)d)[i*3 + 1] = hex[((uchar*)s)[i] & 0xF];
+					((char*)d)[i*3 + 2] = ' ';
+				}
+				((char*)d)[n*3] = 0;
+				return d;
+			}
+			/* no break */
+		case 'b':
+			if(TAG(s) == 's'){
+				n = strlen(s);
+				/* zero length string is converted to zero length buffer */
+				if(n > 0) n++;
+			}
+			d = mk(tag, n);
+			memmove(d, s, n);
+			return d;
+		}
+	}
+	return s;
+}
+
+static void*
+store(void *s, void *d)
+{
+	void *p, **pp;
+
+	if(d == nil)
+		return nil;
+	switch(TAG(d)){
+	default:
+		return nil;
+	case 'A':
+		s = deref(s);
+		/* no break */
+	case 'R': case 'L':
+		pp = ((Ref*)d)->ptr;
+		while((p = *pp) != nil){
+			switch(TAG(p)){
+			case 'R': case 'A': case 'L':
+				pp = ((Ref*)p)->ptr;
+				break;
+			case 'N':
+				pp = &((Name*)p)->v;
+				break;
+			}
+			if(*pp == p)
+				break;
+		}
+		break;
+	case 'N':
+		pp = &((Name*)d)->v;
+		break;
+	}
+	p = *pp;
+	if(p != nil && TAG(p) != 'N'){
+		switch(TAG(p)){
+		case 'f':
+		case 'u':
+			rwfield(p, s, 1);
+			return d;
+		}
+		if(TAG(d) != 'A' && TAG(d) != 'L'){
+			*pp = copy(TAG(p), s);
+			return d;
+		}
+	}
+	*pp = copy(0, s);
+	return d;
+}
+
+static int
+Nfmt(Fmt *f)
+{
+	char buf[5];
+	int i;
+	Name *n;
+
+	n = va_arg(f->args, Name*);
+	if(n == nil)
+		return fmtprint(f, "?NIL");
+	if(n == n->up)
+		return fmtprint(f, "\\");
+	strncpy(buf, n->seg, 4);
+	buf[4] = 0;
+	for(i=3; i>0; i--){
+		if(buf[i] != '_')
+			break;
+		buf[i] = 0;
+	}
+	if(n->up == n->up->up)
+		return fmtprint(f, "\\%s", buf);
+	return fmtprint(f, "%N.%s", n->up, buf);
+}
+
+static int
+Vfmt(Fmt *f)
+{
+	void *p;
+	int i, n, c;
+	Env *e;
+	Field *l;
+	Name *nm;
+	Method *m;
+	Region *g;
+	Ref *r;
+
+	p = va_arg(f->args, void*);
+	if(p == nil)
+		return fmtprint(f, "nil");
+	c = TAG(p);
+	switch(c){
+	case 'N':
+		nm = p;
+		if(nm->v != nm)
+			return fmtprint(f, "%N=%V", nm, nm->v);
+		return fmtprint(f, "%N=*", nm);
+	case 'A':
+	case 'L':
+		r = p;
+		e = r->ref;
+		if(c == 'A')
+			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':
+		n = SIZE(p)/sizeof(void*);
+		fmtprint(f, "Package(%d){", n);
+		for(i=0; i<n; i++){
+			if(i > 0)
+				fmtprint(f, ", ");
+			fmtprint(f, "%V", ((void**)p)[i]);
+		}
+		fmtprint(f, "}");
+		return 0;
+	case 'b':
+		n = SIZE(p);
+		fmtprint(f, "Buffer(%d){", n);
+		for(i=0; i<n; i++){
+			if(i > 0)
+				fmtprint(f, ", ");
+			fmtprint(f, "%.2uX", ((uchar*)p)[i]);
+		}
+		fmtprint(f, "}");
+		return 0;
+	case 'r':
+		g = p;
+		return fmtprint(f, "Region(%s, %#llux, %#llux)",
+			spacename[g->space & 7], g->off, g->len);
+	case 'm':
+		m = p;
+		fmtprint(f, "%N(", m->name);
+		for(i=0; i < m->narg; i++){
+			if(i > 0)
+				fmtprint(f, ", ");
+			fmtprint(f, "Arg%d", i);
+		}
+		fmtprint(f, ")");
+		return 0;
+	case 'u':
+		fmtprint(f, "Buffer");
+		/* no break */
+	case 'f':
+		l = p;
+		if(l->index)
+			return fmtprint(f, "IndexField(%x, %x, %x) @ %V[%V]",
+				l->flags, l->bitoff, l->bitlen, l->index, l->indexv);
+		return fmtprint(f, "Field(%x, %x, %x) @ %V",
+			l->flags, l->bitoff, l->bitlen, l->reg);
+	default:
+		return fmtprint(f, "%c:%p", c, p);
+	}
+}
+
+static void
+dumpregs(void)
+{
+	Frame *f;
+	Env *e;
+	int i;
+
+	print("\n*** dumpregs: PC=%p FP=%p\n", PC, FP);
+	e = nil;
+	for(f = FP; f >= FB; f--){
+		print("%.8p.%.2lx: %-8s %N\t", f->start, f-FB, f->phase, f->dot);
+		if(f->op)
+			print("%s", f->op->name);
+		print("(");
+		for(i=0; i<f->narg; i++){
+			if(i > 0)
+				print(", ");
+			print("%V", f->arg[i]);
+		}
+		print(")\n");
+		if(e == f->env)
+			continue;
+		if(e = f->env){
+			for(i=0; i<nelem(e->arg); i++)
+				print("Arg%d=%V ", i, e->arg[i]);
+			print("\n");
+			for(i=0; i<nelem(e->loc); i++)
+				print("Local%d=%V ", i, e->loc[i]);
+			print("\n");
+		}
+	}
+}
+
+static int
+xec(uchar *pc, uchar *end, Name *dot, Env *env, void **pret)
+{
+	static int loop;
+	int i, c;
+	void *r;
+
+	PC = pc;
+	FP = FB;
+
+	FP->tag = 0;
+	FP->cond = 0;
+	FP->narg = 0;
+	FP->phase = "}";
+	FP->start = PC;
+	FP->end = end;
+	FP->aux = end;
+	FB->ref = nil;
+	FP->dot = dot;
+	FP->env = env;
+	FP->op = nil;
+
+	for(;;){
+		if((++loop & 127) == 0)
+			gc();
+		if(amldebug)
+			print("\n%.8p.%.2lx %-8s\t%N\t", PC, FP - FB, FP->phase, FP->dot);
+		r = nil;
+		c = *FP->phase++;
+		switch(c){
+		default:
+			if(PC >= FP->end){
+			Overrun:
+				print("aml: PC overrun frame end");
+				goto Out;
+			}
+			FP++;
+			if(FP >= FT){
+				print("aml: frame stack overflow");
+				goto Out;
+			}
+			*FP = FP[-1];
+			FP->aux = nil;
+			FP->ref = nil;
+			FP->tag = c;
+			FP->start = PC;
+			c = *PC++;
+			if(amldebug) print("%.2X", c);
+			if(c == '['){
+				if(PC >= FP->end)
+					goto Overrun;
+				c = *PC++;
+				if(amldebug) print("%.2X", c);
+				c = octab2[c];
+			}else
+				c = octab1[c];
+			FP->op = &optab[c];
+			FP->narg = 0;
+			FP->phase = FP->op->sequence;
+			if(amldebug) print("\t%s %s", FP->op->name, FP->phase);
+			continue;
+		case '{':
+			end = PC;
+			c = pkglen(PC, FP->end, &PC);
+			end += c;
+			if(c < 0 || end > FP->end)
+				goto Overrun;
+			FP->end = end;
+			continue;
+		case ',':
+			FP->start = PC;
+			continue;
+		case 's':
+			if(end = memchr(PC, 0, FP->end - PC))
+				end++;
+			else
+				end = FP->end;
+			c = end - PC;
+			r = mk('s', c+1);
+			memmove(r, PC, c);
+			((uchar*)r)[c] = 0;
+			PC = end;
+			break;
+		case '1':
+		case '2':
+		case '4':
+		case '8':
+			end = PC+(c-'0');
+			if(end > FP->end)
+				goto Overrun;
+			else {
+				r = mki(*PC++);
+				for(i = 8; PC < end; i += 8)
+					*((uvlong*)r) |= ((uvlong)*PC++) << i;
+			}
+			break;
+		case '}':
+		case 0:
+			if(FP->op){
+				if(amldebug){
+					print("*%p,%V\t%s(", FP->aux, FP->ref, FP->op->name);
+					for(i = 0; i < FP->narg; i++){
+						if(i > 0)
+							print(", ");
+						print("%V", FP->arg[i]);
+					}
+					print(")");
+				}
+				for(i = FP->narg; i < nelem(FP->arg); i++)
+					FP->arg[i] = nil;
+				r = FP->op->eval();
+				if(amldebug)
+					print(" -> %V", r);
+			}
+
+			c = FP->phase[-1];
+			if(c == '}' && PC < FP->end){
+				FP->narg = 0;
+				FP->phase = "*}";
+				continue;
+			}
+
+			if(r) switch(FP->tag){
+			case '@':
+				break;
+			case 'n':
+			case 'N':
+				if(TAG(r) != 'N')
+					r = nil;
+				break;
+			default:
+				if((r = deref(r)) == nil)
+					break;
+				switch(TAG(r)){
+				case 'f': case 'u':
+					r = rwfield(r, nil, 0);
+					break;
+				case 'm': {
+					Method *m = r;
+					FP->ref = m;
+					FP->narg = 0;
+					FP->phase = "********}" + (8 - m->narg);
+					FP->op = &optab[Ocall];
+					continue;
+					}
+				}
+			}
+			FP--;
+			break;
+		}
+		if(FP < FB){
+			if(pret){
+				if(amldebug) print(" -> %V\n", r);
+				*pret = r;
+			}
+			return 0;
+		}
+		FP->arg[FP->narg++] = r;
+	}
+Out:
+	if(amldebug)
+		dumpregs();
+	return -1;
+}
+
+static void*
+evalnamec(void)
+{
+	static char name[1024];
+	char *d;
+	void *r;
+	int c;
+
+	c = 1;
+	d = name;
+	PC = FP->start;
+	if(*PC == '\\')
+		*d++ = *PC++;
+	while(*PC == '^'){
+		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++;
+		c = 2;
+	} else if(*PC == '/'){
+		PC++;
+		c = *PC++;
+	} else if(*PC == 0){
+		PC++;
+		c = 0;
+	}
+	while(c > 0){
+		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++ = '.';
+	}
+	*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*
+evaliarg0(void)
+{
+	return FP->arg[0];
+}
+
+static void*
+evalconst(void)
+{
+	switch(FP->start[0]){
+	case 0x01:
+		return mki(1);
+	case 0xFF:
+		return mki(-1);
+	}
+	return nil;
+}
+
+static void*
+evalbuf(void)
+{
+	int n, m;
+	uchar *p;
+
+	n = ival(FP->arg[0]);
+	p = mk('b', n);
+	m = FP->end - PC;
+	if(m > n)
+		m = n;
+	memmove(p, PC, m);
+	PC = FP->end;
+	return p;
+}
+
+static void*
+evalpkg(void)
+{
+	void **p, **x;
+	int n;
+
+	if((p = FP->ref) != nil){
+		x = FP->aux;
+		if(x >= p && x < (p+(SIZE(p)/sizeof(void*)))){
+			*x++ = FP->arg[0];
+			FP->aux = x;
+		}
+	}else {
+		n = ival(FP->arg[0]);
+		if(n < 0) n = 0;
+		p = mk('p', n*sizeof(void*));
+		FP->aux = p;
+		FP->ref = p;
+	}
+	return p;
+}
+
+static void*
+evalname(void)
+{
+	Name *n;
+
+	if(n = FP->arg[0])
+		n->v = FP->arg[1];
+	else
+		PC = FP->end;
+	return nil;
+}
+
+static void*
+evalscope(void)
+{
+	Name *n;
+
+	if(n = FP->arg[0])
+		FP->dot = n;
+	else
+		PC = FP->end;
+	FP->op = nil;
+	return nil;
+}
+
+static void*
+evalalias(void)
+{
+	Name *n;
+
+	if(n = FP->arg[1])
+		n->v = deref(FP->arg[0]);
+	return nil;
+}
+
+static void*
+evalmet(void)
+{
+	Name *n;
+	Method *m;
+
+	if((n = FP->arg[0]) != nil){
+		m = mk('m', sizeof(Method));
+		m->narg = ival(FP->arg[1]) & 7;
+		m->start = PC;
+		m->end = FP->end;
+		m->name = n;
+		n->v = m;
+	}
+	PC = FP->end;
+	return nil;
+}
+
+static void*
+evalreg(void)
+{
+	Name *n;
+	Region *r;
+
+	if((n = FP->arg[0]) != nil){
+		r = mk('r', sizeof(Region));
+		r->space = ival(FP->arg[1]);
+		r->off = ival(FP->arg[2]);
+		r->len = ival(FP->arg[3]);
+		r->name = n;
+		r->va = nil;
+		n->v = r;
+	}
+	return nil;
+}
+
+static void*
+evalcfield(void)
+{
+	void *r;
+	Field *f;
+	Name *n;
+	int c;
+
+	r = FP->arg[0];
+	if(r == nil || (TAG(r) != 'b' && TAG(r) != 'r'))
+		return nil;
+	c = FP->op - optab;
+	if(c == Ocfld)
+		n = FP->arg[3];
+	else
+		n = FP->arg[2];
+	if(n == nil || TAG(n) != 'N')
+		return nil;
+	if(TAG(r) == 'b')
+		f = mk('u', sizeof(Field));
+	else
+		f = mk('f', sizeof(Field));
+	switch(c){
+	case Ocfld:
+		f->bitoff = ival(FP->arg[1]);
+		f->bitlen = ival(FP->arg[2]);
+		break;
+	case Ocfld0:
+		f->bitoff = ival(FP->arg[1]);
+		f->bitlen = 1;
+		break;
+	case Ocfld1:
+	case Ocfld2:
+	case Ocfld4:
+	case Ocfld8:
+		f->bitoff = 8*ival(FP->arg[1]);
+		f->bitlen = 8*(c - Ocfld0);
+		break;
+	}
+	f->reg = r;
+	n->v = f;
+	return nil;
+}
+
+static void*
+evalfield(void)
+{
+	int flags, bitoff, wa, n;
+	Field *f, *df;
+	Name *d;
+	uchar *p;
+
+	df = nil;
+	flags = 0;
+	bitoff = 0;
+	switch(FP->op - optab){
+	case Ofld:
+		flags = ival(FP->arg[1]);
+		break;
+	case Oxfld:
+		df = deref(FP->arg[1]);
+		if(df == nil || TAG(df) != 'f')
+			goto Out;
+		flags = ival(FP->arg[2]);
+		break;
+	}
+	p = PC;
+	if(p >= FP->end)
+		return nil;
+	while(p < FP->end){
+		if(*p == 0x00){
+			p++;
+			if((n = pkglen(p, FP->end, &p)) < 0)
+				break;
+			bitoff += n;
+			continue;
+		}
+		if(*p == 0x01){
+			p++;
+			flags = *p;
+			p += 2;
+			continue;
+		}
+		if(p+4 >= FP->end)
+			break;
+		if((d = getseg(FP->dot, p, 1)) == nil)
+			break;
+		if((n = pkglen(p+4, FP->end, &p)) < 0)
+			break;
+		f = mk('f', sizeof(Field));
+		f->flags = flags;
+		f->bitlen = n;
+		switch(FP->op - optab){
+		case Ofld:
+			f->reg = FP->arg[0];
+			f->bitoff = bitoff;
+			break;
+		case Oxfld:
+			wa = fieldalign(df->flags);
+			f->reg = df->reg;
+			f->bitoff = df->bitoff + (bitoff % (wa*8));
+			f->indexv = mki((bitoff/(wa*8))*wa);
+			f->index = FP->arg[0];
+			break;
+		}
+		bitoff += n;
+		d->v = f;
+	}
+Out:
+	PC = FP->end;
+	return nil;
+}
+
+static void*
+evalnop(void)
+{
+	return nil;
+}
+
+static void*
+evalbad(void)
+{
+	int i;
+
+	print("aml: bad opcode %p: ", PC);
+	for(i=0; i < 8 && (FP->start+i) < FP->end; i++){
+		if(i > 0)
+			print(" ");
+		print("%.2X", FP->start[i]);
+	}
+	if((FP->start+i) < FP->end)
+		print("...");
+	print("\n");
+	PC = FP->end;
+	return nil;
+}
+
+static void*
+evalcond(void)
+{
+	switch(FP->op - optab){
+	case Oif:
+		if(FP <= FB)
+			break;
+		FP[-1].cond = ival(FP->arg[0]) != 0;
+		if(!FP[-1].cond)
+			PC = FP->end;
+		break;
+	case Oelse:
+		if(FP <= FB)
+			break;
+		if(FP[-1].cond)
+			PC = FP->end;
+		break;
+	case Owhile:
+		if(FP->aux){
+			if(PC >= FP->end){
+				PC = FP->start;
+				FP->aux = nil;
+			}
+			return nil;
+		}
+		FP->aux = FP->end;
+		if(ival(FP->arg[0]) == 0){
+			PC = FP->end;
+			break;
+		}
+		return nil;
+	}
+	FP->op = nil;
+	return nil;
+}
+
+static void*
+evalcmp(void)
+{
+	void *a, *b;
+	int tag, c;
+
+	a = FP->arg[0];
+	b = FP->arg[1];
+	if(a == nil || TAG(a) == 'i'){
+		c = ival(a) - ival(b);
+	} else {
+		tag = TAG(a);
+		if(b == nil || TAG(b) != tag)
+			b = copy(tag, b);
+		if(TAG(b) != tag)
+			return nil;	/* botch */
+		switch(tag){
+		default:
+			return nil;	/* botch */
+		case 's':
+			c = strcmp((char*)a, (char*)b);
+			break;
+		case 'b':
+			if((c = SIZE(a) - SIZE(b)) == 0)
+				c = memcmp(a, b, SIZE(a));
+			break;
+		}
+	}
+
+	switch(FP->op - optab){
+	case Oleq:
+		if(c == 0) return mki(1);
+		break;
+	case Olgt:
+		if(c > 0) return mki(1);
+		break;
+	case Ollt:
+		if(c < 0) return mki(1);
+		break;
+	}
+	return nil;
+}
+
+static void*
+evalcall(void)
+{
+	Method *m;
+	Env *e;
+	int i;
+
+	if(FP->aux){
+		if(PC >= FP->end){
+			PC = FP->aux;
+			FP->end = PC;
+		}
+		return nil;
+	}
+	m = FP->ref;
+	e = mk('E', sizeof(Env));
+	for(i=0; i<FP->narg; i++)
+		e->arg[i] = deref(FP->arg[i]);
+	FP->env = e;
+	FP->narg = 0;
+	FP->dot = m->name;
+	if(m->eval != nil){
+		FP->op = nil;
+		FP->end = PC;
+		return (*m->eval)();
+	}
+	FP->dot = forkname(FP->dot);
+	FP->aux = PC;
+	FP->start = m->start;
+	FP->end = m->end;
+	PC = FP->start;
+	return nil;
+}
+
+static void*
+evalret(void)
+{
+	void *r = FP->arg[0];
+	int brk = (FP->op - optab) != Oret;
+	while(--FP >= FB){
+		switch(FP->op - optab){
+		case Owhile:
+			if(!brk)
+				continue;
+			PC = FP->end;
+			return nil;
+		case Ocall:
+			PC = FP->aux;
+			return r;
+		}
+	}
+	FP = FB;
+	PC = FB->end;
+	return r;
+}
+
+static void*
+evalenv(void)
+{
+	Ref *r;
+	Env *e;
+	int c;
+
+	if((e = FP->env) == nil)
+		return nil;
+	c = FP->start[0];
+	if(c >= 0x60 && c <= 0x67){
+		r = mk('L', sizeof(Ref));
+		r->ptr = &e->loc[c - 0x60];
+	} else if(c >= 0x68 && c <= 0x6E){
+		r = mk('A', sizeof(Ref));
+		r->ptr = &e->arg[c - 0x68];
+	} else
+		return nil;
+	r->ref = e;
+	return r;
+}
+
+static void*
+evalstore(void)
+{
+	return store(FP->arg[0], FP->arg[1]);
+}
+
+static void*
+evalcat(void)
+{
+	void *r, *a, *b;
+	int tag, n, m;
+
+	a = FP->arg[0];
+	b = FP->arg[1];
+	if(a == nil || TAG(a) == 'i')
+		a = copy('b', a);	/* Concat(Int, ???) -> Buf */
+	tag = TAG(a);
+	if(b == nil || TAG(b) != tag)
+		b = copy(tag, b);
+	if(TAG(b) != tag)
+		return nil;	/* botch */
+	switch(tag){
+	default:
+		return nil;	/* botch */
+	case 'b':
+		n = SIZE(a);
+		m = SIZE(b);
+		r = mk('b', n + m);
+		memmove(r, a, n);
+		memmove((uchar*)r + n, b, m);
+		break;
+	case 's':
+		n = strlen((char*)a);
+		m = strlen((char*)b);
+		r = mk('s', n + m + 1);
+		memmove(r, a, n);
+		memmove((char*)r + n, b, m);
+		((char*)r)[n+m] = 0;
+		break;
+	}
+	store(r, FP->arg[2]);
+	return r;
+}
+
+static void*
+evalindex(void)
+{
+	Field *f;
+	void *p;
+	Ref *r;
+	int x;
+
+	x = ival(FP->arg[1]);
+	if(p = deref(FP->arg[0])) switch(TAG(p)){
+	case 's':
+		if(x >= strlen((char*)p))
+			break;
+		/* no break */
+	case 'b':
+		if(x < 0 || x >= SIZE(p))
+			break;
+		f = mk('u', sizeof(Field));
+		f->reg = p;
+		f->bitlen = 8;
+		f->bitoff = 8*x;
+		store(f, FP->arg[2]);
+		return f;
+	case 'p':
+		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));
+		else
+			r = mk('R', sizeof(Ref));
+		r->ref = p;
+		r->ptr = ((void**)p) + x;
+		store(r, FP->arg[2]);
+		return r;
+	}
+	return nil;
+}
+
+static void*
+evalcondref(void)
+{
+	void *s;
+	if((s = FP->arg[0]) == nil)
+		return nil;
+	store(s, FP->arg[1]);
+	return mki(1);
+}
+
+static void*
+evalsize(void)
+{
+	return mki(amllen(FP->arg[0]));
+}
+
+static void*
+evalderef(void)
+{
+	void *p;
+
+	if(p = FP->arg[0]){
+		if(TAG(p) == 's' || TAG(p) == 'n')
+			p = getname(FP->dot, (char*)p, 0);
+		p = deref(p);
+	}
+	return p;
+}
+
+static void*
+evalarith(void)
+{
+	uvlong v, d;
+	void *r;
+	int i;
+
+	r = nil;
+	switch(FP->op - optab){
+	case Oadd:
+		r = mki(ival(FP->arg[0]) + ival(FP->arg[1]));
+		break;
+	case Osub:
+		r = mki(ival(FP->arg[0]) - ival(FP->arg[1]));
+		break;
+	case Omul:
+		r = mki(ival(FP->arg[0]) * ival(FP->arg[1]));
+		break;
+	case Omod:
+	case Odiv:
+		v = ival(FP->arg[0]);
+		d = ival(FP->arg[1]);
+		if(d == 0){
+			print("aml: division by zero: PC=%#p\n", PC);
+			return nil;
+		}
+		r = mki(v % d);
+		store(r, FP->arg[2]);
+		if((FP->op - optab) != Odiv)
+			return r;
+		r = mki(v / d);
+		store(r, FP->arg[3]); 
+		return r;
+	case Oshl:
+		r = mki(ival(FP->arg[0]) << ival(FP->arg[1]));
+		break;
+	case Oshr:
+		r = mki(ival(FP->arg[0]) >> ival(FP->arg[1]));
+		break;
+	case Oand:
+		r = mki(ival(FP->arg[0]) & ival(FP->arg[1]));
+		break;
+	case Onand:
+		r = mki(~(ival(FP->arg[0]) & ival(FP->arg[1])));
+		break;
+	case Oor:
+		r = mki(ival(FP->arg[0]) | ival(FP->arg[1]));
+		break;
+	case Onor:
+		r = mki(~(ival(FP->arg[0]) | ival(FP->arg[1])));
+		break;
+	case Oxor:
+		r = mki(ival(FP->arg[0]) ^ ival(FP->arg[1]));
+		break;
+	case Onot:
+		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:
+		return mki(ival(FP->arg[0]) || ival(FP->arg[1]));
+	case Olnot:
+		return mki(ival(FP->arg[0]) == 0);
+
+	case Oinc:
+		r = mki(ival(deref(FP->arg[0]))+1);
+		store(r, FP->arg[0]);
+		return r;
+	case Odec:
+		r = mki(ival(deref(FP->arg[0]))-1);
+		store(r, FP->arg[0]);
+		return r;
+	}
+
+	store(r, FP->arg[2]);
+	return r;
+}
+
+static void*
+evalload(void)
+{
+	enum { LenOffset = 4, HdrLen = 36 };
+	uvlong *tid;
+	Region *r;
+	int l;
+
+	tid = nil;
+	if(FP->aux){
+		if(PC >= FP->end){
+			amlenum(amlroot, nil, fixnames, nil);
+			FP->aux = nil;
+			FP->end = PC;
+			tid = mki(1);	/* fake */
+		}
+	} else {
+		store(nil, FP->arg[1]);
+		if(FP->arg[0] == nil)
+			return nil;
+
+		l = rwreg(FP->arg[0], LenOffset, 4, 0, 0);
+		if(l <= HdrLen)
+			return nil;
+
+		FP->aux = PC;	/* save */
+		FP->ref = FP->arg[0];
+		switch(TAG(FP->ref)){
+		case 'b':
+			if(SIZE(FP->ref) < l)
+				return nil;
+			PC = (uchar*)FP->ref + HdrLen;
+			break;
+		case 'r':
+			r = FP->ref;
+			if(r->len < l || r->va == nil || r->mapped <= 0)
+				return nil;
+			PC = (uchar*)r->va + HdrLen;
+			break;
+		default:
+			return nil;
+		}
+		FP->end = PC + (l - HdrLen);
+		FP->dot = amlroot;
+		FP->env = nil;
+
+		tid = mki(1); /* fake */
+		store(tid, FP->arg[1]);
+	}
+	return tid;
+}
+
+static void*
+evalstall(void)
+{
+	amldelay(ival(FP->arg[0]));
+	return nil;
+}
+
+static void*
+evalsleep(void)
+{
+	amldelay(ival(FP->arg[0])*1000);
+	return nil;
+}
+
+static Op optab[] = {
+	[Obad]		"",			"",		evalbad,
+	[Onop]		"Noop",			"",		evalnop,
+	[Odebug]	"Debug",		"",		evalnop,
+
+	[Ostr]		".str",			"s",		evaliarg0,
+	[Obyte]		".byte",		"1",		evaliarg0,
+	[Oword]		".word",		"2",		evaliarg0,
+	[Odword]	".dword",		"4",		evaliarg0,
+	[Oqword]	".qword",		"8",		evaliarg0,
+	[Oconst]	".const",		"",		evalconst,
+	[Onamec]	".name",		"",		evalnamec,
+	[Oenv]		".env",			"",		evalenv,
+
+	[Oname]		"Name",			"N*",		evalname,
+	[Oscope]	"Scope",		"{n}",		evalscope,
+	[Oalias]	"Alias",		"nN",		evalalias,
+
+	[Odev]		"Device",		"{N}",		evalscope,
+	[Ocpu]		"Processor",		"{N141}",	evalscope,
+	[Othz]		"ThermalZone",		"{N}",		evalscope,
+	[Oprc]		"PowerResource",	"{N12}",	evalscope,
+
+	[Oreg]		"OperationRegion",	"N1ii",		evalreg,
+	[Ofld]		"Field",		"{n1",		evalfield,
+	[Oxfld]		"IndexField",		"{nn1",		evalfield,
+
+	[Ocfld]		"CreateField",		"*iiN",		evalcfield,
+	[Ocfld0]	"CreateBitField",	"*iN",		evalcfield,
+	[Ocfld1]	"CreateByteField",	"*iN",		evalcfield,
+	[Ocfld2]	"CreateWordField",	"*iN",		evalcfield,
+	[Ocfld4]	"CreateDWordField",	"*iN",		evalcfield,
+	[Ocfld8]	"CreateQWordField",	"*iN",		evalcfield,
+
+	[Opkg]		"Package",		"{1}",		evalpkg,
+	[Ovpkg]		"VarPackage",		"{i}",		evalpkg,
+	[Obuf]		"Buffer",		"{i",		evalbuf,
+	[Omet]		"Method",		"{N1",		evalmet,
+
+	[Oadd]		"Add",			"ii@",		evalarith,
+	[Osub]		"Subtract",		"ii@",		evalarith,
+	[Omod]		"Mod",			"ii@",		evalarith,
+	[Omul]		"Multiply",		"ii@",		evalarith,
+	[Odiv]		"Divide",		"ii@@",		evalarith,
+	[Oshl]		"ShiftLef",		"ii@",		evalarith,
+	[Oshr]		"ShiftRight",		"ii@",		evalarith,
+	[Oand]		"And",			"ii@",		evalarith,
+	[Onand]		"Nand",			"ii@",		evalarith,
+	[Oor]		"Or",			"ii@",		evalarith,
+	[Onor]		"Nor",			"ii@",		evalarith,
+	[Oxor]		"Xor",			"ii@",		evalarith,
+	[Onot]		"Not",			"i@",		evalarith,
+
+	[Olbit]		"FindSetLeftBit",	"i@",		evalarith,
+	[Orbit]		"FindSetRightBit",	"i@",		evalarith,
+
+	[Oinc]		"Increment",		"@",		evalarith,
+	[Odec]		"Decrement",		"@",		evalarith,
+
+	[Oland]		"LAnd",			"ii",		evalarith,
+	[Olor]		"LOr",			"ii",		evalarith,
+	[Olnot]		"LNot",			"i",		evalarith,
+
+	[Oleq]		"LEqual",		"**",		evalcmp,
+	[Olgt]		"LGreater",		"**",		evalcmp,
+	[Ollt]		"LLess",		"**",		evalcmp,
+
+	[Omutex]	"Mutex",		"N1",		evalnop,
+	[Oevent]	"Event",		"N",		evalnop,
+
+	[Oif]		"If",			"{i}",		evalcond,
+	[Oelse]		"Else",			"{}",		evalcond,
+	[Owhile]	"While",		"{,i}",		evalcond,
+	[Obreak]	"Break",		"",		evalret,
+	[Oret]		"Return",		"*",		evalret,
+	[Ocall]		"Call",			"",		evalcall,
+
+	[Ostore]	"Store",		"*@",		evalstore,
+	[Oindex]	"Index",		"@i@",		evalindex,
+	[Osize]		"SizeOf",		"*",		evalsize,
+	[Oref]		"RefOf",		"@",		evaliarg0,
+	[Ocref]		"CondRefOf",		"@@",		evalcondref,
+	[Oderef]	"DerefOf",		"@",		evalderef,
+	[Ocat]		"Concatenate",		"**@",		evalcat,
+
+	[Oacq]		"Acquire",		"@2",		evalnop,
+	[Orel]		"Release",		"@",		evalnop,
+	[Ostall]	"Stall",		"i",		evalstall,
+	[Osleep]	"Sleep",		"i",		evalsleep,
+	[Oload] 	"Load", 		"*@}", 		evalload,
+	[Ounload]	"Unload",		"@",		evalnop,
+};
+
+static uchar octab1[] = {
+/* 00 */	Oconst,	Oconst,	Obad,	Obad,	Obad,	Obad,	Oalias,	Obad,
+/* 08 */	Oname,	Obad,	Obyte,	Oword,	Odword,	Ostr,	Oqword,	Obad,
+/* 10 */	Oscope,	Obuf,	Opkg,	Ovpkg,	Omet,	Obad,	Obad,	Obad,
+/* 18 */	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,
+/* 20 */	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,
+/* 28 */	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Onamec,	Onamec,
+/* 30 */	Onamec,	Onamec,	Onamec,	Onamec,	Onamec,	Onamec,	Onamec,	Onamec,
+/* 38 */	Onamec,	Onamec,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,
+/* 40 */	Obad,	Onamec,	Onamec,	Onamec,	Onamec,	Onamec,	Onamec,	Onamec,
+/* 48 */	Onamec,	Onamec,	Onamec,	Onamec,	Onamec,	Onamec,	Onamec,	Onamec,
+/* 50 */	Onamec,	Onamec,	Onamec,	Onamec,	Onamec,	Onamec,	Onamec,	Onamec,
+/* 58 */	Onamec,	Onamec,	Onamec,	Obad,	Onamec,	Obad,	Onamec,	Onamec,
+/* 60 */	Oenv,	Oenv,	Oenv,	Oenv,	Oenv,	Oenv,	Oenv,	Oenv,
+/* 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,	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,
+/* A0 */	Oif,	Oelse,	Owhile,	Onop,	Oret,	Obreak,	Obad,	Obad,
+/* A8 */	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,
+/* B0 */	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,
+/* B8 */	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,
+/* C0 */	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,
+/* C8 */	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,
+/* D0 */	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,
+/* D8 */	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,
+/* E0 */	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,
+/* E8 */	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,
+/* F0 */	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,
+/* F8 */	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Oconst,
+};
+
+static uchar octab2[] = {
+/* 00 */	Obad,	Omutex,	Oevent,	Obad,	Obad,	Obad,	Obad,	Obad,
+/* 08 */	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,
+/* 10 */	Obad,	Obad,	Ocref,	Ocfld,	Obad,	Obad,	Obad,	Obad,
+/* 18 */	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,
+/* 20 */	Oload,	Ostall,	Osleep,	Oacq,	Obad,	Obad,	Obad,	Orel,
+/* 28 */	Obad,	Obad,	Ounload,Obad,	Obad,	Obad,	Obad,	Obad,
+/* 30 */	Obad,	Odebug,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,
+/* 38 */	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,
+/* 40 */	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,
+/* 48 */	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,
+/* 50 */	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,
+/* 58 */	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,
+/* 60 */	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,
+/* 68 */	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,
+/* 70 */	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,
+/* 78 */	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,
+/* 80 */	Oreg,	Ofld,	Odev,	Ocpu,	Oprc,	Othz,	Oxfld,	Obad,
+/* 88 */	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,
+/* 90 */	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,
+/* 98 */	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,
+/* A0 */	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,
+/* A8 */	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,
+/* B0 */	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,
+/* B8 */	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,
+/* C0 */	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,
+/* C8 */	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,
+/* D0 */	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,
+/* D8 */	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,
+/* E0 */	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,
+/* E8 */	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,
+/* F0 */	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,
+/* F8 */	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,	Obad,
+};
+
+int
+amltag(void *p)
+{
+	return p ? TAG(p) : 0;
+}
+
+void*
+amlval(void *p)
+{
+	return deref(p);
+}
+
+uvlong
+amlint(void *p)
+{
+	return ival(p);
+}
+
+int
+amllen(void *p)
+{
+	while(p){
+		switch(TAG(p)){
+		case 'R':
+			p = *((Ref*)p)->ptr;
+			continue;
+		case 'n':
+		case 's':
+			return strlen((char*)p);
+		case 'p':
+			return SIZE(p)/sizeof(void*);
+		default:
+			return SIZE(p);
+		}
+	}
+	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);
+	}
+}
+
+static void*
+evalosi(void)
+{
+	static char *w[] = { 
+		"Windows 2001",
+		"Windows 2001 SP1",
+		"Windows 2001 SP2",
+		"Windows 2006",
+	};
+	char *s;
+	int i;
+
+	s = FP->env->arg[0];
+	if(s == nil || TAG(s) != 's')
+		return nil;
+	for(i = 0; i < nelem(w); i++)
+		if(strcmp(s, w[i]) == 0)
+			return mki(0xFFFFFFFF);
+	return nil;
+}
+
+void
+amlinit(void)
+{
+	Name *n;
+
+	fmtinstall('V', Vfmt);
+	fmtinstall('N', Nfmt);
+
+	n = mk('N', sizeof(Name));
+	n->up = n;
+
+	amlroot = n;
+
+	getname(amlroot, "_GPE", 1);
+	getname(amlroot, "_PR", 1);
+	getname(amlroot, "_SB", 1);
+	getname(amlroot, "_TZ", 1);
+	getname(amlroot, "_SI", 1);
+	getname(amlroot, "_GL", 1);
+
+	if(n = getname(amlroot, "_REV", 1))
+		n->v = mki(2);
+	if(n = getname(amlroot, "_OS", 1))
+		n->v = mks("Microsoft Windows");
+	if(n = getname(amlroot, "_OSI", 1)){
+		Method *m;
+
+		m = mk('m', sizeof(Method));
+		m->narg = 1;
+		m->eval = evalosi;
+		m->name = n;
+		n->v = m;
+	}
+}
+
+void
+amlexit(void)
+{
+	amlroot = nil;
+	FP = FB-1;
+	gc();
+}
+
+int
+amlload(uchar *data, int len)
+{
+	int ret;
+
+	ret = xec(data, data+len, amlroot, nil, nil);
+	amlenum(amlroot, nil, fixnames, nil);
+	return ret;
+}
+
+void*
+amlwalk(void *dot, char *name)
+{
+	return getname(dot, name, 0);
+}
+
+void
+amlenum(void *dot, char *seg, int (*proc)(void *, void *), void *arg)
+{
+	Name *n, *d;
+	int rec;
+
+	d = dot;
+	if(d == nil || TAG(d) != 'N')
+		return;
+	do {
+		rec = 1;
+		if(seg == nil || memcmp(seg, d->seg, sizeof(d->seg)) == 0)
+			rec = (*proc)(d, arg) == 0;
+		for(n = d->down; n && rec; n = n->next)
+			amlenum(n, seg, proc, arg);
+		d = d->fork;
+	} while(d);
+}
+
+int
+amleval(void *dot, char *fmt, ...)
+{
+	va_list a;
+	Method *m;
+	void **r;
+	Env *e;
+	int i;
+
+	va_start(a, fmt);
+	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;
+		case 'i':
+			e->arg[i++] = mki(va_arg(a, int));
+			break;
+		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**);
+	va_end(a);
+	if(dot = deref(dot))
+	if(TAG(dot) == 'm'){
+		m = dot;
+		if(i != m->narg)
+			return -1;
+		if(m->eval == nil)
+			return xec(m->start, m->end, forkname(m->name), e, r);
+		FP = FB;
+		FP->op = nil;
+		FP->env = e;
+		FP->narg = 0;
+		FP->dot = m->name;
+		FP->ref = FP->aux = nil;
+		dot = (*m->eval)();
+	}
+	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;
+}
diff -Nru /sys/src/libaml/amlalloc.c /sys/src/libaml/amlalloc.c
--- /sys/src/libaml/amlalloc.c	Thu Jan  1 00:00:00 1970
+++ /sys/src/libaml/amlalloc.c	Fri Nov 13 00:00:00 2015
@@ -0,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);
+}
diff -Nru /sys/src/libaml/amldelay.c /sys/src/libaml/amldelay.c
--- /sys/src/libaml/amldelay.c	Thu Jan  1 00:00:00 1970
+++ /sys/src/libaml/amldelay.c	Fri Nov 13 00:00:00 2015
@@ -0,0 +1,8 @@
+#include <u.h>
+#include <libc.h>
+#include <aml.h>
+
+void
+amldelay(int)
+{
+}
diff -Nru /sys/src/libaml/amlmapio.c /sys/src/libaml/amlmapio.c
--- /sys/src/libaml/amlmapio.c	Thu Jan  1 00:00:00 1970
+++ /sys/src/libaml/amlmapio.c	Fri Nov 13 00:00:00 2015
@@ -0,0 +1,9 @@
+#include <u.h>
+#include <libc.h>
+#include <aml.h>
+
+int
+amlmapio(Amlio*)
+{
+	return -1;
+}
diff -Nru /sys/src/libaml/amlunmapio.c /sys/src/libaml/amlunmapio.c
--- /sys/src/libaml/amlunmapio.c	Thu Jan  1 00:00:00 1970
+++ /sys/src/libaml/amlunmapio.c	Fri Nov 13 00:00:00 2015
@@ -0,0 +1,8 @@
+#include <u.h>
+#include <libc.h>
+#include <aml.h>
+
+void
+amlunmapio(Amlio*)
+{
+}
diff -Nru /sys/src/libaml/mkfile /sys/src/libaml/mkfile
--- /sys/src/libaml/mkfile	Thu Jan  1 00:00:00 1970
+++ /sys/src/libaml/mkfile	Fri Nov 13 00:00:00 2015
@@ -0,0 +1,19 @@
+</$objtype/mkfile
+
+LIB=/$objtype/lib/libaml.a
+OFILES=\
+	aml.$O\
+	amlmapio.$O\
+	amlunmapio.$O\
+	amlalloc.$O\
+	amldelay.$O\
+
+HFILES=/sys/include/aml.h
+
+UPDATE=\
+	mkfile\
+	$HFILES\
+	${OFILES:%.$O=%.c}\
+	${LIB:/$objtype/%=/386/%}\
+
+</sys/src/cmd/mksyslib
--- /n/sources/plan9/sys/src/mkfile	Fri May  9 22:24:50 2008
+++ /sys/src/mkfile	Fri Nov 13 00:00:00 2015
@@ -3,6 +3,7 @@
 LIBS=\
 	lib9p\
 	libString\
+	libaml\
 	libauth\
 	libauthsrv\
 	libavl\

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.