ref: d5305dc19943b98ce9e5a98110389d6800f56318
dir: /sys/src/libaml/aml.c/
#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, 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, 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* evalalias(void){ Name *n; if(n = FP->arg[1]) n->v = deref(FP->arg[0]); 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, [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, [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, 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, 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, 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){ 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; }