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