]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/vmx/x86.c
vmx(1): use cycles() instead of nsec() when possible
[plan9front.git] / sys / src / cmd / vmx / x86.c
1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4 #include <bio.h>
5 #include <mach.h>
6 #include "dat.h"
7 #include "fns.h"
8 #include "x86.h"
9
10 typedef struct VMemReq VMemReq;
11 struct VMemReq {
12         QLock;
13         uintptr va, len;
14         void *buf;
15         uintptr rc;
16         int wr;
17 };
18
19 static uintptr
20 translateflat(uintptr va, uintptr *pa, int *perm)
21 {
22         if(sizeof(uintptr) != 4 && va >> 32 != 0) return 0;
23         *pa = va;
24         if(va == 0)
25                 return 0xFFFFFFFFUL;
26         if(perm != 0) *perm = -1;
27         return -va;
28 }
29
30 static uintptr
31 translate32(uintptr va, uintptr *pa, int *perm)
32 {
33         void *pd, *pt;
34         u32int pde, pte;
35
36         if(sizeof(uintptr) != 4 && va >> 32 != 0) return -1;
37         pd = gptr(rget("cr3") & ~0xfff, 4096);
38         if(pd == nil) return 0;
39         pde = GET32(pd, (va >> 22) * 4);
40         if(perm != nil) *perm = pde;
41         if((pde & 1) == 0) return 0;
42         if((pde & 0x80) != 0 && (rget("cr4real") & Cr4Pse) != 0){
43                 *pa = pde & 0xffc00000 | (uintptr)(pde & 0x3fe000) << 19 | va & 0x3fffff;
44                 return 0x400000 - (va & 0x3fffff);
45         }
46         pt = gptr(pde & ~0xfff, 4096);
47         if(pt == nil) return 0;
48         pte = GET32(pt, va >> 10 & 0xffc);
49         if((pte & 1) == 0) return 0;
50         if(perm != nil) *perm &= pte;
51         *pa = pte & ~0xfff | va & 0xfff;
52         return 0x1000 - (va & 0xfff);
53 }
54
55 static uintptr
56 translatepae(uintptr, uintptr *, int *)
57 {
58         vmerror("PAE translation not implemented");
59         return 0;
60 }
61
62 static uintptr
63 translate64(uintptr, uintptr *, int *)
64 {
65         vmerror("long mode translation not implemented");
66         return 0;       
67 }
68
69 static uintptr (*
70 translator(void))(uintptr, uintptr *, int *)
71 {
72         uintptr cr0, cr4, efer;
73         
74         cr0 = rget("cr0real");
75         if((cr0 & Cr0Pg) == 0)
76                 return translateflat;
77         efer = rget("efer");
78         if((efer & EferLme) != 0)
79                 return translate64;
80         cr4 = rget("cr4real");
81         if((cr4 & Cr4Pae) != 0)
82                 return translatepae;
83         return translate32;
84 }
85
86 static void
87 vmemread0(void *aux)
88 {
89         VMemReq *req;
90         uintptr va, pa, n, ok, pok;
91         void *v;
92         uintptr (*trans)(uintptr, uintptr *, int *);
93         uchar *p;
94         int wr;
95         
96         req = aux;
97         va = req->va;
98         n = req->len;
99         p = req->buf;
100         wr = req->wr;
101         trans = translator();
102         while(n > 0){
103                 ok = trans(va, &pa, nil);
104                 if(ok == 0) break;
105                 if(ok > n) ok = n;
106                 v = gptr(pa, 1);
107                 if(v == nil) break;
108                 pok = gavail(v);
109                 if(ok > pok) ok = pok;
110                 if(wr)
111                         memmove(v, p, ok);
112                 else
113                         memmove(p, v, ok);
114                 n -= ok;
115                 p += ok;
116                 va += ok;
117         }
118         req->rc = req->len - n;
119         qunlock(req);
120 }
121
122 uintptr
123 vmemread(void *buf, uintptr len, uintptr va)
124 {
125         VMemReq req;
126         
127         memset(&req, 0, sizeof(VMemReq));
128         req.wr = 0;
129         req.buf = buf;
130         req.len = len;
131         req.va = va;
132         qlock(&req);
133         sendnotif(vmemread0, &req);
134         qlock(&req);
135         return req.rc;
136 }
137
138 uintptr
139 vmemwrite(void *buf, uintptr len, uintptr va)
140 {
141         VMemReq req;
142         
143         memset(&req, 0, sizeof(VMemReq));
144         req.wr = 1;
145         req.buf = buf;
146         req.len = len;
147         req.va = va;
148         qlock(&req);
149         sendnotif(vmemread0, &req);
150         qlock(&req);
151         return req.rc;
152 }
153
154 int
155 x86access(int seg, uintptr addr0, int asz, uvlong *val, int sz, int acc, TLB *tlb)
156 {
157         int cpl;
158         static char *baser[] = {"csbase", "dsbase", "esbase", "fsbase", "gsbase", "ssbase"};
159         static char *limitr[] = {"cslimit", "dslimit", "eslimit", "fslimit", "gslimit", "sslimit"};
160         static char *permr[] = {"csperm", "dsperm", "esperm", "fsperm", "gsperm", "ssperm"};
161         uvlong tval;
162         u32int limit, perm;
163         uintptr addr, base, szmax;
164         int pperm, wp, i;
165         uintptr pa[8], pav;
166         uintptr l;
167         uchar *ptr;
168         Region *r;
169
170         switch(asz){
171         case 2: addr0 = (u16int)addr0; break;
172         case 4: addr0 = (u32int)addr0; break;
173         case 8: break;
174         default:
175                 vmerror("invalid asz=%d in x86access", asz);
176                 assert(0);
177         }
178         assert(seg < SEGMAX && (u8int)acc <= ACCX);
179         addr = addr0;
180         if(tlb != nil && tlb->asz == asz && tlb->seg == seg && tlb->acc == (u8int)acc && addr >= tlb->start && addr + sz >= addr && addr + sz < tlb->end){
181                 ptr = tlb->base + addr;
182                 pa[0] = tlb->pabase + addr;
183                 r = tlb->reg;
184                 goto fast;
185         }
186         if(sizeof(uintptr) == 8 && asz == 8){
187                 if(seg == SEGFS || seg == SEGGS)
188                         addr += rget(baser[seg]);
189                 if((u16int)(((u64int)addr >> 48) + 1) > 1){
190                 gpf:
191                         if((acc & ACCSAFE) == 0){
192                                 vmdebug("gpf");
193                                 postexc("#gp", 0);
194                         }
195                         return -1;
196                 }
197                 if((vlong)addr >= 0)
198                         szmax = (1ULL<<48) - addr;
199                 else
200                         szmax = -addr;
201         }else{
202                 limit = rget(limitr[seg]);
203                 perm = rget(permr[seg]);
204                 if((perm & 0xc) == 0x4){
205                         if((u32int)(addr + sz - 1) < addr || addr <= limit)
206                                 goto limfault;
207                         szmax = (u32int)-addr;
208                 }else{
209                         if((u64int)addr + sz - 1 >= limit){
210                         limfault:
211                                 if((acc & ACCSAFE) == 0){
212                                         vmdebug("limit fault");
213                                         postexc(seg == SEGSS ? "#ss" : "#gp", 0);
214                                 }
215                                 return -1;
216                         }
217                         szmax = limit - addr + 1;
218                 }
219                 if((perm & 0x10080) != 0x80)
220                         goto gpf;
221                 switch((u8int)acc){
222                 case ACCR: if((perm & 0xa) == 8) goto gpf; break;
223                 case ACCW: if((perm & 0xa) != 2) goto gpf; break;
224                 case ACCX: if((perm & 8) == 0) goto gpf; break;
225                 }
226                 base = rget(baser[seg]);
227                 addr = (u32int)(addr + base);
228         }
229         cpl = rget("cs") & 3;
230         wp = (rget("cr0real") & 1<<16) != 0;
231         for(i = 0; i < sz; ){
232                 l = translator()(addr+i, &pav, &pperm);
233                 if(l == 0){
234                 pf:
235                         if((acc & ACCSAFE) == 0){
236                                 vmdebug("page fault @ %#p", addr+i);
237                                 postexc("#pf", pperm & 1 | ((u8int)acc == ACCW) << 1 | (cpl == 3) << 2 | ((u8int)acc == ACCX) << 4);
238                                 rset("cr2", addr+i);
239                         }
240                         return -1;
241                 }
242                 if((cpl == 3 || wp) && (u8int)acc == ACCW && (pperm & 2) == 0)
243                         goto pf;
244                 if(cpl == 3 && (pperm & 4) == 0)
245                         goto pf;
246                 if(i == 0 && l < szmax) szmax = l;
247                 while(i < sz && l-- > 0)
248                         pa[i++] = pav++;
249         }
250         if(szmax >= sz){
251                 r = regptr(pa[0]);
252                 if(r == nil || pa[0]+sz > r->end) goto slow;
253                 ptr = (uchar*)r->v + (pa[0] - r->start);
254                 if(tlb != nil){
255                         l = gavail(ptr);
256                         if(l < szmax) szmax = l;
257                         tlb->asz = asz;
258                         tlb->seg = seg;
259                         tlb->acc = (u8int)acc;
260                         tlb->start = addr0;
261                         tlb->end = addr0 + szmax;
262                         tlb->reg = r;
263                         tlb->base = ptr - addr0;
264                         tlb->pabase = pa[0] - addr0;
265                 }
266         fast:
267                 if(r->mmio != nil)
268                         r->mmio(pa[0], val, sz, (u8int)acc == ACCW);
269                 else if(acc == ACCW)
270                         switch(sz){
271                         case 1: PUT8(ptr, 0, *val); break;
272                         case 2: PUT16(ptr, 0, *val); break;
273                         case 4: PUT32(ptr, 0, *val); break;
274                         case 8: PUT64(ptr, 0, *val); break;
275                         default: goto slow;
276                         }
277                 else
278                         switch(sz){
279                         case 1: *val = GET8(ptr, 0); break;
280                         case 2: *val = GET16(ptr, 0); break;
281                         case 4: *val = GET32(ptr, 0); break;
282                         case 8: *val = GET64(ptr, 0); break;
283                         default: goto slow;
284                         }
285         }else{
286         slow:
287                 if(acc != ACCW)
288                         *val = 0;
289                 for(i = 0; i < sz; i++){
290                         r = regptr(pa[i]);
291                         if(r == nil)
292                                 vmerror("x86access: access to unmapped address %#p", pa[i]);
293                         else if(acc == ACCW){
294                                 tval = GET8(val, i);
295                                 if(r->mmio != nil)
296                                         r->mmio(pa[i], &tval, 1, 1);
297                                 else
298                                         PUT8(r->v, pa[i] - r->start, tval);
299                         }else{
300                                 if(r->mmio != nil)
301                                         r->mmio(pa[i], &tval, 1, 0);
302                                 else
303                                         tval = GET8(r->v, pa[i] - r->start);
304                                 PUT8(val, i, tval);
305                         }       
306                 }
307         }
308         return 0;
309 }
310
311 enum {
312         ONOPE,  OADC,   OADD,   OAND,   OASZ,   OCALL,  OCMP,   OCMPS,  ODEC,
313         OENTER, OEX,    OIMUL,  OINC,   OINS,   OLEAVE, OLOCK,  OLODS,  OMOV,   OMOVS,
314         OOR,    OOSZ,   OOUTS,  OPOP,   OPOPA,  OPOPF,  OPUSH,  OPUSHA, OPUSHF,
315         OREP,   OREPNE, ORET,   OSBB,   OSCAS,  OSEG,   OSTOS,  OSUB,
316         OTEST,  OXCHG,  OXLAT,  OXOR,   OROL,   OROR,   ORCL,   ORCR,
317         OSHL,   OSHR,   OSAR,   ONOT,   ONEG,   ODIV,   OIDIV,  OMUL,
318         OJMP,
319 };
320
321 static char *onames[] = {
322         [ONOPE]"ONOPE", [OADC]"OADC", [OADD]"OADD", [OAND]"OAND", [OASZ]"OASZ", [OCALL]"OCALL", [OCMP]"OCMP", [OCMPS]"OCMPS", [ODEC]"ODEC",
323         [OENTER]"OENTER", [OIMUL]"OIMUL", [OINC]"OINC", [OINS]"OINS", [OLEAVE]"OLEAVE", [OLOCK]"OLOCK", [OLODS]"OLODS", [OMOV]"OMOV", [OMOVS]"OMOVS",
324         [OOR]"OOR", [OOSZ]"OOSZ", [OOUTS]"OOUTS", [OPOP]"OPOP", [OPOPA]"OPOPA", [OPOPF]"OPOPF", [OPUSH]"OPUSH", [OPUSHA]"OPUSHA", [OPUSHF]"OPUSHF",
325         [OREP]"OREP", [OREPNE]"OREPNE", [ORET]"ORET", [OSBB]"OSBB", [OSCAS]"OSCAS", [OSEG]"OSEG", [OSTOS]"OSTOS", [OSUB]"OSUB",
326         [OTEST]"OTEST", [OXCHG]"OXCHG", [OXLAT]"OXLAT", [OXOR]"OXOR", [OEX]"OEX", [OROL]"OROL", [OROR]"OROR", [ORCL]"ORCL", [ORCR]"ORCR",
327         [OSHL]"OSHL", [OSHR]"OSHR", [OSAR]"OSAR", [ONOT]"ONOT", [ONEG]"ONEG", [ODIV]"ODIV", [OIDIV]"OIDIV", [OMUL]"OMUL", [OJMP]"OJMP"
328 };
329 #define enumconv(x,buf,tab) ((x)<nelem(tab)?(tab)[x]:(sprint(buf,"%d",(x)),buf))
330
331 /*
332         size fields:
333         0 b byte
334         1 v short/long/vlong (16-bit,32-bit,64-bit mode)
335         2 z short/long/long
336         3 w short
337 */
338
339 enum {
340         ANOPE,
341         A1 = 1, /* constant 1 */
342         
343         /* general purpose registers with size+1 in high nibble */
344         AGPRb = 0x10,
345         AGPRv = 0x20,
346         AGPRz = 0x30,
347         AAXb = 0x10,    ACXb = 0x11,    ADXb = 0x12,    ABXb = 0x13,    ASPb = 0x14,    ABPb = 0x15,    ASIb = 0x16,    ADIb = 0x17,
348         AAXv = 0x20,    ACXv = 0x21,    ADXv = 0x22,    ABXv = 0x23,    ASPv = 0x24,    ABPv = 0x25,    ASIv = 0x26,    ADIv = 0x27,
349         AAXz = 0x30,    ACXz = 0x31,    ADXz = 0x32,    ABXz = 0x33,    ASPz = 0x34,    ABPz = 0x35,    ASIz = 0x36,    ADIz = 0x37,
350         
351         ASEG = 0x40,    ACS = 0x40,     ADS = 0x41,     AES = 0x42,     AFS = 0x43,     AGS = 0x44,     ASS = 0x45,
352         
353         /* below has valid size in lower nibble */
354         AGOTSZ = 0x50,
355         AOb = 0x50,     AOv = 0x51,
356         
357         AIMM = 0x70,
358         AIb = 0x70,             AIz = 0x72,
359         /* below involves modrm */
360         AMODRM = 0x80,
361         AEb = 0x80,     AEv = 0x81,
362         AGb = 0x90,     AGv = 0x91,
363         ASw = 0xA3,
364 };
365
366 static char *anames[] = {
367         [ANOPE]"ANOPE", [AEb]"AEb",     [AEv]"AEv",     [AGb]"AGb",     [AGv]"AGv",     [AIb]"AIb",     [AIz]"AIz",
368         [ASw]"ASw",     [AOb]"AOb",     [AOv]"AOv",
369         [ACS]"ACS",     [ADS]"ADS",     [AES]"AES",     [AFS]"AFS",     [AGS]"AGS",     [ASS]"ASS",
370         [AAXb]"AAXb",   [ABXb]"ABXb",   [ACXb]"ACXb",   [ADXb]"ADXb",   [ABPb]"ABPb",   [ASPb]"ASPb",   [ASIb]"ASIb",   [ADIb]"ADIb",
371         [AAXv]"AAXv",   [ABXv]"ABXv",   [ACXv]"ACXv",   [ADXv]"ADXv",   [ABPv]"ABPv",   [ASPv]"ASPv",   [ASIv]"ASIv",   [ADIv]"ADIv",
372         [AAXz]"AAXz",   [ABXz]"ABXz",   [ACXz]"ACXz",   [ADXz]"ADXz",   [ABPz]"ABPz",   [ASPz]"ASPz",   [ASIz]"ASIz",   [ADIz]"ADIz",
373 };
374 /* typically b is dst and c is src */
375 #define O(a,b,c) ((a)|(b)<<8|(c)<<16)
376
377 /* we only care about operations that can go to memory */
378 static u32int optab[256] = {
379 /*0*/   O(OADD,AEb,AGb), O(OADD,AEv,AGv), O(OADD,AGb,AEb), O(OADD,AGv,AEv), O(OADD,AAXb,AIb), O(OADD,AAXz,AIz), O(OPUSH,AES,0), O(OPOP,AES,0),
380         O(OOR,AEb,AGb), O(OOR,AEv,AGv), O(OOR,AGb,AEb), O(OOR,AGv,AEv), O(OOR,AAXb,AIb), O(OOR,AAXz,AIz), O(OPUSH,ACS,0), 0,
381         
382 /*1*/   O(OADC,AEb,AGb), O(OADC,AEv,AGv), O(OADC,AGb,AEb), O(OADC,AGv,AEv), O(OADC,AAXb,AIb), O(OADC,AAXz,AIz), O(OPUSH,ASS,0), O(OPOP,ASS,0),
383         O(OSBB,AEb,AGb), O(OSBB,AEv,AGv), O(OSBB,AGb,AEb), O(OSBB,AGv,AEv), O(OSBB,AAXb,AIb), O(OSBB,AAXz,AIz), O(OPUSH,ADS,0), O(OPOP,ADS,0),
384         
385 /*2*/   O(OAND,AEb,AGb), O(OAND,AEv,AGv), O(OAND,AGb,AEb), O(OAND,AGv,AEv), O(OAND,AAXb,AIb), O(OAND,AAXz,AIz), O(OSEG,AES,0), 0/*DAA*/,
386         O(OSUB,AEb,AGb), O(OSUB,AEv,AGv), O(OSUB,AGb,AEb), O(OSUB,AGv,AEv), O(OSUB,AAXb,AIb), O(OSUB,AAXz,AIz), O(OSEG,ACS,0), 0/*DAS*/,
387
388 /*3*/   O(OXOR,AEb,AGb), O(OXOR,AEv,AGv), O(OXOR,AGb,AEb), O(OXOR,AGv,AEv), O(OXOR,AAXb,AIb), O(OXOR,AAXz,AIz), O(OSEG,ASS,0), 0/*AAA*/,
389         O(OCMP,AEb,AGb), O(OCMP,AEv,AGv), O(OCMP,AGb,AEb), O(OCMP,AGv,AEv), O(OCMP,AAXb,AIb), O(OCMP,AAXz,AIz), O(OSEG,ADS,0), 0/*AAS*/,
390         
391 /*4*/   0, 0, 0, 0, 0, 0, 0, 0, /* rex prefixes */
392         0, 0, 0, 0, 0, 0, 0, 0,
393         
394 /*5*/   O(OPUSH,AAXv,0), O(OPUSH,ACXv,0), O(OPUSH,ADXv,0), O(OPUSH,ABXv,0), O(OPUSH,ASPv,0), O(OPUSH,ABPv,0), O(OPUSH,ASIv,0), O(OPUSH,ADIv,0),
395         O(OPOP,AAXv,0), O(OPOP,ACXv,0), O(OPOP,ADXv,0), O(OPOP,ABXv,0), O(OPOP,ASPv,0), O(OPOP,ABPv,0), O(OPOP,ASIv,0), O(OPOP,ADIv,0),
396         
397 /*6*/   OPUSHA, OPOPA, 0/*BOUND*/, 0/*ARPL*/, O(OSEG,AFS,0), O(OSEG,AGS,0), OOSZ, OASZ,
398         O(OPUSH,AIz,0), O(OIMUL,AGv,AIz), O(OPUSH,AIb,0), O(OIMUL,AGv,AIb), OINS, OINS, OOUTS, OOUTS,
399         
400 /*7*/   0, 0, 0, 0, 0, 0, 0, 0, /* jumps */
401         0, 0, 0, 0, 0, 0, 0, 0,
402         
403 /*8*/   OEX, OEX, OEX, OEX, O(OTEST,AEb,AGb), O(OTEST,AEv,AGv), O(OXCHG,AEb,AGb), O(OXCHG,AEv,AGv),
404         O(OMOV,AEb,AGb), O(OMOV,AEv,AGv), O(OMOV,AGb,AEb), O(OMOV,AGv,AEv), O(OMOV,AEv,ASw), 0/*LEA*/, O(OMOV,ASw,AEv), OEX,
405
406 /*9*/   0, 0, 0, 0, 0, 0, 0, 0, /* register exchange */
407         0/*CBW*/, 0/*CWD*/, OCALL, 0/*FWAIT*/, OPUSHF, OPOPF, 0/*OSAHF*/, 0/*OLAHF*/,
408         
409 /*A*/   O(OMOV,AAXb,AOb), O(OMOV,AAXv,AOv), O(OMOV,AOb,AAXb), O(OMOV,AOv,AAXv), OMOVS, OMOVS, OCMPS, OCMPS,
410         0, 0/*TEST Reg,Imm*/, OSTOS, OSTOS, OLODS, OLODS, OSCAS, OSCAS,
411
412 /*B*/   0, 0, 0, 0, 0, 0, 0, 0, /* move immediate to register */
413         0, 0, 0, 0, 0, 0, 0, 0,
414
415 /*C*/   OEX, OEX, ORET, ORET, 0/*LES*/, 0/*LDS*/, OEX, OEX,
416         OENTER, OLEAVE, ORET, ORET, 0/*INT3*/, 0/*INTn*/, 0/*INTO*/, 0/*IRET*/,
417         
418 /*D*/   OEX, OEX, OEX, OEX, 0/*AAM*/, 0/*AAD*/, 0, OXLAT,
419         0, 0, 0, 0, 0, 0, 0, 0, /* fpu */
420
421 /*E*/   0, 0, 0/*LOOPx*/, 0/*JrCXZ*/, 0, 0/*IN*/, 0, 0/*OUT*/,
422         OCALL, OCALL, 0, 0/*JMP*/, 0, 0/*IN*/, 0, 0/*OUT*/,
423
424 /*F*/   OLOCK, 0, OREPNE, OREP, 0/*HALT*/, 0/*CMC*/, OEX, OEX,
425         0/*CLC*/, 0/*STC*/, 0/*CLI*/, 0/*STI*/, 0/*CLD*/, 0/*STD*/, OEX, OEX,
426 };
427 /* OEX tables (operations determined by modrm byte) */
428 static u32int optab80[8] = {O(OADD,AEb,AIb), O(OOR,AEb,AIb), O(OADC,AEb,AIb), O(OSBB,AEb,AIb), O(OAND,AEb,AIb), O(OSUB,AEb,AIb), O(OXOR,AEb,AIb), O(OCMP,AEb,AIb)};
429 static u32int optab81[8] = {O(OADD,AEv,AIz), O(OOR,AEv,AIz), O(OADC,AEv,AIz), O(OSBB,AEv,AIz), O(OAND,AEv,AIz), O(OSUB,AEv,AIz), O(OXOR,AEv,AIz), O(OCMP,AEv,AIz)};
430 /* 0x82 is identical to 0x80 */
431 static u32int optab83[8] = {O(OADD,AEv,AIb), O(OOR,AEv,AIb), O(OADC,AEv,AIb), O(OSBB,AEv,AIb), O(OAND,AEv,AIb), O(OSUB,AEv,AIb), O(OXOR,AEv,AIb), O(OCMP,AEv,AIb)};
432 static u32int optab8F[8] = {O(OPOP,AEv,0)};
433 static u32int optabC0[8] = {O(OROL,AEb,AIb), O(OROR,AEb,AIb), O(ORCL,AEb,AIb), O(ORCR,AEb,AIb), O(OSHL,AEb,AIb), O(OSHR,AEb,AIb), 0, O(OSAR,AEb,AIb)};
434 static u32int optabC1[8] = {O(OROL,AEv,AIb), O(OROR,AEv,AIb), O(ORCL,AEv,AIb), O(ORCR,AEv,AIb), O(OSHL,AEv,AIb), O(OSHR,AEv,AIb), 0, O(OSAR,AEv,AIb)};
435 static u32int optabD0[8] = {O(OROL,AEb,A1), O(OROR,AEb,A1), O(ORCL,AEb,A1), O(ORCR,AEb,A1), O(OSHL,AEb,A1), O(OSHR,AEb,A1), 0, O(OSAR,AEb,A1)};
436 static u32int optabD1[8] = {O(OROL,AEv,A1), O(OROR,AEv,A1), O(ORCL,AEv,A1), O(ORCR,AEv,A1), O(OSHL,AEv,A1), O(OSHR,AEv,A1), 0, O(OSAR,AEv,A1)};
437 static u32int optabD2[8] = {O(OROL,AEb,ACXb), O(OROR,AEb,ACXb), O(ORCL,AEb,ACXb), O(ORCR,AEb,ACXb), O(OSHL,AEb,ACXb), O(OSHR,AEb,ACXb), 0, O(OSAR,AEb,ACXb)};
438 static u32int optabD3[8] = {O(OROL,AEv,ACXb), O(OROR,AEv,ACXb), O(ORCL,AEv,ACXb), O(ORCR,AEv,ACXb), O(OSHL,AEv,ACXb), O(OSHR,AEv,ACXb), 0, O(OSAR,AEv,ACXb)};
439 static u32int optabC6[8] = {O(OMOV,AEb,AIb)};
440 static u32int optabC7[8] = {O(OMOV,AEv,AIz)};
441 static u32int optabF6[8] = {O(OTEST,AEb,AIb), 0, O(ONOT,AEb,0), O(ONEG,AEb,0), O(OMUL,AAXb,AEb), O(OIMUL,AAXb,0), O(ODIV,AAXb,0), O(OIDIV,AAXb,0)};
442 static u32int optabF7[8] = {O(OTEST,AEv,AIz), 0, O(ONOT,AEv,0), O(ONEG,AEv,0), O(OMUL,AAXv,AEv), O(OIMUL,AAXv,0), O(ODIV,AAXv,0), O(OIDIV,AAXv,0)};
443 static u32int optabFE[8] = {O(OINC,AEb,0),O(ODEC,AEb,0)};
444 static u32int optabFF[8] = {O(OINC,AEv,0),O(ODEC,AEv,0),OCALL,OCALL,OJMP,OJMP,O(OPUSH,AEv,0),0};
445
446 typedef struct Instr Instr;
447 typedef struct Oper Oper;
448 /* for registers we put the number in addr and add +0x10 for "high bytes" (AH etc) */
449 struct Oper {
450         enum { OPNONE, OPREG, OPSEG, OPIMM, OPMEM } type;
451         uintptr addr;
452         int sz;
453         uvlong val;
454 };
455 struct Instr {
456         u8int bytes[16];
457         int nbytes;
458         u8int opcode; /* first byte after the prefixes */
459         u32int inf;
460         u8int modrm, sib;
461         vlong disp;
462         uvlong imm;
463         enum {
464                 INSLOCK = 0x1,
465                 INSREP = 0x2,
466                 INSREPNE = 0x4,
467                 INSOSZ = 0x8,
468                 INSASZ = 0x10,
469                 INSMODRM = 0x20,
470                 INSSIB = 0x40,
471                 INSDISP8 = 0x80,
472                 INSDISP16 = 0x100,
473                 INSDISP32 = 0x200,
474                 INSDISP64 = 0x400,
475                 INSIMM8 = 0x800,
476                 INSIMM16 = 0x1000,
477                 INSIMM32 = 0x2000,
478         /*      INSIMM64 = 0x4000, not yet */
479         } flags;
480         int seg;
481         u8int osz, asz;
482         Oper op[2];
483 };
484
485 struct Step {
486         uintptr pc, npc;
487         u8int mode;
488         TLB tlb;
489         Instr;
490 } step;
491
492 static int
493 fetch8(int acc)
494 {
495         uvlong v;
496         
497         if(step.nbytes >= sizeof(step.bytes)){
498                 if((acc & ACCSAFE) == 0){
499                         vmerror("x86step: instruction too long (pc=%#p)", step.pc);
500                         postexc("#ud", NOERRC);
501                 }
502                 return -1;
503         }
504         if(x86access(SEGCS, step.npc, step.mode, &v, 1, ACCX|acc, &step.tlb) < 0){
505                 vmerror("x86step: fault while trying to load %#p, shouldn't happen", step.pc);
506                 return -1;
507         }
508         step.npc++;
509         step.bytes[step.nbytes++] = v;
510         return (u8int)v;
511 }
512
513 static int
514 fetch16(int acc)
515 {
516         int r0, r1;
517         
518         if(r0 = fetch8(acc), r0 < 0) return -1;
519         if(r1 = fetch8(acc), r1 < 0) return -1;
520         return r0 | r1 << 8;
521 }
522
523 static vlong
524 fetch32(int acc)
525 {
526         int r0, r1, r2, r3;
527         
528         if(r0 = fetch8(acc), r0 < 0) return -1;
529         if(r1 = fetch8(acc), r1 < 0) return -1;
530         if(r2 = fetch8(acc), r2 < 0) return -1;
531         if(r3 = fetch8(acc), r3 < 0) return -1;
532         return r0 | r1 << 8 | r2 << 16 | r3 << 24;
533 }
534
535 static int
536 fetch64(int acc, uvlong *p)
537 {
538         vlong r0, r1;
539         
540         if(r0 = fetch32(acc), r0 < 0) return -1;
541         if(r1 = fetch32(acc), r1 < 0) return -1;
542         *p = r0 | r1 << 32;
543         return 0;
544 }
545
546 static long
547 machread(int, void *vb, long n, vlong soff)
548 {
549         uvlong o;
550         
551         o = soff;
552         if(o < step.pc) return 0;
553         if(o >= step.pc+step.nbytes) return 0;
554         if(n > step.pc+step.nbytes-o)
555                 n = step.pc+step.nbytes-o;
556         memmove(vb, step.bytes+(o-step.pc), n);
557         return n;
558 }
559
560 static void
561 giveup(void)
562 {
563         static Map *m;
564         char buf[128];
565         char *p, *e;
566         extern Machdata i386mach;
567         int i, rc;
568         
569         if(m == nil){
570                 m = newmap(nil, 1);
571                 setmap(m, -1, 0, -1, 0, "text");
572                 m->seg[0].read = machread;
573         }
574         p = buf;
575         e = buf + sizeof(buf);
576         while(fetch8(ACCSAFE) >= 0)
577                 ;
578         if(rc = i386mach.das(m, step.pc, 0, buf, sizeof(buf)), rc >= 0){
579                 p += strlen(buf);
580                 p = seprint(p, e, " # ");
581         }else
582                 rc = step.nbytes;
583         for(i = 0; i < rc; i++)
584                 p = seprint(p, e, "%.2x ", step.bytes[i]);
585         vmerror("x86step: unimplemented instruction %s", buf);  
586 }
587
588 static int
589 grab(void)
590 {
591         int op;
592         int rc;
593         vlong vrc;
594         u32int inf;
595         u32int *tab;
596
597 again:
598         op = fetch8(0);
599         if(op < 0) return -1;
600         inf = optab[op];
601         if(inf == 0){ giveup(); return -1; }
602         switch((u8int)inf){
603         case OLOCK: step.flags |= INSLOCK; goto again;
604         case OREP: step.flags |= INSREP; goto again;
605         case OREPNE: step.flags |= INSREPNE; goto again;
606         case OOSZ: step.flags |= INSOSZ; step.osz = step.osz == 2 ? 4 : 2; goto again;
607         case OASZ: step.flags |= INSASZ; step.asz = step.asz == 2 ? 4 : 2; goto again;
608         case OSEG: step.seg = inf >> 8; goto again;
609         }
610         step.opcode = op;
611         if((u8int)(inf >> 8) >= AMODRM || (u8int)(inf >> 16) >= AMODRM || inf == OEX){
612                 rc = fetch8(0);
613                 if(rc < 0) return -1;
614                 step.modrm = rc;
615                 step.flags |= INSMODRM;
616                 if(step.asz != 2 && (step.modrm & 0x07) == 0x04 && step.modrm < 0xc0){
617                         rc = fetch8(0); if(rc < 0) return -1;
618                         step.sib = rc;
619                         step.flags |= INSSIB;
620                 }
621                 switch(step.modrm >> 6){
622                 case 1:
623                         rc = fetch8(0); if(rc < 0) return -1;
624                         step.disp = (s8int)rc;
625                         step.flags |= INSDISP8;
626                         break;
627                 case 0:
628                         if((step.modrm & 7) != (step.asz == 2) + 5 && (step.sib & 7) != 5)
629                                 break;
630                         /* wet floor */
631                 case 2:
632                         if(step.asz == 2){
633                                 rc = fetch16(0); if(rc < 0) return -1;
634                                 step.disp = (s16int)rc;
635                                 step.flags |= INSDISP16;
636                         }else{
637                                 vrc = fetch32(0); if(vrc < 0) return -1;
638                                 step.disp = (s32int)vrc;
639                                 step.flags |= INSDISP32;
640                         }
641                         break;
642                 }
643         }
644         if(inf == OEX){
645                 switch(op){
646                 case 0x80: case 0x82: tab = optab80; break;
647                 case 0x81: tab = optab81; break;
648                 case 0x83: tab = optab83; break;
649                 case 0x8f: tab = optab8F; break;
650                 case 0xc0: tab = optabC0; break;
651                 case 0xc1: tab = optabC1; break;
652                 case 0xd0: tab = optabD0; break;
653                 case 0xd1: tab = optabD1; break;
654                 case 0xd2: tab = optabD2; break;
655                 case 0xd3: tab = optabD3; break;
656                 case 0xc6: tab = optabC6; break;
657                 case 0xc7: tab = optabC7; break;
658                 case 0xf6: tab = optabF6; break;
659                 case 0xf7: tab = optabF7; break;
660                 case 0xfe: tab = optabFE; break;
661                 case 0xff: tab = optabFF; break;
662                 default: tab = nil;
663                 }
664                 if(tab == nil || (inf = tab[step.modrm >> 3 & 7]) == 0){
665                         giveup();
666                         return -1;
667                 }
668         }
669         if(((u8int)(inf >> 8) & 0xf0) == AIMM){
670                 rc = inf >> 8 & 0xf;
671         imm:
672                 switch(rc){
673                 case 0:
674                         rc = fetch8(0); if(rc < 0) return -1;
675                         step.imm = rc;
676                         step.flags |= INSIMM8;
677                         break;
678                 case 2:
679                         switch(step.osz){
680                         case 2:
681                                 rc = fetch16(0); if(rc < 0) return -1;
682                                 step.imm = rc;
683                                 step.flags |= INSIMM16;
684                                 break;
685                         case 4:
686                         case 8:
687                                 vrc = fetch32(0); if(vrc < 0) return -1;
688                                 step.imm = vrc;
689                                 step.flags |= INSIMM32;
690                                 break;
691                         }
692                         break;
693                 default:
694                         vmerror("x86step: grab: immediate size=%d, shouldn't happen", rc);
695                         giveup();
696                         return -1;
697                 }
698         }else if((u8int)(inf >> 16 & 0xf0) == AIMM){
699                 rc = inf >> 16 & 0xf;
700                 goto imm;
701         }
702         if(((u8int)(inf >> 8) & 0xf0) == AOb || (u8int)(inf >> 16 & 0xf0) == AOb)
703                 switch(step.asz){
704                 case 2:
705                         rc = fetch16(0); if(rc < 0) return -1;
706                         step.disp = rc;
707                         step.flags |= INSDISP16;
708                         break;
709                 case 4:
710                         vrc = fetch32(0); if(vrc < 0) return -1;
711                         step.disp = vrc;
712                         step.flags |= INSDISP32;
713                         break;
714                 case 8:
715                         if(fetch64(0, (uvlong *) &step.disp) < 0) return -1;
716                         step.flags |= INSDISP64;
717                         break;                  
718                 }
719         step.inf = inf;
720         return 0;
721 }
722
723 static void
724 decreg(Oper *o, int n, int sz)
725 {
726         o->type = OPREG;
727         o->sz = sz;
728         if(sz == 1 && n >= 4){
729                 o->addr = n ^ 0x14;
730                 o->val = (u8int)(rget(x86reg[n&3]) >> 8);
731         }else{
732                 o->addr = n;
733                 o->val = rgetsz(x86reg[n], sz);
734         }
735 }
736
737 static void
738 decmodrm(Oper *o, int sz)
739 {
740         u8int mod, m;
741         
742         mod = step.modrm >> 6;
743         m = step.modrm & 7;
744         if(mod == 3){
745                 decreg(o, m, sz);
746                 return;
747         }
748         o->type = OPMEM;
749         o->sz = sz;
750         if(step.asz == 2){
751                 switch(m){
752                 case 0: o->addr = rget(RBX) + rget(RSI); break;
753                 case 1: o->addr = rget(RBX) + rget(RDI); break;
754                 case 2: o->addr = rget(RBP) + rget(RSI); break;
755                 case 3: o->addr = rget(RBX) + rget(RDI); break;
756                 case 4: o->addr = rget(RSI); break;
757                 case 5: o->addr = rget(RDI); break;
758                 case 6: o->addr = mod == 0 ? 0 : rget(RBP); break;
759                 case 7: o->addr = rget(RBX); break;
760                 }
761                 o->addr = (u16int)(o->addr + step.disp);
762                 if(step.seg < 0)
763                         if(m == 6 && mod != 0)
764                                 step.seg = SEGSS;
765                         else
766                                 step.seg = SEGDS;
767                 return;
768         }
769         if(m != 4){
770                 if((step.modrm & 0xc7) == 5)
771                         o->addr = 0;
772                 else
773                         o->addr = rget(x86reg[m]);
774                 o->addr = (u32int)(o->addr + step.disp);
775                 if(step.seg < 0)
776                         if(m == 5 && mod != 0)
777                                 step.seg = SEGSS;
778                         else
779                                 step.seg = SEGDS; 
780                 return;
781         }
782         if((step.sib >> 3 & 7) != 4)
783                 o->addr = rget(x86reg[step.sib >> 3 & 7]);
784         else
785                 o->addr = 0;
786         o->addr <<= step.sib >> 6;
787         if((step.sib & 7) != 5 || mod != 0)
788                 o->addr += rget(x86reg[step.sib & 7]);
789         o->addr = (u32int)(o->addr + step.disp);
790         if(step.seg < 0)
791                 if((step.sib & 7) == 4 || (step.sib & 7) == 5 && mod != 0)
792                         step.seg = SEGSS;
793                 else
794                         step.seg = SEGDS;
795 }
796
797 static int
798 parseoper(void)
799 {
800         int i;
801         u8int f;
802         Oper *o;
803         u8int sizes[4] = {1, step.osz, step.osz == 8 ? 4 : step.osz, 2};
804         
805         for(i = 0; i < 2; i++){
806                 f = step.inf >> 8 * (i + 1);
807                 o = &step.op[i];
808                 switch(f & 0xf0){
809                 case AGPRb:
810                 case AGPRv:
811                 case AGPRz:
812                         o->type = OPREG;
813                         o->addr = f & 0xf;
814                         o->val = rget(x86reg[f & 0xf]);
815                         o->sz = sizes[(f >> 4) - 1];
816                         break;
817                 case ASEG:
818                         o->type = OPSEG;
819                         o->addr = f & 0xf;
820                         o->val = rget(x86segreg[f & 0xf]);
821                         o->sz = 2;
822                         break;
823                 case AOb:
824                         o->type = OPMEM;
825                         o->addr = step.disp;
826                         o->sz = sizes[f & 0xf];
827                         if(step.seg < 0)
828                                 step.seg = SEGDS;
829                         break;
830                 case AIMM:
831                         o->type = OPIMM;
832                         o->val = step.imm;
833                         o->sz = sizes[f & 0xf];
834                         break;
835                 case AEb:
836                         decmodrm(o, sizes[f & 0xf]);
837                         break;
838                 case A1:
839                         o->type = OPIMM;
840                         o->val = 1;
841                         o->sz = 1;
842                         break;
843                 case AGb:
844                         decreg(o, step.modrm >> 3 & 7, sizes[f & 0xf]);
845                         break;
846                 }
847         }
848         return 0;
849 }
850
851 static int
852 opwrite(Oper *o, uvlong v)
853 {
854         char *n;
855         
856         switch(o->type){
857         case OPREG:
858                 n = x86reg[o->addr & 0xf];
859                 if((o->addr & 0x10) != 0)
860                         rset(n, rget(n) & ~0xff00ULL | (u8int)v << 8);
861                 else
862                         rsetsz(n, v, o->sz);
863                 return 0;
864         case OPMEM:
865                 if(x86access(step.seg, o->addr, step.asz, &v, o->sz, ACCW, &step.tlb) < 0)
866                         return -1;
867                 return 0;
868         case OPSEG:
869                 giveup();
870                 return -1;
871         default:
872                 vmerror("x86step: opwrite: unhandled o->type==%d, shouldn't happen", o->type);
873                 giveup();
874                 return -1;
875         }
876 }
877
878 static int
879 opread(Oper *o, uvlong *v)
880 {
881         switch(o->type){
882         case OPREG:
883         case OPSEG:
884         case OPIMM:
885                 *v = o->val;
886                 return 0;
887         case OPMEM:
888                 if(x86access(step.seg, o->addr, step.asz, v, o->sz, ACCR, &step.tlb) < 0)
889                         return -1;
890                 return 0;
891         default:
892                 vmerror("x86step: opread: unhandled o->type==%d, shouldn't happen", o->type);
893                 giveup();
894                 return -1;
895         }
896 }
897
898 static vlong
899 alu(int op, vlong a, int asz, vlong b, int bsz, uvlong *flags)
900 {
901         vlong c;
902         vlong amsk, sbit;
903         u32int flout;
904         u8int p;
905         
906         flout = 0;
907         amsk = (-1ULL)>>64-8*asz;
908         sbit = 1<<8*asz-1;
909         b = b << 64 - 8*bsz >> 64 - 8*bsz;
910         switch(op){
911         case OADD:
912         case OADC:
913                 c = (a & amsk) + (b & amsk);
914                 if(op == OADC) c += *flags & 1;
915                 if((~(a ^ b) & (a ^ c) & 1<<sbit) != 0) flout |= OF;
916                 if((a & 0xf) + (b & 0xf) >= 0x10) flout |= AF;
917                 goto addsub;
918         case OSUB:
919         case OSBB:
920         case OCMP:
921                 c = (a & amsk) - (b & amsk);
922                 if(op == OSBB) c -= *flags & 1;
923                 if(((a ^ b) & (a ^ c) & 1<<sbit) != 0) flout |= OF;
924                 if((a & 0xf) < (b & 0xf)) flout |= AF;
925         addsub:
926                 if((c & ~amsk) != 0) flout |= CF;
927         logic:
928                 if((c & 1<<sbit) != 0) flout |= SF;
929                 if((c & amsk) == 0) flout |= ZF;
930                 p = c;
931                 if(0x69966996 << (p ^ p >> 4) < 0) flout |= PF;
932                 break;
933         case OAND: c = a & b; goto logic;
934         case OOR: c = a | b; goto logic;
935         case OXOR: c = a ^ b; goto logic;
936         default:
937                 vmerror("x86step: alu: unhandled case op==%d, shouldn't happen", op);
938                 return 0;
939         }
940         *flags ^= (*flags ^ flout) & (CF|SF|ZF|OF|AF|PF);
941         return c & amsk;
942 }
943
944 static int
945 opcstring(void)
946 {
947         int sz, srcseg, rc, inc;
948         uvlong srcaddr, dstaddr;
949         uvlong v;
950         uvlong cx;
951         char buf[16];
952         
953         if((step.opcode & 1) != 0)
954                 sz = step.osz;
955         else
956                 sz = 1;
957         srcseg = step.seg >= 0 ? step.seg : SEGDS;
958         srcaddr = rget(RSI);
959         dstaddr = rget(RDI);
960         if((step.flags & INSREP) != 0)
961                 cx = rgetsz(RCX, step.asz);
962         else
963                 cx = 1;
964         if((rget(RFLAGS) & 0x400) != 0)
965                 inc = -sz;
966         else
967                 inc = sz;
968
969         rc = 1;
970         switch((u8int)step.inf){
971         case OLODS:
972                 for(; cx > 0; cx--){
973                         if(x86access(srcseg, srcaddr, step.asz, &v, sz, ACCR, &step.tlb) < 0){
974                                 rc = 0;
975                                 break;
976                         }
977                         rsetsz(RAX, v, sz);
978                         srcaddr += inc;
979                 }
980                 break;
981         case OSTOS:
982                 v = rget(RAX);
983                 for(; cx > 0; cx--){
984                         if(x86access(SEGES, dstaddr, step.asz, &v, sz, ACCW, &step.tlb) < 0){
985                                 rc = 0;
986                                 break;
987                         }
988                         dstaddr += inc;
989                 }
990                 break;
991         case OMOVS:
992                 for(; cx > 0; cx--){
993                         if(x86access(srcseg, srcaddr, step.asz, &v, sz, ACCR, &step.tlb) < 0 ||
994                            x86access(SEGES, dstaddr, step.asz, &v, sz, ACCW, &step.tlb) < 0){
995                                 rc = 0;
996                                 break;
997                         }
998                         srcaddr += inc;
999                         dstaddr += inc;
1000                 }
1001                 break;
1002         default:
1003                 vmerror("x86step: opcstring: unhandled case %s", enumconv((u8int)step.inf, buf, onames));
1004                 giveup();
1005                 return 0;
1006         }
1007         rsetsz(RSI, srcaddr, step.asz);
1008         rsetsz(RDI, dstaddr, step.asz);
1009
1010         if((step.flags & (INSREP|INSREPNE)) != 0)
1011                 rsetsz(RCX, cx, step.asz);
1012         return rc;
1013 }
1014
1015 static int
1016 opcstack(void)
1017 {
1018         uvlong val, sp;
1019         int spsz;
1020         
1021         /* todo: get stack pointer size from stack segment */
1022         spsz = step.mode;
1023         sp = rgetsz(RSP, spsz);
1024         switch((u8int)step.inf){
1025         case OPUSH:
1026                 if(opread(&step.op[0], &val) < 0) return 0;
1027                 if(step.op[0].sz < step.osz && step.op[0].type != OPSEG)
1028                         val = (vlong)val << 64 - 8 * step.op[0].sz >> 64 - 8 * step.op[0].sz;
1029                 sp -= step.osz;
1030                 if(x86access(SEGSS, sp, spsz, &val, step.osz, ACCW, &step.tlb) < 0) return 0;
1031                 break;
1032         case OPOP:
1033                 if(x86access(SEGSS, sp, spsz, &val, step.osz, ACCR, &step.tlb) < 0) return 0;
1034                 if(opwrite(&step.op[0], val) < 0) return 0;
1035                 sp += step.osz;
1036                 break;
1037         default:
1038                 vmerror("x86step: stack: unhandled case op==%d, shouldn't happen", (u8int)step.inf);
1039                 return 0;
1040         }
1041         rsetsz(RSP, sp, spsz);
1042         return 1;
1043 }
1044
1045 int
1046 x86step(void)
1047 {
1048         uvlong val, valb;
1049         uvlong rflags;
1050         char buf[16];
1051         
1052         memset(&step, 0, sizeof(step));
1053         step.seg = -1;
1054         step.pc = rget(RPC);
1055         step.npc = step.pc;
1056         step.mode = 4;
1057         step.asz = step.osz = step.mode;
1058         if(grab() < 0 || parseoper() < 0)
1059                 return 0;
1060 //      print("flags=%#ux modrm=%#ux sib=%#ux disp=%#ullx imm=%#ullx\n", step.flags, step.modrm, step.sib, step.disp, step.imm);
1061 //      print("op0: type=%#ux addr=%#ullx val=%#ullx sz=%d\n", , );
1062 //      print("op1: type=%#ux addr=%#ullx val=%#ullx sz=%d\n", step.op[1].type, step.op[1].addr, step.op[1].val, step.op[1].sz);
1063         print("%#.*p %s (%#ux,%d,%#ullx,%#ullx) (%#ux,%d,%#ullx,%#ullx) si %#llux di %#llux\n", 2*step.mode, step.pc, enumconv((u8int)step.inf,buf,onames), step.op[0].type, step.op[0].sz, (uvlong)step.op[0].addr, step.op[0].val, step.op[1].type, step.op[1].sz, (uvlong)step.op[1].addr, step.op[1].val, rget(RSI), rget(RDI));
1064         switch((u8int)step.inf){
1065         case OMOV:
1066                 if((step.flags & (INSREP|INSREPNE|INSLOCK)) != 0) {giveup(); return 0;}
1067                 if(opread(&step.op[1], &val) < 0) return 0;
1068                 if(opwrite(&step.op[0], val) < 0) return 0;
1069                 return 1;
1070         case OSTOS: case OLODS: case OMOVS:
1071                 if((step.flags & (INSREPNE|INSLOCK)) != 0) {giveup(); return 0;}
1072                 return opcstring();
1073         case OADD: case OADC: case OSUB: case OSBB: case OCMP: case OAND: case OOR: case OXOR:
1074                 if((step.flags & (INSREP|INSREPNE)) != 0) {giveup(); return 0;}
1075                 if(opread(&step.op[0], &val) < 0) return 0;
1076                 if(opread(&step.op[1], &valb) < 0) return 0;
1077                 rflags = rget(RFLAGS);
1078                 val = alu((u8int)step.inf, val, step.op[0].sz, valb, step.op[1].sz, &rflags);
1079                 if((u8int)step.inf != OCMP && opwrite(&step.op[0], val) < 0) return 0;
1080                 rset(RFLAGS, rflags);
1081                 return 1;
1082         case OPUSH: case OPOP:
1083                 if((step.flags & (INSLOCK|INSREPNE|INSLOCK)) != 0) {giveup(); return 0;}
1084                 return opcstack();
1085         default:
1086                 vmerror("x86step: unhandled case %s", enumconv((u8int)step.inf, buf, onames));
1087                 giveup();
1088                 return 0;
1089         }
1090 }