]> git.lizzy.rs Git - plan9front.git/blob - sys/src/libaml/aml.c
tlsclient: remove X509dump() call, writes to fd 1
[plan9front.git] / sys / src / libaml / aml.c
1 #include <u.h>
2 #include <libc.h>
3 #include <aml.h>
4
5 typedef struct Interp Interp;
6 typedef struct Frame Frame;
7 typedef struct Heap Heap;
8
9 typedef struct Method Method;
10 typedef struct Region Region;
11 typedef struct Field Field;
12
13 typedef struct Name Name;
14 typedef struct Ref Ref;
15 typedef struct Env Env;
16 typedef struct Op Op;
17
18 struct Heap {
19         Heap    *link;
20         int     size;
21         uchar   mark;
22         char    tag;
23 };
24
25 #define H2D(h)  (((Heap*)(h))+1)
26 #define D2H(d)  (((Heap*)(d))-1)
27 #define TAG(d)  D2H(d)->tag
28 #define SIZE(d) D2H(d)->size
29
30 static char *spacename[] = {
31         "Mem", 
32         "Io",
33         "Pcicfg",
34         "Ebctl",
35         "Smbus",
36         "Cmos",
37         "Pcibar",
38         "Ipmi",
39 };
40
41 /* field flags */
42 enum {
43         AnyAcc          = 0x00,
44         ByteAcc         = 0x01,
45         WordAcc         = 0x02,
46         DWordAcc        = 0x03,
47         QWordAcc        = 0x04,
48         BufferAcc       = 0x05,
49         AccMask         = 0x07,
50
51         NoLock          = 0x10,
52
53         Preserve        = 0x00,
54         WriteAsOnes     = 0x20,
55         WriteAsZeros    = 0x40,
56         UpdateMask      = 0x60,
57 };
58
59 struct Method {
60         Name    *name;
61         int     narg;
62         void*   (*eval)(void);
63         uchar   *start;
64         uchar   *end;
65 };
66
67 struct Region {
68         Amlio;
69         char    mapped;
70 };
71
72 struct Field {
73         void    *reg;   /* Buffer or Region */
74         Field   *index;
75         void    *indexv;
76         int     flags;
77         int     bitoff;
78         int     bitlen;
79 };
80
81 struct Name {
82         void    *v;
83
84         Name    *up;
85         Name    *next;
86         Name    *fork;
87         Name    *down;
88
89         char    seg[4];
90 };
91
92 struct Ref {
93         void    *ref;
94         void    **ptr;
95 };
96
97 struct Env {
98         void    *loc[8];
99         void    *arg[8];
100 };
101
102 struct Op {
103         char    *name;
104         char    *sequence;
105         void*   (*eval)(void);
106 };
107
108 struct Frame {
109         int     tag;
110         int     cond;
111         char    *phase;
112         uchar   *start;
113         uchar   *end;
114         Op      *op;
115         Env     *env;
116         Name    *dot;
117         void    *ref;
118         void    *aux;
119         int     narg;
120         void    *arg[8];
121 };
122
123 struct Interp {
124         uchar   *pc;
125         Frame   *fp;
126 };
127
128 static Interp   interp;
129 static Frame    stack[32];
130
131 #define PC      interp.pc
132 #define FP      interp.fp
133 #define FB      stack
134 #define FT      &stack[nelem(stack)]
135
136 static Heap *hp;
137
138 enum {
139         Obad, Onop, Odebug,
140         Ostr, Obyte, Oword, Odword, Oqword, Oconst,
141         Onamec, Oname, Oscope, Oalias,
142         Oreg, Ofld, Oxfld, Obfld, Opkg, Ovpkg, Oenv, Obuf, Omet, 
143         Odev, Ocpu, Othz, Oprc,
144         Oadd, Osub, Omod, Omul, Odiv, Oshl, Oshr, Oand, Onand, Oor,
145         Onor, Oxor, Onot, Olbit, Orbit, Oinc, Odec,
146         Oland, Olor, Olnot, Oleq, Olgt, Ollt,
147         Oindex, Omatch, Omutex, Oevent,
148         Ocfld, Ocfld0, Ocfld1, Ocfld2, Ocfld4, Ocfld8,
149         Oif, Oelse, Owhile, Obreak, Oret, Ocall, 
150         Ostore, Oderef, Osize, Oref, Ocref, Ocat,
151         Oacq, Orel, Ostall, Osleep, Oload, Ounload,
152         Otoint,
153 };
154
155 static Op optab[];
156 static uchar octab1[];
157 static uchar octab2[];
158
159 static Name*
160 rootname(Name *dot)
161 {
162         while(dot != dot->up)
163                 dot = dot->up;
164         return dot;
165 }
166
167 static void
168 gcmark(void *p)
169 {
170         int i;
171         Env *e;
172         Field *f;
173         Heap *h;
174         Name *n, *d;
175
176         if(p == nil)
177                 return;
178         h = D2H(p);
179         if(h->mark & 1)
180                 return;
181         h->mark |= 1;
182         switch(h->tag){
183         case 'E':
184                 e = p;
185                 for(i=0; i<nelem(e->loc); i++)
186                         gcmark(e->loc[i]);
187                 for(i=0; i<nelem(e->arg); i++)
188                         gcmark(e->arg[i]);
189                 break;
190         case 'R':
191         case 'A':
192         case 'L':
193                 gcmark(((Ref*)p)->ref);
194                 break;
195         case 'N':
196                 n = p;
197                 gcmark(n->v);
198                 for(d = n->down; d; d = d->next)
199                         gcmark(d);
200                 gcmark(n->fork);
201                 gcmark(n->up);
202                 break;
203         case 'p':
204                 for(i=0; i<(SIZE(p)/sizeof(void*)); i++)
205                         gcmark(((void**)p)[i]);
206                 break;
207         case 'r':
208                 gcmark(((Region*)p)->name);
209                 break;
210         case 'm':
211                 gcmark(((Method*)p)->name);
212                 break;
213         case 'f':
214         case 'u':
215                 f = p;
216                 gcmark(f->reg);
217                 gcmark(f->index);
218                 gcmark(f->indexv);
219                 break;
220         }
221 }
222
223 static int
224 gc(void)
225 {
226         int i;
227         Heap *h, **hh;
228         Frame *f;
229
230         for(h = hp; h; h = h->link)
231                 h->mark &= ~1;
232
233         for(h = hp; h; h = h->link)
234                 if(h->mark & 2)
235                         gcmark(H2D(h));
236
237         for(f = FP; f >= FB; f--){
238                 for(i=0; i<f->narg; i++)
239                         gcmark(f->arg[i]);
240                 gcmark(f->env);
241                 gcmark(f->dot);
242                 gcmark(f->ref);
243         }
244
245         gcmark(amlroot);
246
247         i = 0;
248         hh = &hp;
249         while(h = *hh){
250                 if(h->mark){
251                         hh = &h->link;
252                         continue;
253                 }
254                 *hh = h->link;
255                 if(h->tag == 'r'){
256                         Region *r = (void*)H2D(h);
257                         if(r->mapped > 0){
258                                 if(amldebug)
259                                         print("\namlunmapio(%N): %-8s %llux - %llux\n", 
260                                                 (Name*)r->name, spacename[r->space],
261                                                 r->off, r->off + r->len);
262                                 amlunmapio(r);
263                         }
264                         r->mapped = 0;
265                         r->write = nil;
266                         r->read = nil;
267                         r->aux = nil;
268                         r->va = nil;
269                 }
270                 memset(h, ~0, sizeof(Heap)+h->size);
271                 amlfree(h);
272                 i++;
273         }
274
275         return i;
276 }
277
278 static void*
279 mk(int tag, int size)
280 {
281         Heap *h;
282         int a;
283
284         a = sizeof(Heap) + size;
285         assert(a >= 0);
286         h = amlalloc(a);
287         h->size = size;
288         h->tag = tag;
289         h->link = hp;
290         hp = h;
291         return h+1;
292 }
293
294 static uvlong*
295 mki(uvlong i)
296 {
297         uvlong *v;
298
299         v = mk('i', sizeof(uvlong));
300         *v = i & amlintmask;
301         return v;
302 }
303
304 static char*
305 mks(char *s)
306 {
307         char *r = mk('s', strlen(s)+1);
308         strcpy(r, s);
309         return r;
310 }
311
312 static int
313 pkglen(uchar *p, uchar *e, uchar **np)
314 {
315         ulong n;
316         uchar b;
317
318         if(p >= e)
319                 return -1;
320         b = *p++;
321         if(b <= 0x3F)
322                 n = b;
323         else {
324                 n = b & 0xF;
325                 if(p >= e)
326                         return -1;
327                 n += *p++ << 4;
328                 if(b >= 0x80){
329                         if(p >= e)
330                                 return -1;
331                         n += *p++ << 12;
332                 }
333                 if(b >= 0xC0){
334                         if(p >= e)
335                                 return -1;
336                         n += *p++ << 20;
337                 }
338         }
339         if(np)
340                 *np = p;
341         return n;
342 }
343
344 static Name*
345 forkname(Name *dot)
346 {
347         Name *n;
348
349         n = mk('N', sizeof(Name));
350         *n = *dot;
351         n->fork = dot;
352         n->next = n->down = nil;
353         if(dot->v == dot)
354                 n->v = n;
355         if(dot->up == dot)
356                 n->up = n;
357         else {
358                 if(n->up = forkname(dot->up))
359                         n->up->down = n;
360         }
361         return n;
362 }
363
364 static Name*
365 getseg(Name *dot, void *seg, int new)
366 {
367         Name *n, *l;
368
369         for(n = l = nil; dot; dot = dot->fork){
370                 for(n = dot->down; n; n = n->next){
371                         if(memcmp(seg, n->seg, 4) == 0)
372                                 return n;
373                         l = n;
374                 }
375                 if(new){
376                         n = mk('N', sizeof(Name));
377                         memmove(n->seg, seg, sizeof(n->seg));
378                         n->up = dot;
379                         if(l == nil)
380                                 dot->down = n;
381                         else
382                                 l->next = n;
383                         n->v = n;
384                         break;
385                 }
386         }
387         return n;
388 }
389
390 Name*
391 getname(Name *dot, char *path, int new)
392 {
393         char seg[4];
394         int i, s;
395         Name *x;
396
397         if(dot == nil)
398                 return nil;
399
400         s = !new;
401         if(*path == '\\'){
402                 path++;
403                 dot = rootname(dot);
404                 s = 0;
405         }
406         while(*path == '^'){
407                 path++;
408                 dot = dot->up;
409                 s = 0;
410         }
411         do {
412                 for(i=0; i<4; i++){
413                         if(*path == 0 || *path == '.')
414                                 break;
415                         seg[i] = *path++;
416                 }
417                 if(i == 0)
418                         break;
419                 while(i < 4)
420                         seg[i++] = '_';
421                 if(s && *path == 0){
422                         for(;;){
423                                 if(x = getseg(dot, seg, 0))
424                                         break;
425                                 if(dot == dot->up)
426                                         break;
427                                 dot = dot->up;
428                         }
429                         return x;
430                 }
431                 s = 0;
432                 dot = getseg(dot, seg, new);
433         } while(*path++ == '.');
434
435         return dot;
436 }
437
438 static int
439 fixnames(void *dot, void *arg)
440 {
441         void **r, *v;
442         int i;
443
444         if(arg == nil)
445                 r = &((Name*)dot)->v;
446         else
447                 r = arg;
448         v = *r;
449         if(v == nil || v == dot)
450                 return 0;
451         if(TAG(v) == 'p'){
452                 r = (void**)v;
453                 for(i=0; i<(SIZE(r)/sizeof(void*)); i++)
454                         fixnames(dot, r+i);
455                 return 0;
456         }
457         if(TAG(v) == 'n' && (v = getname(dot, v, 0)) != nil)
458                 *r = v;
459         return 0;
460 }
461
462 static uvlong
463 getle(uchar *p, int len)
464 {
465         uvlong v;
466         int i;
467
468         v = 0ULL;
469         for(i=0; i<len; i++)
470                 v |= ((uvlong)p[i]) << i*8;
471         return v;
472 }
473
474 static void
475 putle(uchar *p, int len, uvlong v)
476 {
477         int i;
478
479         for(i=0; i<len; i++){
480                 p[i] = v;
481                 v >>= 8;
482         }
483 }
484
485 static uvlong
486 rwreg(void *reg, int off, int len, uvlong v, int write)
487 {
488         uchar buf[8], *p;
489         Region *r;
490
491         switch(TAG(reg)){
492         case 'b':
493                 p = reg;
494                 if((off+len) > SIZE(p))
495                         break;
496                 p += off;
497                 if(write)
498                         putle(p, len, v);
499                 else
500                         v = getle(p, len);
501                 return v;
502
503         case 'r':
504                 r = reg;
505                 if((off+len) > r->len)
506                         break;
507                 if(r->mapped == 0){
508                         if(amldebug)
509                                 print("\namlmapio(%N): %-8s %llux - %llux\n", 
510                                         (Name*)r->name, spacename[r->space],
511                                         r->off, r->off + r->len);
512                         r->mapped = 1;
513                         if(amlmapio(r) < 0)
514                                 r->mapped = -1;
515                 }
516                 if(r->mapped <= 0)
517                         break;
518
519                 if(r->va != nil)
520                         p = r->va + off;
521                 else {
522                         if(len > sizeof(buf))
523                                 break;
524                         p = buf;
525                 }
526
527                 if(write){
528                         if(amldebug)
529                                 print("\nrwreg(%N): %-8s [%llux+%x]/%d <- %llux\n", 
530                                         (Name*)r->name, spacename[r->space],
531                                         r->off, off, len, v);
532                         putle(p, len, v);
533                         if(r->write != nil){
534                                 if((*r->write)(r, p, len, off) != len)
535                                         break;
536                         } else if(p == buf)
537                                 break;
538                 } else {
539                         if(r->read != nil){
540                                 if((*r->read)(r, p, len, off) != len)
541                                         break;
542                         } else if(p == buf)
543                                 break;
544                         v = getle(p, len);
545                         if(amldebug)
546                                 print("\nrwreg(%N): %-8s [%llux+%x]/%d -> %llux\n", 
547                                         (Name*)r->name, spacename[r->space],
548                                         r->off, off, len, v);
549                 }
550                 return v;
551         }
552
553         return ~0;
554 }
555
556 static uvlong
557 ival(void *p)
558 {
559         int n;
560
561         if(p != nil){
562                 switch(TAG(p)){
563                 case 'i':
564                         return *((uvlong*)p);
565                 case 's':
566                         if(*((char*)p) == 0)
567                                 break;
568                         return strtoull((char*)p, 0, 16);
569                 case 'b':
570                         n = SIZE(p);
571                         if(n > 0){
572                                 if(n > 8) n = 8;
573                                 return rwreg(p, 0, n, 0, 0);
574                         }
575                 }
576         }
577         return 0;
578 }
579
580 static void *deref(void *p);
581 static void *store(void *s, void *d);
582
583 static int
584 fieldalign(int flags)
585 {
586         switch(flags & AccMask){
587         default:
588         case AnyAcc:
589         case ByteAcc:
590         case BufferAcc:
591                 return 1;
592         case WordAcc:
593                 return 2;
594         case DWordAcc:
595                 return 4;
596         case QWordAcc:
597                 return 8;
598         }
599 }
600
601 static void*
602 rwfield(Field *f, void *v, int write)
603 {
604         int boff, blen, wo, ws, wl, wa, wd, i;
605         uvlong w, m;
606         void *reg;
607         uchar *b;
608
609         if(f == nil || (reg = deref(f->reg)) == nil)
610                 return nil;
611         if(f->index)
612                 store(f->indexv, f->index);
613         blen = f->bitlen;
614         if(write){
615                 if(v && TAG(v) == 'b'){
616                         b = v;
617                         if(SIZE(b)*8 < blen)
618                                 blen = SIZE(b)*8;
619                 } else {
620                         w = ival(v);
621                         b = mk('b', (blen+7)/8);
622                         putle(b, SIZE(b), w);
623                 }
624         } else
625                 b = mk('b', (blen+7)/8);
626         wa = fieldalign(f->flags);
627         wd = wa*8;
628         boff = 0;
629         while((wl = (blen-boff)) > 0){
630                 wo = (f->bitoff+boff) / wd;
631                 ws = (f->bitoff+boff) % wd;
632                 if(wl > (wd - ws))
633                         wl = wd - ws;
634                 if(write){
635                         w = 0;
636                         for(i = 0; i < wl; i++, boff++)
637                                 if(b[boff/8] & (1<<(boff%8)))
638                                         w |= 1ULL<<i;
639                         w <<= ws;
640                         if(wl != wd){
641                                 m = ((1ULL<<wl)-1) << ws;
642                                 w |= rwreg(reg, wo*wa, wa, 0, 0) & ~m;
643                         }
644                         rwreg(reg, wo*wa, wa, w, 1);
645                 } else {
646                         w = rwreg(reg, wo*wa, wa, 0, 0) >> ws;
647                         for(i = 0; i < wl; i++, boff++){
648                                 b[boff/8] |= (w&1)<<(boff%8);
649                                 w >>= 1;
650                         }
651                 }
652         }
653         if(write)
654                 return nil;
655         if(blen > 64)
656                 return b;
657         w = getle(b, SIZE(b));
658         return mki(w);
659 }
660
661 static void*
662 deref(void *p)
663 {
664         if(p) switch(TAG(p)){
665         case 'N':
666                 return ((Name*)p)->v;
667         case 'R': case 'A': case 'L':
668                 return *((Ref*)p)->ptr;
669         case 'f': case 'u':
670                 return rwfield(p, nil, 0);
671         }
672         return p;
673 }
674
675 static void*
676 copy(int tag, void *s)
677 {
678         static char hex[] = "0123456789ABCDEF";
679         uvlong v;
680         void *d;
681         int i, n;
682
683         if(tag == 0){
684                 if(s == nil)
685                         return nil;
686                 tag = TAG(s);
687         }
688         if(s == nil || TAG(s) == 'i'){
689                 n = 4;
690                 v = ival(s);
691                 if(v > 0xFFFFFFFFULL)
692                         n <<= 1;
693                 switch(tag){
694                 case 'b':
695                         d = mk(tag, n);
696                         rwreg(d, 0, n, v, 1);
697                         return d;
698                 case 's':
699                         n <<= 1;
700                         d = mk(tag, n+1);
701                         ((char*)d)[n] = 0;
702                         while(n > 0){
703                                 ((char*)d)[--n] = hex[v & 0xF];
704                                 v >>= 4;
705                         }
706                         return d;
707                 case 'i':
708                         if(v == 0ULL)
709                                 return nil;
710                         return mki(v);
711                 }
712         } else {
713                 n = SIZE(s);
714                 switch(tag){
715                 case 's':
716                         if(TAG(s) == 'b'){
717                                 d = mk(tag, n*3 + 1);
718                                 for(i=0; i<n; i++){
719                                         ((char*)d)[i*3 + 0] = hex[((uchar*)s)[i] >> 4];
720                                         ((char*)d)[i*3 + 1] = hex[((uchar*)s)[i] & 0xF];
721                                         ((char*)d)[i*3 + 2] = ' ';
722                                 }
723                                 ((char*)d)[n*3] = 0;
724                                 return d;
725                         }
726                         /* no break */
727                 case 'b':
728                         if(TAG(s) == 's'){
729                                 n = strlen(s);
730                                 /* zero length string is converted to zero length buffer */
731                                 if(n > 0) n++;
732                         }
733                         d = mk(tag, n);
734                         memmove(d, s, n);
735                         return d;
736                 }
737         }
738         return s;
739 }
740
741 static void*
742 store(void *s, void *d)
743 {
744         void *p, **pp;
745
746         if(d == nil)
747                 return nil;
748         switch(TAG(d)){
749         default:
750                 return nil;
751         case 'A':
752                 s = deref(s);
753                 /* no break */
754         case 'R': case 'L':
755                 pp = ((Ref*)d)->ptr;
756                 while((p = *pp) != nil){
757                         switch(TAG(p)){
758                         case 'R': case 'A': case 'L':
759                                 pp = ((Ref*)p)->ptr;
760                                 break;
761                         case 'N':
762                                 pp = &((Name*)p)->v;
763                                 break;
764                         }
765                         if(*pp == p)
766                                 break;
767                 }
768                 break;
769         case 'N':
770                 pp = &((Name*)d)->v;
771                 break;
772         }
773         p = *pp;
774         if(p != nil && TAG(p) != 'N'){
775                 switch(TAG(p)){
776                 case 'f':
777                 case 'u':
778                         rwfield(p, s, 1);
779                         return d;
780                 }
781                 if(TAG(d) != 'A' && TAG(d) != 'L'){
782                         *pp = copy(TAG(p), s);
783                         return d;
784                 }
785         }
786         *pp = copy(0, s);
787         return d;
788 }
789
790 static int
791 Nfmt(Fmt *f)
792 {
793         char buf[5];
794         int i;
795         Name *n;
796
797         n = va_arg(f->args, Name*);
798         if(n == nil)
799                 return fmtprint(f, "?NIL");
800         if(n == n->up)
801                 return fmtprint(f, "\\");
802         strncpy(buf, n->seg, 4);
803         buf[4] = 0;
804         for(i=3; i>0; i--){
805                 if(buf[i] != '_')
806                         break;
807                 buf[i] = 0;
808         }
809         if(n->up == n->up->up)
810                 return fmtprint(f, "\\%s", buf);
811         return fmtprint(f, "%N.%s", n->up, buf);
812 }
813
814 static int
815 Vfmt(Fmt *f)
816 {
817         void *p;
818         int i, n, c;
819         Env *e;
820         Field *l;
821         Name *nm;
822         Method *m;
823         Region *g;
824         Ref *r;
825
826         p = va_arg(f->args, void*);
827         if(p == nil)
828                 return fmtprint(f, "nil");
829         c = TAG(p);
830         switch(c){
831         case 'N':
832                 nm = p;
833                 if(nm->v != nm)
834                         return fmtprint(f, "%N=%V", nm, nm->v);
835                 return fmtprint(f, "%N=*", nm);
836         case 'A':
837         case 'L':
838                 r = p;
839                 e = r->ref;
840                 if(c == 'A')
841                         return fmtprint(f, "Arg%zd=%V", r->ptr - e->arg, *r->ptr);
842                 if(c == 'L')
843                         return fmtprint(f, "Local%zd=%V", r->ptr - e->loc, *r->ptr);
844         case 'n':
845                 return fmtprint(f, "%s", (char*)p);
846         case 's':
847                 return fmtprint(f, "\"%s\"", (char*)p);
848         case 'i':
849                 return fmtprint(f, "%#llux", *((uvlong*)p));
850         case 'p':
851                 n = SIZE(p)/sizeof(void*);
852                 fmtprint(f, "Package(%d){", n);
853                 for(i=0; i<n; i++){
854                         if(i > 0)
855                                 fmtprint(f, ", ");
856                         fmtprint(f, "%V", ((void**)p)[i]);
857                 }
858                 fmtprint(f, "}");
859                 return 0;
860         case 'b':
861                 n = SIZE(p);
862                 fmtprint(f, "Buffer(%d){", n);
863                 for(i=0; i<n; i++){
864                         if(i > 0)
865                                 fmtprint(f, ", ");
866                         fmtprint(f, "%.2uX", ((uchar*)p)[i]);
867                 }
868                 fmtprint(f, "}");
869                 return 0;
870         case 'r':
871                 g = p;
872                 return fmtprint(f, "Region(%s, %#llux, %#llux)",
873                         spacename[g->space & 7], g->off, g->len);
874         case 'm':
875                 m = p;
876                 fmtprint(f, "%N(", m->name);
877                 for(i=0; i < m->narg; i++){
878                         if(i > 0)
879                                 fmtprint(f, ", ");
880                         fmtprint(f, "Arg%d", i);
881                 }
882                 fmtprint(f, ")");
883                 return 0;
884         case 'u':
885                 fmtprint(f, "Buffer");
886                 /* no break */
887         case 'f':
888                 l = p;
889                 if(l->index)
890                         return fmtprint(f, "IndexField(%x, %x, %x) @ %V[%V]",
891                                 l->flags, l->bitoff, l->bitlen, l->index, l->indexv);
892                 return fmtprint(f, "Field(%x, %x, %x) @ %V",
893                         l->flags, l->bitoff, l->bitlen, l->reg);
894         default:
895                 return fmtprint(f, "%c:%p", c, p);
896         }
897 }
898
899 static void
900 dumpregs(void)
901 {
902         Frame *f;
903         Env *e;
904         int i;
905
906         print("\n*** dumpregs: PC=%p FP=%p\n", PC, FP);
907         e = nil;
908         for(f = FP; f >= FB; f--){
909                 print("%.8p.%.2zx: %-8s %N\t", f->start, f-FB, f->phase, f->dot);
910                 if(f->op)
911                         print("%s", f->op->name);
912                 print("(");
913                 for(i=0; i<f->narg; i++){
914                         if(i > 0)
915                                 print(", ");
916                         print("%V", f->arg[i]);
917                 }
918                 print(")\n");
919                 if(e == f->env)
920                         continue;
921                 if(e = f->env){
922                         for(i=0; i<nelem(e->arg); i++)
923                                 print("Arg%d=%V ", i, e->arg[i]);
924                         print("\n");
925                         for(i=0; i<nelem(e->loc); i++)
926                                 print("Local%d=%V ", i, e->loc[i]);
927                         print("\n");
928                 }
929         }
930 }
931
932 static int
933 xec(uchar *pc, uchar *end, Name *dot, Env *env, void **pret)
934 {
935         static int loop;
936         int i, c;
937         void *r;
938
939         PC = pc;
940         FP = FB;
941
942         FP->tag = 0;
943         FP->cond = 0;
944         FP->narg = 0;
945         FP->phase = "}";
946         FP->start = PC;
947         FP->end = end;
948         FP->aux = end;
949         FB->ref = nil;
950         FP->dot = dot;
951         FP->env = env;
952         FP->op = nil;
953
954         for(;;){
955                 if((++loop & 127) == 0)
956                         gc();
957                 if(amldebug)
958                         print("\n%.8p.%.2zx %-8s\t%N\t", PC, FP - FB, FP->phase, FP->dot);
959                 r = nil;
960                 c = *FP->phase++;
961                 switch(c){
962                 default:
963                         if(PC >= FP->end){
964                         Overrun:
965                                 print("aml: PC overrun frame end");
966                                 goto Out;
967                         }
968                         FP++;
969                         if(FP >= FT){
970                                 print("aml: frame stack overflow");
971                                 goto Out;
972                         }
973                         *FP = FP[-1];
974                         FP->aux = nil;
975                         FP->ref = nil;
976                         FP->tag = c;
977                         FP->start = PC;
978                         c = *PC++;
979                         if(amldebug) print("%.2X", c);
980                         if(c == '['){
981                                 if(PC >= FP->end)
982                                         goto Overrun;
983                                 c = *PC++;
984                                 if(amldebug) print("%.2X", c);
985                                 c = octab2[c];
986                         }else
987                                 c = octab1[c];
988                         FP->op = &optab[c];
989                         FP->narg = 0;
990                         FP->phase = FP->op->sequence;
991                         if(amldebug) print("\t%s %s", FP->op->name, FP->phase);
992                         continue;
993                 case '{':
994                         end = PC;
995                         c = pkglen(PC, FP->end, &PC);
996                         end += c;
997                         if(c < 0 || end > FP->end)
998                                 goto Overrun;
999                         FP->end = end;
1000                         continue;
1001                 case ',':
1002                         FP->start = PC;
1003                         continue;
1004                 case 's':
1005                         if(end = memchr(PC, 0, FP->end - PC))
1006                                 end++;
1007                         else
1008                                 end = FP->end;
1009                         c = end - PC;
1010                         r = mk('s', c+1);
1011                         memmove(r, PC, c);
1012                         ((uchar*)r)[c] = 0;
1013                         PC = end;
1014                         break;
1015                 case '1':
1016                 case '2':
1017                 case '4':
1018                 case '8':
1019                         end = PC+(c-'0');
1020                         if(end > FP->end)
1021                                 goto Overrun;
1022                         else {
1023                                 r = mki(*PC++);
1024                                 for(i = 8; PC < end; i += 8)
1025                                         *((uvlong*)r) |= ((uvlong)*PC++) << i;
1026                         }
1027                         break;
1028                 case '}':
1029                 case 0:
1030                         if(FP->op){
1031                                 if(amldebug){
1032                                         print("*%p,%V\t%s(", FP->aux, FP->ref, FP->op->name);
1033                                         for(i = 0; i < FP->narg; i++){
1034                                                 if(i > 0)
1035                                                         print(", ");
1036                                                 print("%V", FP->arg[i]);
1037                                         }
1038                                         print(")");
1039                                 }
1040                                 for(i = FP->narg; i < nelem(FP->arg); i++)
1041                                         FP->arg[i] = nil;
1042                                 r = FP->op->eval();
1043                                 if(amldebug)
1044                                         print(" -> %V", r);
1045                         }
1046
1047                         c = FP->phase[-1];
1048                         if(c == '}' && PC < FP->end){
1049                                 FP->narg = 0;
1050                                 FP->phase = "*}";
1051                                 continue;
1052                         }
1053
1054                         if(r) switch(FP->tag){
1055                         case '@':
1056                                 break;
1057                         case 'n':
1058                         case 'N':
1059                                 if(TAG(r) != 'N')
1060                                         r = nil;
1061                                 break;
1062                         default:
1063                                 if((r = deref(r)) == nil)
1064                                         break;
1065                                 switch(TAG(r)){
1066                                 case 'f': case 'u':
1067                                         r = rwfield(r, nil, 0);
1068                                         break;
1069                                 case 'm': {
1070                                         Method *m = r;
1071                                         FP->ref = m;
1072                                         FP->narg = 0;
1073                                         FP->phase = "********}" + (8 - m->narg);
1074                                         FP->op = &optab[Ocall];
1075                                         continue;
1076                                         }
1077                                 }
1078                         }
1079                         FP--;
1080                         break;
1081                 }
1082                 if(FP < FB){
1083                         if(pret){
1084                                 if(amldebug) print(" -> %V\n", r);
1085                                 *pret = r;
1086                         }
1087                         return 0;
1088                 }
1089                 FP->arg[FP->narg++] = r;
1090         }
1091 Out:
1092         if(amldebug)
1093                 dumpregs();
1094         return -1;
1095 }
1096
1097 static void*
1098 evalnamec(void)
1099 {
1100         static char name[1024];
1101         char *d;
1102         void *r;
1103         int c;
1104
1105         c = 1;
1106         d = name;
1107         PC = FP->start;
1108         if(*PC == '\\')
1109                 *d++ = *PC++;
1110         while(*PC == '^'){
1111                 if(d >= &name[sizeof(name)-1]){
1112                 Toolong:
1113                         *d = 0;
1114                         print("aml: name too long: %s\n", name);
1115                         PC = FP->end;
1116                         return nil;
1117                 }
1118                 *d++ = *PC++;
1119         }
1120         if(*PC == '.'){
1121                 PC++;
1122                 c = 2;
1123         } else if(*PC == '/'){
1124                 PC++;
1125                 c = *PC++;
1126         } else if(*PC == 0){
1127                 PC++;
1128                 c = 0;
1129         }
1130         while(c > 0){
1131                 if(d >= &name[sizeof(name)-5])
1132                         goto Toolong;
1133                 *d++ = *PC++;
1134                 *d++ = *PC++;
1135                 *d++ = *PC++;
1136                 *d++ = *PC++;
1137                 while((d > &name[0]) && (d[-1] == '_' || d[-1] == 0))
1138                         d--;
1139                 if(--c > 0)
1140                         *d++ = '.';
1141         }
1142         *d = 0;
1143         if((r = getname(FP->dot, name, FP->tag == 'N')) == nil){
1144                 r = mks(name);
1145                 D2H(r)->tag = 'n';      /* unresolved name */
1146         }
1147         return r;
1148 }
1149
1150 static void*
1151 evaliarg0(void)
1152 {
1153         return FP->arg[0];
1154 }
1155
1156 static void*
1157 evalconst(void)
1158 {
1159         switch(FP->start[0]){
1160         case 0x01:
1161                 return mki(1);
1162         case 0xFF:
1163                 return mki(~0ULL);
1164         }
1165         return nil;
1166 }
1167
1168 static void*
1169 evalbuf(void)
1170 {
1171         int n, m;
1172         uchar *p;
1173
1174         n = ival(FP->arg[0]);
1175         p = mk('b', n);
1176         m = FP->end - PC;
1177         if(m > n)
1178                 m = n;
1179         memmove(p, PC, m);
1180         PC = FP->end;
1181         return p;
1182 }
1183
1184 static void*
1185 evalpkg(void)
1186 {
1187         void **p, **x;
1188         int n;
1189
1190         if((p = FP->ref) != nil){
1191                 x = FP->aux;
1192                 if(x >= p && x < (p+(SIZE(p)/sizeof(void*)))){
1193                         *x++ = FP->arg[0];
1194                         FP->aux = x;
1195                 }
1196         }else {
1197                 n = ival(FP->arg[0]);
1198                 if(n < 0) n = 0;
1199                 p = mk('p', n*sizeof(void*));
1200                 FP->aux = p;
1201                 FP->ref = p;
1202         }
1203         return p;
1204 }
1205
1206 static void*
1207 evalname(void)
1208 {
1209         Name *n;
1210
1211         if(n = FP->arg[0])
1212                 n->v = FP->arg[1];
1213         else
1214                 PC = FP->end;
1215         return nil;
1216 }
1217
1218 static void*
1219 evalscope(void)
1220 {
1221         Name *n;
1222
1223         if(n = FP->arg[0])
1224                 FP->dot = n;
1225         else
1226                 PC = FP->end;
1227         FP->op = nil;
1228         return nil;
1229 }
1230
1231 static void*
1232 evalalias(void)
1233 {
1234         Name *n;
1235
1236         if(n = FP->arg[1])
1237                 n->v = deref(FP->arg[0]);
1238         return nil;
1239 }
1240
1241 static void*
1242 evalmet(void)
1243 {
1244         Name *n;
1245         Method *m;
1246
1247         if((n = FP->arg[0]) != nil){
1248                 m = mk('m', sizeof(Method));
1249                 m->narg = ival(FP->arg[1]) & 7;
1250                 m->start = PC;
1251                 m->end = FP->end;
1252                 m->name = n;
1253                 n->v = m;
1254         }
1255         PC = FP->end;
1256         return nil;
1257 }
1258
1259 static void*
1260 evalreg(void)
1261 {
1262         Name *n;
1263         Region *r;
1264
1265         if((n = FP->arg[0]) != nil){
1266                 r = mk('r', sizeof(Region));
1267                 r->space = ival(FP->arg[1]);
1268                 r->off = ival(FP->arg[2]);
1269                 r->len = ival(FP->arg[3]);
1270                 r->name = n;
1271                 r->va = nil;
1272                 n->v = r;
1273         }
1274         return nil;
1275 }
1276
1277 static void*
1278 evalcfield(void)
1279 {
1280         void *r;
1281         Field *f;
1282         Name *n;
1283         int c;
1284
1285         r = FP->arg[0];
1286         if(r == nil || (TAG(r) != 'b' && TAG(r) != 'r'))
1287                 return nil;
1288         c = FP->op - optab;
1289         if(c == Ocfld)
1290                 n = FP->arg[3];
1291         else
1292                 n = FP->arg[2];
1293         if(n == nil || TAG(n) != 'N')
1294                 return nil;
1295         if(TAG(r) == 'b')
1296                 f = mk('u', sizeof(Field));
1297         else
1298                 f = mk('f', sizeof(Field));
1299         switch(c){
1300         case Ocfld:
1301                 f->bitoff = ival(FP->arg[1]);
1302                 f->bitlen = ival(FP->arg[2]);
1303                 break;
1304         case Ocfld0:
1305                 f->bitoff = ival(FP->arg[1]);
1306                 f->bitlen = 1;
1307                 break;
1308         case Ocfld1:
1309         case Ocfld2:
1310         case Ocfld4:
1311         case Ocfld8:
1312                 f->bitoff = 8*ival(FP->arg[1]);
1313                 f->bitlen = 8*(c - Ocfld0);
1314                 break;
1315         }
1316         f->reg = r;
1317         n->v = f;
1318         return nil;
1319 }
1320
1321 static void*
1322 evalfield(void)
1323 {
1324         int flags, bitoff, wa, n;
1325         Field *f, *df;
1326         Name *d;
1327         uchar *p;
1328
1329         df = nil;
1330         flags = 0;
1331         bitoff = 0;
1332         switch(FP->op - optab){
1333         case Ofld:
1334                 flags = ival(FP->arg[1]);
1335                 break;
1336         case Oxfld:
1337                 df = deref(FP->arg[1]);
1338                 if(df == nil || TAG(df) != 'f')
1339                         goto Out;
1340                 flags = ival(FP->arg[2]);
1341                 break;
1342         case Obfld:
1343                 df = deref(FP->arg[1]);
1344                 if(df == nil || TAG(df) != 'f')
1345                         goto Out;
1346                 flags = ival(FP->arg[3]);
1347                 break;
1348         }
1349         p = PC;
1350         if(p >= FP->end)
1351                 return nil;
1352         while(p < FP->end){
1353                 if(*p == 0x00){
1354                         p++;
1355                         if((n = pkglen(p, FP->end, &p)) < 0)
1356                                 break;
1357                         bitoff += n;
1358                         continue;
1359                 }
1360                 if(*p == 0x01){
1361                         p++;
1362                         flags = *p;
1363                         p += 2;
1364                         continue;
1365                 }
1366                 if(p+4 >= FP->end)
1367                         break;
1368                 if((d = getseg(FP->dot, p, 1)) == nil)
1369                         break;
1370                 if((n = pkglen(p+4, FP->end, &p)) < 0)
1371                         break;
1372                 f = mk('f', sizeof(Field));
1373                 f->flags = flags;
1374                 f->bitlen = n;
1375                 switch(FP->op - optab){
1376                 case Ofld:
1377                         f->reg = FP->arg[0];
1378                         f->bitoff = bitoff;
1379                         break;
1380                 case Oxfld:
1381                         wa = fieldalign(df->flags);
1382                         f->reg = df->reg;
1383                         f->bitoff = df->bitoff + (bitoff % (wa*8));
1384                         f->indexv = mki((bitoff/(wa*8))*wa);
1385                         f->index = FP->arg[0];
1386                         break;
1387                 case Obfld:
1388                         f->reg = FP->arg[0];
1389                         f->bitoff = bitoff;
1390                         f->indexv = FP->arg[2];
1391                         f->index = df;
1392                         break;
1393                 }
1394                 bitoff += n;
1395                 d->v = f;
1396         }
1397 Out:
1398         PC = FP->end;
1399         return nil;
1400 }
1401
1402 static void*
1403 evalnop(void)
1404 {
1405         return nil;
1406 }
1407
1408 static void*
1409 evalbad(void)
1410 {
1411         int i;
1412
1413         print("aml: bad opcode %p: ", PC);
1414         for(i=0; i < 8 && (FP->start+i) < FP->end; i++){
1415                 if(i > 0)
1416                         print(" ");
1417                 print("%.2X", FP->start[i]);
1418         }
1419         if((FP->start+i) < FP->end)
1420                 print("...");
1421         print("\n");
1422         PC = FP->end;
1423         return nil;
1424 }
1425
1426 static void*
1427 evalcond(void)
1428 {
1429         switch(FP->op - optab){
1430         case Oif:
1431                 if(FP <= FB)
1432                         break;
1433                 FP[-1].cond = ival(FP->arg[0]) != 0;
1434                 if(!FP[-1].cond)
1435                         PC = FP->end;
1436                 break;
1437         case Oelse:
1438                 if(FP <= FB)
1439                         break;
1440                 if(FP[-1].cond)
1441                         PC = FP->end;
1442                 break;
1443         case Owhile:
1444                 if(FP->aux){
1445                         if(PC >= FP->end){
1446                                 PC = FP->start;
1447                                 FP->aux = nil;
1448                         }
1449                         return nil;
1450                 }
1451                 FP->aux = FP->end;
1452                 if(ival(FP->arg[0]) == 0){
1453                         PC = FP->end;
1454                         break;
1455                 }
1456                 return nil;
1457         }
1458         FP->op = nil;
1459         return nil;
1460 }
1461
1462 static vlong
1463 cmp1(void *a, void *b)
1464 {
1465         vlong c;
1466         int tag;
1467
1468         if(a == nil || TAG(a) == 'i'){
1469                 c = ival(a) - ival(b);
1470         } else {
1471                 tag = TAG(a);
1472                 if(b == nil || TAG(b) != tag)
1473                         b = copy(tag, b);
1474                 if(TAG(b) != tag)
1475                         return -1;      /* botch */
1476                 switch(tag){
1477                 default:
1478                         return -1;      /* botch */
1479                 case 's':
1480                         c = strcmp((char*)a, (char*)b);
1481                         break;
1482                 case 'b':
1483                         c = SIZE(a) - SIZE(b);
1484                         if(c == 0)
1485                                 c = memcmp(a, b, SIZE(a));
1486                         break;
1487                 }
1488         }
1489         return c;
1490 }
1491
1492 static void*
1493 evalcmp(void)
1494 {
1495         vlong c = cmp1(FP->arg[0], FP->arg[1]);
1496         switch(FP->op - optab){
1497         case Oleq:
1498                 if(c == 0) return mki(1);
1499                 break;
1500         case Olgt:
1501                 if(c > 0) return mki(1);
1502                 break;
1503         case Ollt:
1504                 if(c < 0) return mki(1);
1505                 break;
1506         }
1507         return nil;
1508 }
1509
1510 static void*
1511 evalcall(void)
1512 {
1513         Method *m;
1514         Env *e;
1515         int i;
1516
1517         if(FP->aux){
1518                 if(PC >= FP->end){
1519                         PC = FP->aux;
1520                         FP->end = PC;
1521                 }
1522                 return nil;
1523         }
1524         m = FP->ref;
1525         e = mk('E', sizeof(Env));
1526         for(i=0; i<FP->narg; i++)
1527                 e->arg[i] = deref(FP->arg[i]);
1528         FP->env = e;
1529         FP->narg = 0;
1530         FP->dot = m->name;
1531         if(m->eval != nil){
1532                 FP->op = nil;
1533                 FP->end = PC;
1534                 return (*m->eval)();
1535         }
1536         FP->dot = forkname(FP->dot);
1537         FP->aux = PC;
1538         FP->start = m->start;
1539         FP->end = m->end;
1540         PC = FP->start;
1541         return nil;
1542 }
1543
1544 static void*
1545 evalret(void)
1546 {
1547         void *r = FP->arg[0];
1548         int brk = (FP->op - optab) != Oret;
1549         while(--FP >= FB){
1550                 switch(FP->op - optab){
1551                 case Owhile:
1552                         if(!brk)
1553                                 continue;
1554                         PC = FP->end;
1555                         return nil;
1556                 case Ocall:
1557                         PC = FP->aux;
1558                         return r;
1559                 }
1560         }
1561         FP = FB;
1562         PC = FB->end;
1563         return r;
1564 }
1565
1566 static void*
1567 evalenv(void)
1568 {
1569         Ref *r;
1570         Env *e;
1571         int c;
1572
1573         if((e = FP->env) == nil)
1574                 return nil;
1575         c = FP->start[0];
1576         if(c >= 0x60 && c <= 0x67){
1577                 r = mk('L', sizeof(Ref));
1578                 r->ptr = &e->loc[c - 0x60];
1579         } else if(c >= 0x68 && c <= 0x6E){
1580                 r = mk('A', sizeof(Ref));
1581                 r->ptr = &e->arg[c - 0x68];
1582         } else
1583                 return nil;
1584         r->ref = e;
1585         return r;
1586 }
1587
1588 static void*
1589 evalstore(void)
1590 {
1591         return store(FP->arg[0], FP->arg[1]);
1592 }
1593
1594 static void*
1595 evalcat(void)
1596 {
1597         void *r, *a, *b;
1598         int tag, n, m;
1599
1600         a = FP->arg[0];
1601         b = FP->arg[1];
1602         if(a == nil || TAG(a) == 'i')
1603                 a = copy('b', a);       /* Concat(Int, ???) -> Buf */
1604         tag = TAG(a);
1605         if(b == nil || TAG(b) != tag)
1606                 b = copy(tag, b);
1607         if(TAG(b) != tag)
1608                 return nil;     /* botch */
1609         switch(tag){
1610         default:
1611                 return nil;     /* botch */
1612         case 'b':
1613                 n = SIZE(a);
1614                 m = SIZE(b);
1615                 r = mk('b', n + m);
1616                 memmove(r, a, n);
1617                 memmove((uchar*)r + n, b, m);
1618                 break;
1619         case 's':
1620                 n = strlen((char*)a);
1621                 m = strlen((char*)b);
1622                 r = mk('s', n + m + 1);
1623                 memmove(r, a, n);
1624                 memmove((char*)r + n, b, m);
1625                 ((char*)r)[n+m] = 0;
1626                 break;
1627         }
1628         store(r, FP->arg[2]);
1629         return r;
1630 }
1631
1632 static void*
1633 evalindex(void)
1634 {
1635         Field *f;
1636         void *p;
1637         Ref *r;
1638         uvlong x;
1639
1640         x = ival(FP->arg[1]);
1641         if(p = deref(FP->arg[0])) switch(TAG(p)){
1642         case 's':
1643                 if(x >= strlen((char*)p))
1644                         break;
1645                 /* no break */
1646         case 'b':
1647                 if(x >= SIZE(p))
1648                         break;
1649                 f = mk('u', sizeof(Field));
1650                 f->reg = p;
1651                 f->bitlen = 8;
1652                 f->bitoff = 8*x;
1653                 store(f, FP->arg[2]);
1654                 return f;
1655         case 'p':
1656                 if(x >= (SIZE(p)/sizeof(void*)))
1657                         break;
1658                 if(TAG(FP->arg[0]) == 'A' || TAG(FP->arg[0]) == 'L')
1659                         r = mk(TAG(FP->arg[0]), sizeof(Ref));
1660                 else
1661                         r = mk('R', sizeof(Ref));
1662                 r->ref = p;
1663                 r->ptr = ((void**)p) + x;
1664                 store(r, FP->arg[2]);
1665                 return r;
1666         }
1667         return nil;
1668 }
1669
1670 static int
1671 match1(int op, void *a, void *b)
1672 {
1673         vlong c = cmp1(a, b);
1674         switch(op){
1675         case 0: return 1;
1676         case 1: return c == 0;
1677         case 2: return c <= 0;
1678         case 3: return c < 0;
1679         case 4: return c >= 0;
1680         case 5: return c > 0;
1681         }
1682         return 0;
1683 }
1684
1685 static void*
1686 evalmatch(void)
1687 {
1688         void **p = FP->arg[0];
1689         if(p != nil && TAG(p) == 'p'){
1690                 uvlong i, n = SIZE(p)/sizeof(void*);
1691                 int o1 = ival(FP->arg[1]), o2 = ival(FP->arg[3]);
1692                 for(i=ival(FP->arg[5]); i<n; i++){
1693                         void *a = deref(p[i]);
1694                         if(match1(o1, a, FP->arg[2]) && match1(o2, a, FP->arg[4]))
1695                                 return mki(i);
1696                 }
1697         }
1698         return mki(~0ULL);
1699 }
1700
1701 static void*
1702 evalcondref(void)
1703 {
1704         void *s;
1705         if((s = FP->arg[0]) == nil)
1706                 return nil;
1707         store(s, FP->arg[1]);
1708         return mki(1);
1709 }
1710
1711 static void*
1712 evalsize(void)
1713 {
1714         return mki(amllen(FP->arg[0]));
1715 }
1716
1717 static void*
1718 evalderef(void)
1719 {
1720         void *p;
1721
1722         if(p = FP->arg[0]){
1723                 if(TAG(p) == 's' || TAG(p) == 'n')
1724                         p = getname(FP->dot, (char*)p, 0);
1725                 p = deref(p);
1726         }
1727         return p;
1728 }
1729
1730 static void*
1731 evalarith(void)
1732 {
1733         uvlong v, d;
1734         void *r;
1735         int i;
1736
1737         r = nil;
1738         switch(FP->op - optab){
1739         case Oadd:
1740                 r = mki(ival(FP->arg[0]) + ival(FP->arg[1]));
1741                 break;
1742         case Osub:
1743                 r = mki(ival(FP->arg[0]) - ival(FP->arg[1]));
1744                 break;
1745         case Omul:
1746                 r = mki(ival(FP->arg[0]) * ival(FP->arg[1]));
1747                 break;
1748         case Omod:
1749         case Odiv:
1750                 v = ival(FP->arg[0]);
1751                 d = ival(FP->arg[1]);
1752                 if(d == 0){
1753                         print("aml: division by zero: PC=%#p\n", PC);
1754                         return nil;
1755                 }
1756                 r = mki(v % d);
1757                 store(r, FP->arg[2]);
1758                 if((FP->op - optab) != Odiv)
1759                         return r;
1760                 r = mki(v / d);
1761                 store(r, FP->arg[3]); 
1762                 return r;
1763         case Oshl:
1764                 r = mki(ival(FP->arg[0]) << ival(FP->arg[1]));
1765                 break;
1766         case Oshr:
1767                 r = mki(ival(FP->arg[0]) >> ival(FP->arg[1]));
1768                 break;
1769         case Oand:
1770                 r = mki(ival(FP->arg[0]) & ival(FP->arg[1]));
1771                 break;
1772         case Onand:
1773                 r = mki(~(ival(FP->arg[0]) & ival(FP->arg[1])));
1774                 break;
1775         case Oor:
1776                 r = mki(ival(FP->arg[0]) | ival(FP->arg[1]));
1777                 break;
1778         case Onor:
1779                 r = mki(~(ival(FP->arg[0]) | ival(FP->arg[1])));
1780                 break;
1781         case Oxor:
1782                 r = mki(ival(FP->arg[0]) ^ ival(FP->arg[1]));
1783                 break;
1784         case Onot:
1785                 r = mki(~ival(FP->arg[0]));
1786                 store(r, FP->arg[1]);
1787                 return r;
1788         case Olbit:
1789                 v = ival(FP->arg[0]);
1790                 if(v == 0)
1791                         break;
1792                 for(i=0; (v & 1) == 0; i++)
1793                         v >>= 1;
1794                 r = mki(i+1);
1795                 break;
1796         case Orbit:
1797                 v = ival(FP->arg[0]);
1798                 if(v == 0)
1799                         break;
1800                 for(i=0; v != 0; i++)
1801                         v >>= 1;
1802                 r = mki(i);
1803                 break;
1804         case Oland:
1805                 return mki(ival(FP->arg[0]) && ival(FP->arg[1]));
1806         case Olor:
1807                 return mki(ival(FP->arg[0]) || ival(FP->arg[1]));
1808         case Olnot:
1809                 return mki(ival(FP->arg[0]) == 0);
1810
1811         case Oinc:
1812                 r = mki(ival(deref(FP->arg[0]))+1);
1813                 store(r, FP->arg[0]);
1814                 return r;
1815         case Odec:
1816                 r = mki(ival(deref(FP->arg[0]))-1);
1817                 store(r, FP->arg[0]);
1818                 return r;
1819         }
1820
1821         store(r, FP->arg[2]);
1822         return r;
1823 }
1824
1825 static void*
1826 evalload(void)
1827 {
1828         enum { LenOffset = 4, HdrLen = 36 };
1829         uvlong *tid;
1830         Region *r;
1831         int l;
1832
1833         tid = nil;
1834         if(FP->aux){
1835                 if(PC >= FP->end){
1836                         amlenum(amlroot, nil, fixnames, nil);
1837                         FP->aux = nil;
1838                         FP->end = PC;
1839                         tid = mki(1);   /* fake */
1840                 }
1841         } else {
1842                 store(nil, FP->arg[1]);
1843                 if(FP->arg[0] == nil)
1844                         return nil;
1845
1846                 l = rwreg(FP->arg[0], LenOffset, 4, 0, 0);
1847                 if(l <= HdrLen)
1848                         return nil;
1849
1850                 FP->aux = PC;   /* save */
1851                 FP->ref = FP->arg[0];
1852                 switch(TAG(FP->ref)){
1853                 case 'b':
1854                         if(SIZE(FP->ref) < l)
1855                                 return nil;
1856                         PC = (uchar*)FP->ref + HdrLen;
1857                         break;
1858                 case 'r':
1859                         r = FP->ref;
1860                         if(r->len < l || r->va == nil || r->mapped <= 0)
1861                                 return nil;
1862                         PC = (uchar*)r->va + HdrLen;
1863                         break;
1864                 default:
1865                         return nil;
1866                 }
1867                 FP->end = PC + (l - HdrLen);
1868                 FP->dot = amlroot;
1869                 FP->env = nil;
1870
1871                 tid = mki(1); /* fake */
1872                 store(tid, FP->arg[1]);
1873         }
1874         return tid;
1875 }
1876
1877 static void*
1878 evalstall(void)
1879 {
1880         amldelay(ival(FP->arg[0]));
1881         return nil;
1882 }
1883
1884 static void*
1885 evalsleep(void)
1886 {
1887         amldelay(ival(FP->arg[0])*1000);
1888         return nil;
1889 }
1890
1891 static void*
1892 evalconv(void)
1893 {
1894         void *r;
1895
1896         r = nil;
1897         switch(FP->op - optab){
1898         case Otoint:
1899                 if(FP->arg[0] != nil && TAG(FP->arg[0]) == 's')
1900                         r = mki(strtoull((char*)FP->arg[0], 0, 0));
1901                 else
1902                         r = mki(ival(FP->arg[0]));
1903                 break;
1904         }
1905         store(r, FP->arg[1]);
1906         return r;
1907 }
1908
1909 static Op optab[] = {
1910         [Obad]          "",                     "",             evalbad,
1911         [Onop]          "Noop",                 "",             evalnop,
1912         [Odebug]        "Debug",                "",             evalnop,
1913
1914         [Ostr]          ".str",                 "s",            evaliarg0,
1915         [Obyte]         ".byte",                "1",            evaliarg0,
1916         [Oword]         ".word",                "2",            evaliarg0,
1917         [Odword]        ".dword",               "4",            evaliarg0,
1918         [Oqword]        ".qword",               "8",            evaliarg0,
1919         [Oconst]        ".const",               "",             evalconst,
1920         [Onamec]        ".name",                "",             evalnamec,
1921         [Oenv]          ".env",                 "",             evalenv,
1922
1923         [Oname]         "Name",                 "N*",           evalname,
1924         [Oscope]        "Scope",                "{n}",          evalscope,
1925         [Oalias]        "Alias",                "nN",           evalalias,
1926
1927         [Odev]          "Device",               "{N}",          evalscope,
1928         [Ocpu]          "Processor",            "{N141}",       evalscope,
1929         [Othz]          "ThermalZone",          "{N}",          evalscope,
1930         [Oprc]          "PowerResource",        "{N12}",        evalscope,
1931
1932         [Oreg]          "OperationRegion",      "N1ii",         evalreg,
1933         [Ofld]          "Field",                "{n1",          evalfield,
1934         [Oxfld]         "IndexField",           "{nn1",         evalfield,
1935         [Obfld]         "BankField",            "{nni1",        evalfield,
1936
1937         [Ocfld]         "CreateField",          "*iiN",         evalcfield,
1938         [Ocfld0]        "CreateBitField",       "*iN",          evalcfield,
1939         [Ocfld1]        "CreateByteField",      "*iN",          evalcfield,
1940         [Ocfld2]        "CreateWordField",      "*iN",          evalcfield,
1941         [Ocfld4]        "CreateDWordField",     "*iN",          evalcfield,
1942         [Ocfld8]        "CreateQWordField",     "*iN",          evalcfield,
1943
1944         [Opkg]          "Package",              "{1}",          evalpkg,
1945         [Ovpkg]         "VarPackage",           "{i}",          evalpkg,
1946         [Obuf]          "Buffer",               "{i",           evalbuf,
1947         [Omet]          "Method",               "{N1",          evalmet,
1948
1949         [Oadd]          "Add",                  "ii@",          evalarith,
1950         [Osub]          "Subtract",             "ii@",          evalarith,
1951         [Omod]          "Mod",                  "ii@",          evalarith,
1952         [Omul]          "Multiply",             "ii@",          evalarith,
1953         [Odiv]          "Divide",               "ii@@",         evalarith,
1954         [Oshl]          "ShiftLef",             "ii@",          evalarith,
1955         [Oshr]          "ShiftRight",           "ii@",          evalarith,
1956         [Oand]          "And",                  "ii@",          evalarith,
1957         [Onand]         "Nand",                 "ii@",          evalarith,
1958         [Oor]           "Or",                   "ii@",          evalarith,
1959         [Onor]          "Nor",                  "ii@",          evalarith,
1960         [Oxor]          "Xor",                  "ii@",          evalarith,
1961         [Onot]          "Not",                  "i@",           evalarith,
1962
1963         [Olbit]         "FindSetLeftBit",       "i@",           evalarith,
1964         [Orbit]         "FindSetRightBit",      "i@",           evalarith,
1965
1966         [Oinc]          "Increment",            "@",            evalarith,
1967         [Odec]          "Decrement",            "@",            evalarith,
1968
1969         [Oland]         "LAnd",                 "ii",           evalarith,
1970         [Olor]          "LOr",                  "ii",           evalarith,
1971         [Olnot]         "LNot",                 "i",            evalarith,
1972
1973         [Oleq]          "LEqual",               "**",           evalcmp,
1974         [Olgt]          "LGreater",             "**",           evalcmp,
1975         [Ollt]          "LLess",                "**",           evalcmp,
1976
1977         [Omutex]        "Mutex",                "N1",           evalnop,
1978         [Oevent]        "Event",                "N",            evalnop,
1979
1980         [Oif]           "If",                   "{i}",          evalcond,
1981         [Oelse]         "Else",                 "{}",           evalcond,
1982         [Owhile]        "While",                "{,i}",         evalcond,
1983         [Obreak]        "Break",                "",             evalret,
1984         [Oret]          "Return",               "*",            evalret,
1985         [Ocall]         "Call",                 "",             evalcall,
1986
1987         [Ostore]        "Store",                "*@",           evalstore,
1988         [Oindex]        "Index",                "@i@",          evalindex,
1989         [Omatch]        "Match",                "*1*1*i",       evalmatch,
1990         [Osize]         "SizeOf",               "*",            evalsize,
1991         [Oref]          "RefOf",                "@",            evaliarg0,
1992         [Ocref]         "CondRefOf",            "@@",           evalcondref,
1993         [Oderef]        "DerefOf",              "@",            evalderef,
1994         [Ocat]          "Concatenate",          "**@",          evalcat,
1995
1996         [Oacq]          "Acquire",              "@2",           evalnop,
1997         [Orel]          "Release",              "@",            evalnop,
1998         [Ostall]        "Stall",                "i",            evalstall,
1999         [Osleep]        "Sleep",                "i",            evalsleep,
2000         [Oload]         "Load",                 "*@}",          evalload,
2001         [Ounload]       "Unload",               "@",            evalnop,
2002
2003         [Otoint]        "ToInteger",            "*@",           evalconv,
2004 };
2005
2006 static uchar octab1[] = {
2007 /* 00 */        Oconst, Oconst, Obad,   Obad,   Obad,   Obad,   Oalias, Obad,
2008 /* 08 */        Oname,  Obad,   Obyte,  Oword,  Odword, Ostr,   Oqword, Obad,
2009 /* 10 */        Oscope, Obuf,   Opkg,   Ovpkg,  Omet,   Obad,   Obad,   Obad,
2010 /* 18 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2011 /* 20 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2012 /* 28 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Onamec, Onamec,
2013 /* 30 */        Onamec, Onamec, Onamec, Onamec, Onamec, Onamec, Onamec, Onamec,
2014 /* 38 */        Onamec, Onamec, Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2015 /* 40 */        Obad,   Onamec, Onamec, Onamec, Onamec, Onamec, Onamec, Onamec,
2016 /* 48 */        Onamec, Onamec, Onamec, Onamec, Onamec, Onamec, Onamec, Onamec,
2017 /* 50 */        Onamec, Onamec, Onamec, Onamec, Onamec, Onamec, Onamec, Onamec,
2018 /* 58 */        Onamec, Onamec, Onamec, Obad,   Onamec, Obad,   Onamec, Onamec,
2019 /* 60 */        Oenv,   Oenv,   Oenv,   Oenv,   Oenv,   Oenv,   Oenv,   Oenv,
2020 /* 68 */        Oenv,   Oenv,   Oenv,   Oenv,   Oenv,   Oenv,   Oenv,   Obad,
2021 /* 70 */        Ostore, Oref,   Oadd,   Ocat,   Osub,   Oinc,   Odec,   Omul,
2022 /* 78 */        Odiv,   Oshl,   Oshr,   Oand,   Onand,  Oor,    Onor,   Oxor,
2023 /* 80 */        Onot,   Olbit,  Orbit,  Oderef, Obad,   Omod,   Obad,   Osize,
2024 /* 88 */        Oindex, Omatch, Ocfld4, Ocfld2, Ocfld1, Ocfld0, Obad,   Ocfld8,
2025 /* 90 */        Oland,  Olor,   Olnot,  Oleq,   Olgt,   Ollt,   Obad,   Obad,
2026 /* 98 */        Obad,   Otoint, Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2027 /* A0 */        Oif,    Oelse,  Owhile, Onop,   Oret,   Obreak, Obad,   Obad,
2028 /* A8 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2029 /* B0 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2030 /* B8 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2031 /* C0 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2032 /* C8 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2033 /* D0 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2034 /* D8 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2035 /* E0 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2036 /* E8 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2037 /* F0 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2038 /* F8 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Oconst,
2039 };
2040
2041 static uchar octab2[] = {
2042 /* 00 */        Obad,   Omutex, Oevent, Obad,   Obad,   Obad,   Obad,   Obad,
2043 /* 08 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2044 /* 10 */        Obad,   Obad,   Ocref,  Ocfld,  Obad,   Obad,   Obad,   Obad,
2045 /* 18 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2046 /* 20 */        Oload,  Ostall, Osleep, Oacq,   Obad,   Obad,   Obad,   Orel,
2047 /* 28 */        Obad,   Obad,   Ounload,Obad,   Obad,   Obad,   Obad,   Obad,
2048 /* 30 */        Obad,   Odebug, Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2049 /* 38 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2050 /* 40 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2051 /* 48 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2052 /* 50 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2053 /* 58 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2054 /* 60 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2055 /* 68 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2056 /* 70 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2057 /* 78 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2058 /* 80 */        Oreg,   Ofld,   Odev,   Ocpu,   Oprc,   Othz,   Oxfld,  Obfld,
2059 /* 88 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2060 /* 90 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2061 /* 98 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2062 /* A0 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2063 /* A8 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2064 /* B0 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2065 /* B8 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2066 /* C0 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2067 /* C8 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2068 /* D0 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2069 /* D8 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2070 /* E0 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2071 /* E8 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2072 /* F0 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2073 /* F8 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2074 };
2075
2076 int
2077 amltag(void *p)
2078 {
2079         return p ? TAG(p) : 0;
2080 }
2081
2082 void*
2083 amlval(void *p)
2084 {
2085         return deref(p);
2086 }
2087
2088 uvlong
2089 amlint(void *p)
2090 {
2091         return ival(p);
2092 }
2093
2094 int
2095 amllen(void *p)
2096 {
2097         while(p){
2098                 switch(TAG(p)){
2099                 case 'R':
2100                         p = *((Ref*)p)->ptr;
2101                         continue;
2102                 case 'n':
2103                 case 's':
2104                         return strlen((char*)p);
2105                 case 'p':
2106                         return SIZE(p)/sizeof(void*);
2107                 default:
2108                         return SIZE(p);
2109                 }
2110         }
2111         return 0;
2112 }
2113
2114 void*
2115 amlnew(char tag, int len)
2116 {
2117         switch(tag){
2118         case 'i':
2119                 return mki(0);
2120         case 'n':
2121         case 's':
2122                 return mk(tag, len + 1);
2123         case 'p':
2124                 return mk(tag, len * sizeof(void*));
2125         default:
2126                 return mk(tag, len);
2127         }
2128 }
2129
2130 static void*
2131 evalosi(void)
2132 {
2133         static char *w[] = { 
2134                 "Windows 2001",
2135                 "Windows 2001 SP1",
2136                 "Windows 2001 SP2",
2137                 "Windows 2006",
2138         };
2139         char *s;
2140         int i;
2141
2142         s = FP->env->arg[0];
2143         if(s == nil || TAG(s) != 's')
2144                 return nil;
2145         for(i = 0; i < nelem(w); i++)
2146                 if(strcmp(s, w[i]) == 0)
2147                         return mki(0xFFFFFFFF);
2148         return nil;
2149 }
2150
2151 void
2152 amlinit(void)
2153 {
2154         Name *n;
2155
2156         fmtinstall('V', Vfmt);
2157         fmtinstall('N', Nfmt);
2158
2159         if(!amlintmask)
2160                 amlintmask = ~0ULL;
2161
2162         n = mk('N', sizeof(Name));
2163         n->up = n;
2164
2165         amlroot = n;
2166
2167         getname(amlroot, "_GPE", 1);
2168         getname(amlroot, "_PR", 1);
2169         getname(amlroot, "_SB", 1);
2170         getname(amlroot, "_TZ", 1);
2171         getname(amlroot, "_SI", 1);
2172         getname(amlroot, "_GL", 1);
2173
2174         if(n = getname(amlroot, "_REV", 1))
2175                 n->v = mki(2);
2176         if(n = getname(amlroot, "_OS", 1))
2177                 n->v = mks("Microsoft Windows");
2178         if(n = getname(amlroot, "_OSI", 1)){
2179                 Method *m;
2180
2181                 m = mk('m', sizeof(Method));
2182                 m->narg = 1;
2183                 m->eval = evalosi;
2184                 m->name = n;
2185                 n->v = m;
2186         }
2187 }
2188
2189 void
2190 amlexit(void)
2191 {
2192         amlroot = nil;
2193         FP = FB-1;
2194         gc();
2195 }
2196
2197 int
2198 amlload(uchar *data, int len)
2199 {
2200         int ret;
2201
2202         ret = xec(data, data+len, amlroot, nil, nil);
2203         amlenum(amlroot, nil, fixnames, nil);
2204         return ret;
2205 }
2206
2207 void*
2208 amlwalk(void *dot, char *name)
2209 {
2210         return getname(dot, name, 0);
2211 }
2212
2213 void
2214 amlenum(void *dot, char *seg, int (*proc)(void *, void *), void *arg)
2215 {
2216         Name *n, *d;
2217         int rec;
2218
2219         d = dot;
2220         if(d == nil || TAG(d) != 'N')
2221                 return;
2222         do {
2223                 rec = 1;
2224                 if(seg == nil || memcmp(seg, d->seg, sizeof(d->seg)) == 0)
2225                         rec = (*proc)(d, arg) == 0;
2226                 for(n = d->down; n && rec; n = n->next)
2227                         amlenum(n, seg, proc, arg);
2228                 d = d->fork;
2229         } while(d);
2230 }
2231
2232 int
2233 amleval(void *dot, char *fmt, ...)
2234 {
2235         va_list a;
2236         Method *m;
2237         void **r;
2238         Env *e;
2239         int i;
2240
2241         va_start(a, fmt);
2242         e = mk('E', sizeof(Env));
2243         for(i=0;*fmt;fmt++){
2244                 switch(*fmt){
2245                 default:
2246                         return -1;
2247                 case 's':
2248                         e->arg[i++] = mks(va_arg(a, char*));
2249                         break;
2250                 case 'i':
2251                         e->arg[i++] = mki(va_arg(a, int));
2252                         break;
2253                 case 'I':
2254                         e->arg[i++] = mki(va_arg(a, uvlong));
2255                         break;
2256                 case 'b':
2257                 case 'p':
2258                 case '*':
2259                         e->arg[i++] = va_arg(a, void*);
2260                         break;
2261                 }
2262         }
2263         r = va_arg(a, void**);
2264         va_end(a);
2265         if(dot = deref(dot))
2266         if(TAG(dot) == 'm'){
2267                 m = dot;
2268                 if(i != m->narg)
2269                         return -1;
2270                 if(m->eval == nil)
2271                         return xec(m->start, m->end, forkname(m->name), e, r);
2272                 FP = FB;
2273                 FP->op = nil;
2274                 FP->env = e;
2275                 FP->narg = 0;
2276                 FP->dot = m->name;
2277                 FP->ref = FP->aux = nil;
2278                 dot = (*m->eval)();
2279         }
2280         if(r != nil)
2281                 *r = dot;
2282         return 0;
2283 }
2284
2285 void
2286 amltake(void *p)
2287 {
2288         if(p != nil)
2289                 D2H(p)->mark |= 2;
2290 }
2291
2292 void
2293 amldrop(void *p)
2294 {
2295         if(p != nil)
2296                 D2H(p)->mark &= ~2;
2297 }