diff options
author | cinap_lenrek <cinap_lenrek@gmx.de> | 2012-06-17 23:12:19 +0200 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@gmx.de> | 2012-06-17 23:12:19 +0200 |
commit | a47521a3ede91ef06bf7938722c490893d5458f6 (patch) | |
tree | 9337bcdee5c2cea704a9a28652abb5b873947c32 /sys/src/libaml | |
parent | 9cb66f310b16b51526fd3f5480b69a54589e229e (diff) |
experimental acpi support for apic irq routing
Diffstat (limited to 'sys/src/libaml')
-rw-r--r-- | sys/src/libaml/aml.c | 1818 | ||||
-rw-r--r-- | sys/src/libaml/mkfile | 15 |
2 files changed, 1833 insertions, 0 deletions
diff --git a/sys/src/libaml/aml.c b/sys/src/libaml/aml.c new file mode 100644 index 000000000..80df2b1b1 --- /dev/null +++ b/sys/src/libaml/aml.c @@ -0,0 +1,1818 @@ +#include <u.h> +#include <libc.h> +#include <aml.h> + +typedef struct Interp Interp; +typedef struct Frame Frame; +typedef struct Heap Heap; + +typedef struct Package Package; +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 + +enum { + MemSpace = 0x00, + IoSpace = 0x01, + PcicfgSpace = 0x02, + EbctlSpace = 0x03, + SmbusSpace = 0x04, + CmosSpace = 0x05, + PcibarSpace = 0x06, + IpmiSpace = 0x07, +}; + +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 Package { + int n; + void *a[]; +}; + +struct Method { + Name *name; + int narg; + void* (*eval)(void); + uchar *start; + uchar *end; +}; + +struct Region { + Name *name; + int space; + uvlong off; + uvlong len; + uchar *va; +}; + +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; + 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; + int cond; +}; + +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, + Ostr, Obyte, Oword, Odword, Oqword, Oconst, + Onamec, Oname, Oscope, + Oreg, Ofld, Oxfld, Opkg, Ovpkg, Oenv, Obuf, Omet, + Odev, Ocpu, Othz, Oprc, + Oadd, Osub, Omod, Omul, Odiv, Oshl, Oshr, Oand, Onand, Oor, + Onor, Oxor, Onot, Oinc, Odec, + 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, + Oacq, Orel, +}; + +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){ + Heap *h; + + if(p == nil) + return; + h = D2H(p); + if(h->mark) + return; + h->mark = 1; + switch(h->tag){ + case 'E': + { + int i; + Env *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': + { + Name *d, *n = p; + gcmark(n->v); + for(d = n->down; d; d = d->next) + gcmark(d); + gcmark(n->fork); + gcmark(n->up); + } + break; + case 'p': + { + int i; + Package *a = p; + for(i=0; i<a->n; i++) + gcmark(a->a[i]); + } + break; + case 'r': + gcmark(((Region*)p)->name); + break; + case 'm': + gcmark(((Method*)p)->name); + break; + case 'f': + case 'u': + { + Field *f = p; + gcmark(f->reg); + gcmark(f->index); + gcmark(f->indexv); + } + break; + } +} + +static int +gc(void){ + Heap *h, **hh; + Frame *f; + int i; + + for(h = hp; h; h = h->link) + h->mark = 0; + + 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; + 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 = 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 uvlong +ival(void *p){ + if(p) switch(TAG(p)){ + case 'i': + return *((uvlong*)p); + case 's': + return strtoull((char*)p, 0, 0); + } + return 0; +} + +static uvlong +rwreg(void *reg, int off, int len, uvlong v, int write) +{ + Region *r; + uchar *p; + int i; + + switch(TAG(reg)){ + case 'b': + p = reg; + if((off+len) > SIZE(p)) + break; + if(write){ + for(i=0; i<len; i++){ + p[off+i] = v & 0xFF; + v >>= 8; + } + } else { + for(i=0; i<len; i++) + v |= ((uvlong)p[off+i]) << i*8; + } + return v; + case 'r': + r = reg; + if((off+len) > r->len) + break; + if(amldebug){ + print("rwreg: %s %-8s [%llux+%x]/%d %llux\n", + write ? "W" : "R", + spacename[r->space], + r->off, off, len, v); + } + break; + } + + 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); + for(i=0; i<SIZE(b); i++){ + b[i] = w & 0xFF; + w >>= 8; + } + } + } 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 |= 1LL<<i; + w <<= ws; + if(wl != wd){ + m = ((1LL<<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 = 0; + for(i=0; i<SIZE(b); i++) + w |= ((uvlong)b[i]) << i*8; + 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){ + void *d; + if(s){ + int n; + if(tag == 0) + tag = TAG(s); + switch(tag){ + case 'b': + case 's': + n = SIZE(s); + if(tag == 's' && TAG(s) == 'b') + n++; + d = mk(tag, n); + memmove(d, s, n); + if(tag == 's') + ((uchar*)d)[n-1] = 0; + return d; + case 'i': + return mki(ival(s)); + } + } + 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){ + switch(TAG(p)){ + case 'R': case 'A': case 'L': + pp = ((Ref*)p)->ptr; + continue; + case 'N': + pp = &((Name*)p)->v; + if(*pp != p) + continue; + } + break; + } + break; + case 'N': + pp = &((Name*)d)->v; + } + p = *pp; + if(p && TAG(p) != 'N'){ + switch(TAG(p)){ + case 'f': + case 'u': + rwfield(p, s, 1); + return d; + } + *pp = copy(TAG(p), s); + } else + *pp = copy(0, s); + return d; +} + +static int +Nfmt(Fmt *f){ + char buf[5]; + Name *n; + int i; + + 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 c; + + p = va_arg(f->args, void*); + if(p == nil) + return fmtprint(f, "nil"); + c = TAG(p); + switch(c){ + case 'N': + { + Name *n = p; + + if(n->v != n) + return fmtprint(f, "%N=%V", n, n->v); + return fmtprint(f, "%N=*", n); + } + case 'A': case 'L': + { + Ref *r = p; + Env *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 's': + return fmtprint(f, "\"%s\"", (char*)p); + case 'i': + return fmtprint(f, "0x%llux", *((uvlong*)p)); + case 'p': + { + int i; + Package *a = p; + fmtprint(f, "Package(%d){", a->n); + for(i=0; i<a->n; i++){ + if(i > 0) + fmtprint(f, ", "); + fmtprint(f, "%V", a->a[i]); + } + fmtprint(f, "}"); + } + return 0; + case 'b': + { + int i, n; + 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': + { + Region *r = p; + return fmtprint(f, "Region(%s, 0x%llux, 0x%llux)", + spacename[r->space & 7], r->off, r->len); + } + case 'm': + { + int i; + Method *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': + { + Field *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->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 %d\t%N\t", PC, FP - FB, FP->phase, interp.cond, FP->dot); + r = nil; + c = *FP->phase++; + switch(c){ + default: + if(PC >= FP->end){ + Overrun: + print("PC overrun frame end"); + goto Out; + } + FP++; + if(FP >= FT){ + print("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){ + int s, c, new; + Name *x, *dot; + + dot = FP->dot; + new = FP->tag == 'N'; + s = !new; + c = 1; + PC = FP->start; + if(*PC == '\\'){ + PC++; + dot = rootname(dot); + s = 0; + } + while(*PC == '^'){ + PC++; + dot = dot->up; + s = 0; + } + if(*PC == '.'){ + PC++; + c = 2; + } else if(*PC == '/'){ + PC++; + c = *PC++; + } else if(*PC == 0){ + PC++; + c = 0; + } else if(s){ + for(;;){ + if(x = getseg(dot, PC, 0)) + break; + if(dot == dot->up) + break; + dot = dot->up; + } + PC += 4; + return x; + } + while(c > 0){ + dot = getseg(dot, PC, new); + PC += 4; + c--; + } + return dot; +} + +static void* +evaliarg0(){ + 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){ + Package *p; + int n; + + if(p = FP->ref){ + n = sizeof(Package)+p->n*sizeof(void*); + if(n < SIZE(p)) + p->a[p->n++] = FP->arg[0]; + }else { + n = sizeof(Package)+ival(FP->arg[0])*sizeof(void*); + p = mk('p', n); + 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* +evalmet(void){ + Name *n; + if(n = FP->arg[0]){ + Method *m; + 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; + if(n = FP->arg[0]){ + Region *r; + 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; + 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("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: + interp.cond = ival(FP->arg[0]) != 0; + if(!interp.cond) + PC = FP->end; + break; + case Oelse: + if(interp.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; + interp.cond = ival(FP->arg[0]) != 0; + if(!interp.cond){ + PC = FP->end; + break; + } + return nil; + } + FP->op = nil; + return nil; +} + +static void* +evalcmp(void){ + void *a, *b; + int c; + + if((a = FP->arg[0]) == nil) + a = mki(0); + if((b = FP->arg[1]) == nil) + b = mki(0); + + switch(TAG(a)){ + default: + return nil; + case 'i': + c = ival(a) - ival(b); + break; + case 's': + if(TAG(b) != 's') + b = copy('s', b); + c = strcmp((char*)a, (char*)b); + break; + case 'b': + if(TAG(b) != 'b') + b = copy('b', 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){ + 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* +evalindex(void){ + Field *f; + void *p; + Ref *r; + int x; + + x = ival(FP->arg[1]); + if(p = 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 >= ((Package*)p)->n) + break; + r = mk('R', sizeof(Ref)); + r->ref = p; + r->ptr = &((Package*)p)->a[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') + p = getname(FP->dot, (char*)p, 0); + p = deref(p); + } + return p; +} + +static void* +evalarith(void){ + void *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 Omod: + { + uvlong d; + d = ival(FP->arg[1]); + r = mki(ival(FP->arg[0]) % d); + } + break; + case Omul: + r = mki(ival(FP->arg[0]) * ival(FP->arg[1])); + break; + case Odiv: + { + uvlong v, d; + v = ival(FP->arg[0]); + d = ival(FP->arg[1]); + r = mki(v / d); + if(FP->arg[2]) + store(mki(v % d), FP->arg[2]); + 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 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 Op optab[] = { + [Obad] "", "", evalbad, + [Onop] "Noop", "", 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, + + [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, + + [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, + + [Oacq] "Acquire", "@2", evalnop, + [Orel] "Release", "@", evalnop, +}; + +static uchar octab1[] = { +/* 00 */ Oconst, Oconst, Obad, Obad, Obad, Obad, Obad, 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, Obad, Osub, Oinc, Odec, Omul, +/* 78 */ Odiv, Oshl, Oshr, Oand, Onand, Oor, Onor, Oxor, +/* 80 */ Onot, Obad, Obad, 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 */ Obad, Obad, Obad, Oacq, Obad, Obad, Obad, Orel, +/* 28 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad, +/* 30 */ Obad, Obad, 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){ + p = deref(p); + if(p && TAG(p) == 'p') + p = ((Package*)p)->a; + return 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 's': + return strlen((char*)p); + case 'p': + return ((Package*)p)->n; + default: + return SIZE(p); + } + } + return 0; +} + +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); + + 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 = evalnop; + m->name = n; + n->v = m; + } +} + +void +amlexit(void){ + amlroot = nil; + FP = FB-1; + gc(); +} + +int +amlload(uchar *data, int len){ + return xec(data, data+len, amlroot, nil, nil); +} + +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 = *fmt ? mk('E', sizeof(Env)) : nil; + for(i=0;*fmt;fmt++){ + switch(*fmt){ + 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; + } + } + r = va_arg(a, void**); + va_end(a); + if(dot = deref(dot)) switch(TAG(dot)){ + case 'm': + m = dot; + if(i != m->narg) + return -1; + return xec(m->start, m->end, forkname(m->name), e, r); + } + if(r) *r = dot; + return 0; +} diff --git a/sys/src/libaml/mkfile b/sys/src/libaml/mkfile new file mode 100644 index 000000000..2195e6006 --- /dev/null +++ b/sys/src/libaml/mkfile @@ -0,0 +1,15 @@ +</$objtype/mkfile + +LIB=/$objtype/lib/libaml.a +OFILES=\ + aml.$O\ + +HFILES=/sys/include/aml.h + +UPDATE=\ + mkfile\ + $HFILES\ + ${OFILES:%.$O=%.c}\ + ${LIB:/$objtype/%=/386/%}\ + +</sys/src/cmd/mksyslib |