plan9fox/sys/src/libaml/aml.c
cinap_lenrek 2731ae50d3 libaml: resolve refs in ObjectType instruction
The standard states in section 19.5.93:

.... Notice that if this operation is performed
on an obeject reference such as one produced by
the Alias, Index, or RefOf statements, the obect
type of the base object is returned.
2021-10-17 19:52:28 +00:00

2466 lines
42 KiB
C

#include <u.h>
#include <libc.h>
#include <aml.h>
typedef struct Interp Interp;
typedef struct Frame Frame;
typedef struct Heap Heap;
typedef struct Method Method;
typedef struct Region Region;
typedef struct Field Field;
typedef struct Name Name;
typedef struct Ref Ref;
typedef struct Env Env;
typedef struct Op Op;
struct Heap {
Heap *link;
int 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 or data Field */
void *bank; /* bank value */
Field *index; /* bank or index Field */
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;
Frame *fb;
};
static Interp interp;
static Frame stack[32];
#define PC interp.pc
#define FP interp.fp
#define FB interp.fb
#define F0 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, Obfld, 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, Omatch, Omutex, Oevent,
Ocfld, Ocfld0, Ocfld1, Ocfld2, Ocfld4, Ocfld8,
Oif, Oelse, Owhile, Obreak, Oret, Ocall,
Ostore, Oderef, Ootype, Osize, Oref, Ocref, Ocat,
Oacq, Osignal, Orel, Ostall, Osleep, Oload, Ounload,
Otodec, Otohex, Otoint, Otostr,
};
static Op optab[];
static uchar octab1[];
static uchar octab2[];
static Name*
rootname(Name *dot)
{
while(dot != dot->up)
dot = dot->up;
return dot;
}
static void
gcmark(void *p)
{
int i;
Env *e;
Field *f;
Heap *h;
Name *n, *d;
if(p == nil)
return;
h = D2H(p);
if(h->mark & 1)
return;
h->mark |= 1;
switch(h->tag){
case 'E':
e = p;
for(i=0; i<nelem(e->loc); i++)
gcmark(e->loc[i]);
for(i=0; i<nelem(e->arg); i++)
gcmark(e->arg[i]);
break;
case 'R':
case 'A':
case 'L':
gcmark(((Ref*)p)->ref);
break;
case 'N':
n = p;
gcmark(n->v);
for(d = n->down; d; d = d->next)
gcmark(d);
gcmark(n->fork);
gcmark(n->up);
break;
case 'p':
for(i=0; i<(SIZE(p)/sizeof(void*)); i++)
gcmark(((void**)p)[i]);
break;
case 'r':
gcmark(((Region*)p)->name);
break;
case 'm':
gcmark(((Method*)p)->name);
break;
case 'f':
case 'u':
f = p;
gcmark(f->reg);
gcmark(f->bank);
gcmark(f->index);
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 >= F0; f--){
for(i=0; i<f->narg; i++)
gcmark(f->arg[i]);
gcmark(f->env);
gcmark(f->dot);
gcmark(f->ref);
}
gcmark(amlroot);
i = 0;
hh = &hp;
while(h = *hh){
if(h->mark){
hh = &h->link;
continue;
}
*hh = h->link;
if(h->tag == 'r'){
Region *r = (void*)H2D(h);
if(r->mapped > 0){
if(amldebug)
print("\namlunmapio(%N): %-8s %llux - %llux\n",
(Name*)r->name, spacename[r->space],
r->off, r->off + r->len);
amlunmapio(r);
}
r->mapped = 0;
r->write = nil;
r->read = nil;
r->aux = nil;
r->va = nil;
}
memset(h, ~0, sizeof(Heap)+h->size);
amlfree(h);
i++;
}
return i;
}
static void*
mk(int tag, int size)
{
Heap *h;
int a;
a = sizeof(Heap) + size;
assert(a >= sizeof(Heap));
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 & amlintmask;
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;
if(dot == nil)
return nil;
s = !new;
if(*path == '\\'){
path++;
dot = rootname(dot);
s = 0;
}
while(*path == '^'){
path++;
dot = dot->up;
s = 0;
}
do {
for(i=0; i<4; i++){
if(*path == 0 || *path == '.')
break;
seg[i] = *path++;
}
if(i == 0)
break;
while(i < 4)
seg[i++] = '_';
if(s && *path == 0){
for(;;){
if(x = getseg(dot, seg, 0))
break;
if(dot == dot->up)
break;
dot = dot->up;
}
return x;
}
s = 0;
dot = getseg(dot, seg, new);
} while(*path++ == '.');
return dot;
}
static int
fixnames(void *dot, void *arg)
{
void **r, *v;
int i;
if(arg == nil)
r = &((Name*)dot)->v;
else
r = arg;
v = *r;
if(v == nil || v == dot)
return 0;
if(TAG(v) == 'p'){
r = (void**)v;
for(i=0; i<(SIZE(r)/sizeof(void*)); i++)
fixnames(dot, r+i);
return 0;
}
if(TAG(v) == 'n' && (v = getname(dot, v, 0)) != nil)
*r = v;
return 0;
}
static uvlong
getle(uchar *p, int len)
{
uvlong v;
int i;
v = 0ULL;
for(i=0; i<len; i++)
v |= ((uvlong)p[i]) << i*8;
return v;
}
static void
putle(uchar *p, int len, uvlong v)
{
int i;
for(i=0; i<len; i++){
p[i] = v;
v >>= 8;
}
}
static uvlong
rwreg(void *reg, int off, int len, uvlong v, int write)
{
Interp save;
uchar buf[8], *p;
Region *r;
save = interp; /* save, in case we reenter the interpreter */
FB = FP+1; /* allocate new base */
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);
goto Out;
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);
}
goto Out;
}
v = -1;
Out:
interp = save; /* restore */
return v;
}
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);
static uvlong
rwfieldunit(Field *f, int off, int len, uvlong v, int write)
{
if(f->index){
if(TAG(f->reg) == 'f'){
/* set index field */
rwfield(f->index, mki(off), 1);
/* set or get data field */
if(write){
void *b = mk('b', len);
putle(b, len, v);
rwfield(f->reg, b, 1);
}else{
v = ival(rwfield(f->reg, nil, 0));
}
return v;
}
/* set bank field */
rwfield(f->index, f->bank, 1);
}
return rwreg(f->reg, off, len, v, write);
}
static void*
rwfield(Field *f, void *v, int write)
{
int boff, blen, wo, ws, wl, wa, wd, i;
uvlong w, m;
uchar *b;
if(f == nil)
return nil;
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);
/*
* don't free b while in rwfieldunit()/rwreg(),
* gc can't find this temporary object referenced.
*/
amltake(b);
wa = fieldalign(f->flags);
wd = wa*8;
boff = 0;
while((wl = (blen-boff)) > 0){
wo = (f->bitoff+boff) / wd;
ws = (f->bitoff+boff) % wd;
if(wl > (wd - ws))
wl = wd - ws;
if(write){
w = 0;
for(i = 0; i < wl; i++, boff++)
if(b[boff/8] & (1<<(boff%8)))
w |= 1ULL<<i;
w <<= ws;
if(wl != wd){
m = ((1ULL<<wl)-1) << ws;
w |= rwfieldunit(f, wo*wa, wa, 0, 0) & ~m;
}
rwfieldunit(f, wo*wa, wa, w, 1);
} else {
w = rwfieldunit(f, wo*wa, wa, 0, 0) >> ws;
for(i = 0; i < wl; i++, boff++){
b[boff/8] |= (w&1)<<(boff%8);
w >>= 1;
}
}
}
amldrop(b);
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 char*
todecstr(uchar *buf, int len, int sep)
{
char *r, *d;
int i, v;
r = d = mk('s', len*4 + 1);
if(len == 0){
*d = 0;
return r;
}
if(sep == 0)
sep = ' ';
for(i=0; i<len; i++){
v = buf[i];
if((*d = '0' + ((v/100) % 10)) != '0')
d++;
if((*d = '0' + ((v/10) % 10)) != '0')
d++;
*d++ = '0' + (v % 10);
*d++ = sep;
}
d[-1] = 0;
return r;
}
static char hex[] = "0123456789ABCDEF";
static char*
tohexstr(uchar *buf, int len, int sep)
{
char *r, *d;
int i;
r = d = mk('s', len*3 + 1);
if(len == 0){
*d = 0;
return r;
}
if(sep == 0)
sep = ' ';
for(i=0; i<len; i++){
*d++ = hex[buf[i] >> 4];
*d++ = hex[buf[i] & 0xF];
*d++ = sep;
}
d[-1] = 0;
return r;
}
static void*
copy(int tag, void *s)
{
uvlong v;
void *d;
int 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')
return tohexstr(s, n, ' ');
/* 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%zd=%V", r->ptr - e->arg, *r->ptr);
if(c == 'L')
return fmtprint(f, "Local%zd=%V", r->ptr - e->loc, *r->ptr);
case 'n':
return fmtprint(f, "%s", (char*)p);
case 's':
return fmtprint(f, "\"%s\"", (char*)p);
case 'i':
return fmtprint(f, "%#llux", *((uvlong*)p));
case 'p':
n = SIZE(p)/sizeof(void*);
fmtprint(f, "Package(%d){", n);
for(i=0; i<n; i++){
if(i > 0)
fmtprint(f, ", ");
fmtprint(f, "%V", ((void**)p)[i]);
}
fmtprint(f, "}");
return 0;
case 'b':
n = SIZE(p);
fmtprint(f, "Buffer(%d){", n);
for(i=0; i<n; i++){
if(i > 0)
fmtprint(f, ", ");
fmtprint(f, "%.2uX", ((uchar*)p)[i]);
}
fmtprint(f, "}");
return 0;
case 'r':
g = p;
return fmtprint(f, "Region(%s, %#llux, %#llux)",
spacename[g->space & 7], g->off, g->len);
case 'm':
m = p;
fmtprint(f, "%N(", m->name);
for(i=0; i < m->narg; i++){
if(i > 0)
fmtprint(f, ", ");
fmtprint(f, "Arg%d", i);
}
fmtprint(f, ")");
return 0;
case 'u':
fmtprint(f, "Buffer");
/* no break */
case 'f':
l = p;
if(l->index){
if(TAG(l->reg) == 'f')
return fmtprint(f, "IndexField(%x, %x, %x) @ %V[%V]",
l->flags, l->bitoff, l->bitlen, l->reg, l->index);
else
return fmtprint(f, "BankField(%x, %x, %x, %V=%V) @ %V",
l->flags, l->bitoff, l->bitlen, l->index, l->bank, l->reg);
}
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.%.2zx: %-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;
if(FB < F0 || FB >= FT)
goto Out;
FP = FB;
FP->tag = 0;
FP->cond = 0;
FP->narg = 0;
FP->phase = "}";
FP->start = PC;
FP->end = end;
FP->aux = end;
FP->ref = nil;
FP->dot = dot;
FP->env = env;
FP->op = nil;
for(;;){
if((++loop & 127) == 0)
gc();
if(amldebug)
print("\n%.8p.%.2zx %-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(~0ULL);
}
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, n;
Field *f, *index;
void *reg, *bank;
Name *d;
uchar *p;
bank = nil;
index = nil;
bitoff = 0;
switch(FP->op - optab){
default:
goto Out;
case Ofld:
if((reg = deref(FP->arg[0])) == nil || TAG(reg) != 'r')
goto Out;
flags = ival(FP->arg[1]);
break;
case Oxfld:
if((index = deref(FP->arg[0])) == nil || TAG(index) != 'f')
goto Out;
if((reg = deref(FP->arg[1])) == nil || TAG(reg) != 'f') /* data field */
goto Out;
flags = ival(FP->arg[2]);
break;
case Obfld:
if((reg = deref(FP->arg[0])) == nil || TAG(reg) != 'r')
goto Out;
if((index = deref(FP->arg[1])) == nil || TAG(index) != 'f')
goto Out;
bank = FP->arg[2];
flags = ival(FP->arg[3]);
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;
f->bitoff = bitoff;
f->reg = reg;
f->bank = bank;
f->index = index;
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 vlong
cmp1(void *a, void *b)
{
vlong c;
int tag;
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(b == nil || TAG(b) != tag)
return -1; /* botch */
switch(tag){
default:
return -1; /* botch */
case 's':
c = strcmp((char*)a, (char*)b);
break;
case 'b':
c = SIZE(a) - SIZE(b);
if(c == 0)
c = memcmp(a, b, SIZE(a));
break;
}
}
return c;
}
static void*
evalcmp(void)
{
vlong c = cmp1(FP->arg[0], FP->arg[1]);
switch(FP->op - optab){
case Oleq:
if(c == 0) return mki(1);
break;
case Olgt:
if(c > 0) return mki(1);
break;
case Ollt:
if(c < 0) return mki(1);
break;
}
return nil;
}
static void*
evalcall(void)
{
Method *m;
Env *e;
int i;
if(FP->aux){
if(PC >= FP->end){
PC = FP->aux;
FP->end = PC;
}
return nil;
}
m = FP->ref;
e = mk('E', sizeof(Env));
for(i=0; i<FP->narg; i++)
e->arg[i] = deref(FP->arg[i]);
FP->env = e;
FP->narg = 0;
FP->dot = m->name;
if(m->eval != nil){
FP->op = nil;
FP->end = PC;
return (*m->eval)();
}
FP->dot = forkname(FP->dot);
FP->aux = PC;
FP->start = m->start;
FP->end = m->end;
PC = FP->start;
return nil;
}
static void*
evalret(void)
{
void *r = FP->arg[0];
int brk = (FP->op - optab) != Oret;
while(--FP >= FB){
switch(FP->op - optab){
case Owhile:
if(!brk)
continue;
PC = FP->end;
return nil;
case Ocall:
PC = FP->aux;
return r;
}
}
FP = FB;
PC = FB->end;
return r;
}
static void*
evalenv(void)
{
Ref *r;
Env *e;
int c;
if((e = FP->env) == nil)
return nil;
c = FP->start[0];
if(c >= 0x60 && c <= 0x67){
r = mk('L', sizeof(Ref));
r->ptr = &e->loc[c - 0x60];
} else if(c >= 0x68 && c <= 0x6E){
r = mk('A', sizeof(Ref));
r->ptr = &e->arg[c - 0x68];
} else
return nil;
r->ref = e;
return r;
}
static void*
evalstore(void)
{
return store(FP->arg[0], FP->arg[1]);
}
static void*
evalcat(void)
{
void *r, *a, *b;
int tag, n, m;
a = FP->arg[0];
b = FP->arg[1];
if(a == nil || TAG(a) == 'i')
a = copy('b', a); /* Concat(Int, ???) -> Buf */
tag = TAG(a);
if(b == nil || TAG(b) != tag)
b = copy(tag, b);
if(TAG(b) != tag)
return nil; /* botch */
switch(tag){
default:
return nil; /* botch */
case 'b':
n = SIZE(a);
m = SIZE(b);
r = mk('b', n + m);
memmove(r, a, n);
memmove((uchar*)r + n, b, m);
break;
case 's':
n = strlen((char*)a);
m = strlen((char*)b);
r = mk('s', n + m + 1);
memmove(r, a, n);
memmove((char*)r + n, b, m);
((char*)r)[n+m] = 0;
break;
}
store(r, FP->arg[2]);
return r;
}
static void*
evalindex(void)
{
Field *f;
void *p;
Ref *r;
uvlong 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 >= 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 >= (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 int
match1(int op, void *a, void *b)
{
vlong c = cmp1(a, b);
switch(op){
case 0: return 1;
case 1: return c == 0;
case 2: return c <= 0;
case 3: return c < 0;
case 4: return c >= 0;
case 5: return c > 0;
}
return 0;
}
static void*
evalmatch(void)
{
void **p = FP->arg[0];
if(p != nil && TAG(p) == 'p'){
uvlong i, n = SIZE(p)/sizeof(void*);
int o1 = ival(FP->arg[1]), o2 = ival(FP->arg[3]);
for(i=ival(FP->arg[5]); i<n; i++){
void *a = deref(p[i]);
if(match1(o1, a, FP->arg[2]) && match1(o2, a, FP->arg[4]))
return mki(i);
}
}
return mki(~0ULL);
}
static void*
evalcondref(void)
{
void *s;
if((s = FP->arg[0]) == nil)
return nil;
store(s, FP->arg[1]);
return mki(1);
}
static void*
evalotype(void)
{
void *r;
int t;
t = 0; /* Uninitialized */
r = FP->arg[0];
while(r != nil){
switch(TAG(r)){
case 'R': case 'A': case 'L': /* Ref */
r = *((Ref*)r)->ptr;
continue;
case 'N': /* Name */
r = ((Name*)r)->v;
continue;
case 'i': t = 1; break; /* Integer */
case 's': t = 2; break; /* String */
case 'b': t = 3; break; /* Buffer */
case 'p': t = 4; break; /* Package */
case 'f': t = 5; break; /* FieldUnit */
case 'm': t = 8; break; /* Method */
case 'r': t = 10; break; /* OperationRegion */
case 'u': t = 14; break; /* BufferField */
}
break;
}
return mki(t);
}
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 void*
evalconv(void)
{
void *r, *a;
r = nil;
a = FP->arg[0];
switch(FP->op - optab){
case Otodec:
if(a == nil)
break;
if(TAG(a) == 's'){
r = a;
break;
}
if(TAG(a) == 'b'){
r = todecstr(a, SIZE(a), ',');
break;
}
break;
case Otohex:
if(a == nil)
break;
if(TAG(a) == 's'){
r = a;
break;
}
if(TAG(a) == 'b'){
r = tohexstr(a, SIZE(a), ',');
break;
}
break;
case Otoint:
if(a != nil && TAG(a) == 's')
r = mki(strtoull((char*)a, 0, 0));
else
r = mki(ival(a));
break;
}
store(r, FP->arg[1]);
return r;
}
static void*
evaltostr(void)
{
char *buf, *r, *e;
int len;
buf = FP->arg[0];
if(buf == nil || (TAG(buf) != 'b' && TAG(buf) != 's'))
buf = copy('b', buf);
len = ival(FP->arg[1]);
if(~len == 0 || len > SIZE(buf))
len = SIZE(buf);
if(len > 0 && (e = memchr(buf, 0, len)) != nil)
len = e - buf;
r = mk('s', len+1);
r[len] = '\0';
memmove(r, buf, len);
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,
[Obfld] "BankField", "{nni1", 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,
[Omatch] "Match", "*1*1*i", evalmatch,
[Ootype] "ObjectType", "@", evalotype,
[Osize] "SizeOf", "*", evalsize,
[Oref] "RefOf", "@", evaliarg0,
[Ocref] "CondRefOf", "@@", evalcondref,
[Oderef] "DerefOf", "@", evalderef,
[Ocat] "Concatenate", "**@", evalcat,
[Oacq] "Acquire", "@2", evalnop,
[Osignal] "Signal", "@", evalnop,
[Orel] "Release", "@", evalnop,
[Ostall] "Stall", "i", evalstall,
[Osleep] "Sleep", "i", evalsleep,
[Oload] "Load", "*@}", evalload,
[Ounload] "Unload", "@", evalnop,
[Otodec] "ToDecimalString", "*@", evalconv,
[Otohex] "ToHexString", "*@", evalconv,
[Otoint] "ToInteger", "*@", evalconv,
[Otostr] "ToString", "*i@", evaltostr,
};
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, Omatch, Ocfld4, Ocfld2, Ocfld1, Ocfld0, Ootype, Ocfld8,
/* 90 */ Oland, Olor, Olnot, Oleq, Olgt, Ollt, Obad, Otodec,
/* 98 */ Otohex, Otoint, Obad, Obad, Otostr, 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, Osignal,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, Obfld,
/* 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;
FB = F0;
FP = F0-1;
fmtinstall('V', Vfmt);
fmtinstall('N', Nfmt);
if(!amlintmask)
amlintmask = ~0ULL;
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;
FB = F0;
FP = F0-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);
if(FB < F0 || FB >= FT)
return -1;
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;
}