Files
jehanne/sys/src/lib/aml/aml.c
Giacomo Tesio c7d0f621c9 Clarify Forsyth's and 9front's copyrights
I'm very grateful to Charles Forsyth for creating most of Jehanne's kernel
and to 9front's guys for all the code and ideas they freely share.

Here I make their copyrights explicit as they had been erroneusly omitted
or messed up before. Sorry.
2018-01-05 02:30:45 +01:00

2318 lines
40 KiB
C

/* Copyright (c) 20XX 9front
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <u.h>
#include <lib9.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;
uint8_t 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);
uint8_t *start;
uint8_t *end;
};
struct Region {
Amlio;
char mapped;
};
struct Field {
void *reg; /* Buffer or Region */
Field *index;
void *indexv;
int flags;
int bitoff;
int bitlen;
};
struct Name {
void *v;
Name *up;
Name *next;
Name *fork;
Name *down;
char seg[4];
};
struct Ref {
void *ref;
void **ptr;
};
struct Env {
void *loc[8];
void *arg[8];
};
struct Op {
char *name;
char *sequence;
void* (*eval)(void);
};
struct Frame {
int tag;
int cond;
char *phase;
uint8_t *start;
uint8_t *end;
Op *op;
Env *env;
Name *dot;
void *ref;
void *aux;
int narg;
void *arg[8];
};
struct Interp {
uint8_t *pc;
Frame *fp;
};
static Interp interp;
static Frame stack[32];
#define PC interp.pc
#define FP interp.fp
#define FB stack
#define FT &stack[nelem(stack)]
static Heap *hp;
enum {
Obad, Onop, Odebug,
Ostr, Obyte, Oword, Odword, Oqword, Oconst,
Onamec, Oname, Oscope, Oalias,
Oreg, Ofld, Oxfld, 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, Osize, Oref, Ocref, Ocat,
Oacq, Orel, Ostall, Osleep, Oload, Ounload,
Otoint,
};
static Op optab[];
static uint8_t octab1[];
static uint8_t octab2[];
static Name*
rootname(Name *dot)
{
while(dot != dot->up)
dot = dot->up;
return dot;
}
static void
gcmark(void *p)
{
int i;
Env *e;
Field *f;
Heap *h;
Name *n, *d;
if(p == nil)
return;
h = D2H(p);
if(h->mark & 1)
return;
h->mark |= 1;
switch(h->tag){
case 'E':
e = p;
for(i=0; i<nelem(e->loc); i++)
gcmark(e->loc[i]);
for(i=0; i<nelem(e->arg); i++)
gcmark(e->arg[i]);
break;
case 'R':
case 'A':
case 'L':
gcmark(((Ref*)p)->ref);
break;
case 'N':
n = p;
gcmark(n->v);
for(d = n->down; d; d = d->next)
gcmark(d);
gcmark(n->fork);
gcmark(n->up);
break;
case 'p':
for(i=0; i<(SIZE(p)/sizeof(void*)); i++)
gcmark(((void**)p)[i]);
break;
case 'r':
gcmark(((Region*)p)->name);
break;
case 'm':
gcmark(((Method*)p)->name);
break;
case 'f':
case 'u':
f = p;
gcmark(f->reg);
gcmark(f->index);
gcmark(f->indexv);
break;
}
}
static int
gc(void)
{
int i;
Heap *h, **hh;
Frame *f;
for(h = hp; h; h = h->link)
h->mark &= ~1;
for(h = hp; h; h = h->link)
if(h->mark & 2)
gcmark(H2D(h));
for(f = FP; f >= FB; f--){
for(i=0; i<f->narg; i++)
gcmark(f->arg[i]);
gcmark(f->env);
gcmark(f->dot);
gcmark(f->ref);
}
gcmark(amlroot);
i = 0;
hh = &hp;
while(h = *hh){
if(h->mark){
hh = &h->link;
continue;
}
*hh = h->link;
if(h->tag == 'r'){
Region *r = (void*)H2D(h);
if(r->mapped > 0){
if(amldebug)
print("\namlunmapio(%N): %-8s %llux - %llux\n",
(Name*)r->name, spacename[r->space],
r->off, r->off + r->len);
amlunmapio(r);
}
r->mapped = 0;
r->write = nil;
r->read = nil;
r->aux = nil;
r->va = nil;
}
memset(h, ~0, sizeof(Heap)+h->size);
amlfree(h);
i++;
}
return i;
}
static void*
mk(int tag, int size)
{
Heap *h;
int a;
a = sizeof(Heap) + size;
assert(a >= 0);
h = amlalloc(a);
h->size = size;
h->tag = tag;
h->link = hp;
hp = h;
return h+1;
}
static uint64_t*
mki(uint64_t i)
{
uint64_t *v;
v = mk('i', sizeof(uint64_t));
*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(uint8_t *p, uint8_t *e, uint8_t **np)
{
uint32_t n;
uint8_t 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 uint64_t
getle(uint8_t *p, int len)
{
uint64_t v;
int i;
v = 0ULL;
for(i=0; i<len; i++)
v |= ((uint64_t)p[i]) << i*8;
return v;
}
static void
putle(uint8_t *p, int len, uint64_t v)
{
int i;
for(i=0; i<len; i++){
p[i] = v;
v >>= 8;
}
}
static uint64_t
rwreg(void *reg, int off, int len, uint64_t v, int write)
{
uint8_t buf[8], *p;
Region *r;
switch(TAG(reg)){
case 'b':
p = reg;
if((off+len) > SIZE(p))
break;
p += off;
if(write)
putle(p, len, v);
else
v = getle(p, len);
return v;
case 'r':
r = reg;
if((off+len) > r->len)
break;
if(r->mapped == 0){
if(amldebug)
print("\namlmapio(%N): %-8s %llux - %llux\n",
(Name*)r->name, spacename[r->space],
r->off, r->off + r->len);
r->mapped = 1;
if(amlmapio(r) < 0)
r->mapped = -1;
}
if(r->mapped <= 0)
break;
if(r->va != nil)
p = r->va + off;
else {
if(len > sizeof(buf))
break;
p = buf;
}
if(write){
if(amldebug)
print("\nrwreg(%N): %-8s [%llux+%x]/%d <- %llux\n",
(Name*)r->name, spacename[r->space],
r->off, off, len, v);
putle(p, len, v);
if(r->write != nil){
if((*r->write)(r, p, len, off) != len)
break;
} else if(p == buf)
break;
} else {
if(r->read != nil){
if((*r->read)(r, p, len, off) != len)
break;
} else if(p == buf)
break;
v = getle(p, len);
if(amldebug)
print("\nrwreg(%N): %-8s [%llux+%x]/%d -> %llux\n",
(Name*)r->name, spacename[r->space],
r->off, off, len, v);
}
return v;
}
return ~0;
}
static uint64_t
ival(void *p)
{
int n;
if(p != nil){
switch(TAG(p)){
case 'i':
return *((uint64_t*)p);
case 's':
if(*((char*)p) == 0)
break;
return strtoull((char*)p, 0, 16);
case 'b':
n = SIZE(p);
if(n > 0){
if(n > 8) n = 8;
return rwreg(p, 0, n, 0, 0);
}
}
}
return 0;
}
static void *deref(void *p);
static void *store(void *s, void *d);
static int
fieldalign(int flags)
{
switch(flags & AccMask){
default:
case AnyAcc:
case ByteAcc:
case BufferAcc:
return 1;
case WordAcc:
return 2;
case DWordAcc:
return 4;
case QWordAcc:
return 8;
}
}
static void*
rwfield(Field *f, void *v, int write)
{
int boff, blen, wo, ws, wl, wa, wd, i;
uint64_t w, m;
void *reg;
uint8_t *b;
if(f == nil || (reg = deref(f->reg)) == nil)
return nil;
if(f->index)
store(f->indexv, f->index);
blen = f->bitlen;
if(write){
if(v && TAG(v) == 'b'){
b = v;
if(SIZE(b)*8 < blen)
blen = SIZE(b)*8;
} else {
w = ival(v);
b = mk('b', (blen+7)/8);
putle(b, SIZE(b), w);
}
} else
b = mk('b', (blen+7)/8);
wa = fieldalign(f->flags);
wd = wa*8;
boff = 0;
while((wl = (blen-boff)) > 0){
wo = (f->bitoff+boff) / wd;
ws = (f->bitoff+boff) % wd;
if(wl > (wd - ws))
wl = wd - ws;
if(write){
w = 0;
for(i = 0; i < wl; i++, boff++)
if(b[boff/8] & (1<<(boff%8)))
w |= 1ULL<<i;
w <<= ws;
if(wl != wd){
m = ((1ULL<<wl)-1) << ws;
w |= rwreg(reg, wo*wa, wa, 0, 0) & ~m;
}
rwreg(reg, wo*wa, wa, w, 1);
} else {
w = rwreg(reg, wo*wa, wa, 0, 0) >> ws;
for(i = 0; i < wl; i++, boff++){
b[boff/8] |= (w&1)<<(boff%8);
w >>= 1;
}
}
}
if(write)
return nil;
if(blen > 64)
return b;
w = getle(b, SIZE(b));
return mki(w);
}
static void*
deref(void *p)
{
if(p) switch(TAG(p)){
case 'N':
return ((Name*)p)->v;
case 'R': case 'A': case 'L':
return *((Ref*)p)->ptr;
case 'f': case 'u':
return rwfield(p, nil, 0);
}
return p;
}
static void*
copy(int tag, void *s)
{
static char hex[] = "0123456789ABCDEF";
uint64_t v;
void *d;
int i, n;
if(tag == 0){
if(s == nil)
return nil;
tag = TAG(s);
}
if(s == nil || TAG(s) == 'i'){
n = 4;
v = ival(s);
if(v > 0xFFFFFFFFULL)
n <<= 1;
switch(tag){
case 'b':
d = mk(tag, n);
rwreg(d, 0, n, v, 1);
return d;
case 's':
n <<= 1;
d = mk(tag, n+1);
((char*)d)[n] = 0;
while(n > 0){
((char*)d)[--n] = hex[v & 0xF];
v >>= 4;
}
return d;
case 'i':
if(v == 0ULL)
return nil;
return mki(v);
}
} else {
n = SIZE(s);
switch(tag){
case 's':
if(TAG(s) == 'b'){
d = mk(tag, n*3 + 1);
for(i=0; i<n; i++){
((char*)d)[i*3 + 0] = hex[((uint8_t*)s)[i] >> 4];
((char*)d)[i*3 + 1] = hex[((uint8_t*)s)[i] & 0xF];
((char*)d)[i*3 + 2] = ' ';
}
((char*)d)[n*3] = 0;
return d;
}
/* no break */
case 'b':
if(TAG(s) == 's'){
n = strlen(s);
/* zero length string is converted to zero length buffer */
if(n > 0) n++;
}
d = mk(tag, n);
memmove(d, s, n);
return d;
}
}
return s;
}
static void*
store(void *s, void *d)
{
void *p, **pp;
if(d == nil)
return nil;
switch(TAG(d)){
default:
return nil;
case 'A':
s = deref(s);
/* no break */
case 'R': case 'L':
pp = ((Ref*)d)->ptr;
while((p = *pp) != nil){
switch(TAG(p)){
case 'R': case 'A': case 'L':
pp = ((Ref*)p)->ptr;
break;
case 'N':
pp = &((Name*)p)->v;
break;
}
if(*pp == p)
break;
}
break;
case 'N':
pp = &((Name*)d)->v;
break;
}
p = *pp;
if(p != nil && TAG(p) != 'N'){
switch(TAG(p)){
case 'f':
case 'u':
rwfield(p, s, 1);
return d;
}
if(TAG(d) != 'A' && TAG(d) != 'L'){
*pp = copy(TAG(p), s);
return d;
}
}
*pp = copy(0, s);
return d;
}
static int
Nfmt(Fmt *f)
{
char buf[5];
int i;
Name *n;
n = va_arg(f->args, Name*);
if(n == nil)
return fmtprint(f, "?NIL");
if(n == n->up)
return fmtprint(f, "\\");
strncpy(buf, n->seg, 4);
buf[4] = 0;
for(i=3; i>0; i--){
if(buf[i] != '_')
break;
buf[i] = 0;
}
if(n->up == n->up->up)
return fmtprint(f, "\\%s", buf);
return fmtprint(f, "%N.%s", n->up, buf);
}
static int
Vfmt(Fmt *f)
{
void *p;
int i, n, c;
Env *e;
Field *l;
Name *nm;
Method *m;
Region *g;
Ref *r;
p = va_arg(f->args, void*);
if(p == nil)
return fmtprint(f, "nil");
c = TAG(p);
switch(c){
case 'N':
nm = p;
if(nm->v != nm)
return fmtprint(f, "%N=%V", nm, nm->v);
return fmtprint(f, "%N=*", nm);
case 'A':
case 'L':
r = p;
e = r->ref;
if(c == 'A')
return fmtprint(f, "Arg%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", *((uint64_t*)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", ((uint8_t*)p)[i]);
}
fmtprint(f, "}");
return 0;
case 'r':
g = p;
return fmtprint(f, "Region(%s, %#llux, %#llux)",
spacename[g->space & 7], g->off, g->len);
case 'm':
m = p;
fmtprint(f, "%N(", m->name);
for(i=0; i < m->narg; i++){
if(i > 0)
fmtprint(f, ", ");
fmtprint(f, "Arg%d", i);
}
fmtprint(f, ")");
return 0;
case 'u':
fmtprint(f, "Buffer");
/* no break */
case 'f':
l = p;
if(l->index)
return fmtprint(f, "IndexField(%x, %x, %x) @ %V[%V]",
l->flags, l->bitoff, l->bitlen, l->index, l->indexv);
return fmtprint(f, "Field(%x, %x, %x) @ %V",
l->flags, l->bitoff, l->bitlen, l->reg);
default:
return fmtprint(f, "%c:%p", c, p);
}
}
static void
dumpregs(void)
{
Frame *f;
Env *e;
int i;
print("\n*** dumpregs: PC=%p FP=%p\n", PC, FP);
e = nil;
for(f = FP; f >= FB; f--){
print("%.8p.%.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(uint8_t *pc, uint8_t *end, Name *dot, Env *env, void **pret)
{
static int loop;
int i, c;
void *r;
PC = pc;
FP = FB;
FP->tag = 0;
FP->cond = 0;
FP->narg = 0;
FP->phase = "}";
FP->start = PC;
FP->end = end;
FP->aux = end;
FB->ref = nil;
FP->dot = dot;
FP->env = env;
FP->op = nil;
for(;;){
if((++loop & 127) == 0)
gc();
if(amldebug)
print("\n%.8p.%.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);
((uint8_t*)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)
*((uint64_t*)r) |= ((uint64_t)*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;
uint8_t *p;
n = ival(FP->arg[0]);
p = mk('b', n);
m = FP->end - PC;
if(m > n)
m = n;
memmove(p, PC, m);
PC = FP->end;
return p;
}
static void*
evalpkg(void)
{
void **p, **x;
int n;
if((p = FP->ref) != nil){
x = FP->aux;
if(x >= p && x < (p+(SIZE(p)/sizeof(void*)))){
*x++ = FP->arg[0];
FP->aux = x;
}
}else {
n = ival(FP->arg[0]);
if(n < 0) n = 0;
p = mk('p', n*sizeof(void*));
FP->aux = p;
FP->ref = p;
}
return p;
}
static void*
evalname(void)
{
Name *n;
if(n = FP->arg[0])
n->v = FP->arg[1];
else
PC = FP->end;
return nil;
}
static void*
evalscope(void)
{
Name *n;
if(n = FP->arg[0])
FP->dot = n;
else
PC = FP->end;
FP->op = nil;
return nil;
}
static void*
evalalias(void)
{
Name *n;
if(n = FP->arg[1])
n->v = deref(FP->arg[0]);
return nil;
}
static void*
evalmet(void)
{
Name *n;
Method *m;
if((n = FP->arg[0]) != nil){
m = mk('m', sizeof(Method));
m->narg = ival(FP->arg[1]) & 7;
m->start = PC;
m->end = FP->end;
m->name = n;
n->v = m;
}
PC = FP->end;
return nil;
}
static void*
evalreg(void)
{
Name *n;
Region *r;
if((n = FP->arg[0]) != nil){
r = mk('r', sizeof(Region));
r->space = ival(FP->arg[1]);
r->off = ival(FP->arg[2]);
r->len = ival(FP->arg[3]);
r->name = n;
r->va = nil;
n->v = r;
}
return nil;
}
static void*
evalcfield(void)
{
void *r;
Field *f;
Name *n;
int c;
r = FP->arg[0];
if(r == nil || (TAG(r) != 'b' && TAG(r) != 'r'))
return nil;
c = FP->op - optab;
if(c == Ocfld)
n = FP->arg[3];
else
n = FP->arg[2];
if(n == nil || TAG(n) != 'N')
return nil;
if(TAG(r) == 'b')
f = mk('u', sizeof(Field));
else
f = mk('f', sizeof(Field));
switch(c){
case Ocfld:
f->bitoff = ival(FP->arg[1]);
f->bitlen = ival(FP->arg[2]);
break;
case Ocfld0:
f->bitoff = ival(FP->arg[1]);
f->bitlen = 1;
break;
case Ocfld1:
case Ocfld2:
case Ocfld4:
case Ocfld8:
f->bitoff = 8*ival(FP->arg[1]);
f->bitlen = 8*(c - Ocfld0);
break;
}
f->reg = r;
n->v = f;
return nil;
}
static void*
evalfield(void)
{
int flags, bitoff, wa, n;
Field *f, *df;
Name *d;
uint8_t *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;
case Obfld:
df = deref(FP->arg[1]);
if(df == nil || TAG(df) != 'f')
goto Out;
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;
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;
case Obfld:
f->reg = FP->arg[0];
f->bitoff = bitoff;
f->indexv = FP->arg[2];
f->index = df;
break;
}
bitoff += n;
d->v = f;
}
Out:
PC = FP->end;
return nil;
}
static void*
evalnop(void)
{
return nil;
}
static void*
evalbad(void)
{
int i;
print("aml: bad opcode %p: ", PC);
for(i=0; i < 8 && (FP->start+i) < FP->end; i++){
if(i > 0)
print(" ");
print("%.2X", FP->start[i]);
}
if((FP->start+i) < FP->end)
print("...");
print("\n");
PC = FP->end;
return nil;
}
static void*
evalcond(void)
{
switch(FP->op - optab){
case Oif:
if(FP <= FB)
break;
FP[-1].cond = ival(FP->arg[0]) != 0;
if(!FP[-1].cond)
PC = FP->end;
break;
case Oelse:
if(FP <= FB)
break;
if(FP[-1].cond)
PC = FP->end;
break;
case Owhile:
if(FP->aux){
if(PC >= FP->end){
PC = FP->start;
FP->aux = nil;
}
return nil;
}
FP->aux = FP->end;
if(ival(FP->arg[0]) == 0){
PC = FP->end;
break;
}
return nil;
}
FP->op = nil;
return nil;
}
static int64_t
cmp1(void *a, void *b)
{
int64_t 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(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)
{
int64_t 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((uint8_t*)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;
uint64_t 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)
{
int64_t 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'){
uint64_t 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*
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)
{
uint64_t 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 };
uint64_t *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 = (uint8_t*)FP->ref + HdrLen;
break;
case 'r':
r = FP->ref;
if(r->len < l || r->va == nil || r->mapped <= 0)
return nil;
PC = (uint8_t*)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;
r = nil;
switch(FP->op - optab){
case Otoint:
if(FP->arg[0] != nil && TAG(FP->arg[0]) == 's')
r = mki(strtoull((char*)FP->arg[0], 0, 0));
else
r = mki(ival(FP->arg[0]));
break;
}
store(r, FP->arg[1]);
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,
[Osize] "SizeOf", "*", evalsize,
[Oref] "RefOf", "@", evaliarg0,
[Ocref] "CondRefOf", "@@", evalcondref,
[Oderef] "DerefOf", "@", evalderef,
[Ocat] "Concatenate", "**@", evalcat,
[Oacq] "Acquire", "@2", evalnop,
[Orel] "Release", "@", evalnop,
[Ostall] "Stall", "i", evalstall,
[Osleep] "Sleep", "i", evalsleep,
[Oload] "Load", "*@}", evalload,
[Ounload] "Unload", "@", evalnop,
[Otoint] "ToInteger", "*@", evalconv,
};
static uint8_t 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, Obad, Ocfld8,
/* 90 */ Oland, Olor, Olnot, Oleq, Olgt, Ollt, Obad, Obad,
/* 98 */ Obad, Otoint, 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 uint8_t octab2[] = {
/* 00 */ Obad, Omutex, Oevent, Obad, Obad, Obad, Obad, Obad,
/* 08 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad,
/* 10 */ Obad, Obad, Ocref, Ocfld, Obad, Obad, Obad, Obad,
/* 18 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad,
/* 20 */ Oload, Ostall, Osleep, Oacq, Obad, Obad, Obad, Orel,
/* 28 */ Obad, Obad, Ounload,Obad, Obad, Obad, Obad, Obad,
/* 30 */ Obad, Odebug, Obad, Obad, Obad, Obad, Obad, Obad,
/* 38 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad,
/* 40 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad,
/* 48 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad,
/* 50 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad,
/* 58 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad,
/* 60 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad,
/* 68 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad,
/* 70 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad,
/* 78 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad,
/* 80 */ Oreg, Ofld, Odev, Ocpu, Oprc, Othz, Oxfld, 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);
}
uint64_t
amlint(void *p)
{
return ival(p);
}
int
amllen(void *p)
{
while(p){
switch(TAG(p)){
case 'R':
p = *((Ref*)p)->ptr;
continue;
case 'n':
case 's':
return strlen((char*)p);
case 'p':
return SIZE(p)/sizeof(void*);
default:
return SIZE(p);
}
}
return 0;
}
void*
amlnew(char tag, int len)
{
switch(tag){
case 'i':
return mki(0);
case 'n':
case 's':
return mk(tag, len + 1);
case 'p':
return mk(tag, len * sizeof(void*));
default:
return mk(tag, len);
}
}
static void*
evalosi(void)
{
static char *w[] = {
"Windows 2001",
"Windows 2001 SP1",
"Windows 2001 SP2",
"Windows 2006",
};
char *s;
int i;
s = FP->env->arg[0];
if(s == nil || TAG(s) != 's')
return nil;
for(i = 0; i < nelem(w); i++)
if(strcmp(s, w[i]) == 0)
return mki(0xFFFFFFFF);
return nil;
}
void
amlinit(void)
{
Name *n;
fmtinstall('V', Vfmt);
fmtinstall('N', Nfmt);
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;
FP = FB-1;
gc();
}
int
amlload(uint8_t *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, uint64_t));
break;
case 'b':
case 'p':
case '*':
e->arg[i++] = va_arg(a, void*);
break;
}
}
r = va_arg(a, void**);
va_end(a);
if(dot = deref(dot))
if(TAG(dot) == 'm'){
m = dot;
if(i != m->narg)
return -1;
if(m->eval == nil)
return xec(m->start, m->end, forkname(m->name), e, r);
FP = FB;
FP->op = nil;
FP->env = e;
FP->narg = 0;
FP->dot = m->name;
FP->ref = FP->aux = nil;
dot = (*m->eval)();
}
if(r != nil)
*r = dot;
return 0;
}
void
amltake(void *p)
{
if(p != nil)
D2H(p)->mark |= 2;
}
void
amldrop(void *p)
{
if(p != nil)
D2H(p)->mark &= ~2;
}