--- /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 +#include +#include + +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 +#include +#include + +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; iloc); i++) + gcmark(e->loc[i]); + for(i=0; iarg); 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; inarg; 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>= 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<> 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> 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 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 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; inarg; i++){ + if(i > 0) + print(", "); + print("%V", f->arg[i]); + } + print(")\n"); + if(e == f->env) + continue; + if(e = f->env){ + for(i=0; iarg); i++) + print("Arg%d=%V ", i, e->arg[i]); + print("\n"); + for(i=0; iloc); 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; inarg; 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 +#include +#include + +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 +#include +#include + +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 +#include +#include + +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 +#include +#include + +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 @@ +