10 typedef struct VMemReq VMemReq;
20 translateflat(uintptr va, uintptr *pa, int *perm)
22 if(sizeof(uintptr) != 4 && va >> 32 != 0) return 0;
26 if(perm != 0) *perm = -1;
31 translate32(uintptr va, uintptr *pa, int *perm)
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);
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);
56 translatepae(uintptr, uintptr *, int *)
58 vmerror("PAE translation not implemented");
63 translate64(uintptr, uintptr *, int *)
65 vmerror("long mode translation not implemented");
70 translator(void))(uintptr, uintptr *, int *)
72 uintptr cr0, cr4, efer;
74 cr0 = rget("cr0real");
75 if((cr0 & Cr0Pg) == 0)
78 if((efer & EferLme) != 0)
80 cr4 = rget("cr4real");
81 if((cr4 & Cr4Pae) != 0)
90 uintptr va, pa, n, ok, pok;
92 uintptr (*trans)(uintptr, uintptr *, int *);
101 trans = translator();
103 ok = trans(va, &pa, nil);
109 if(ok > pok) ok = pok;
118 req->rc = req->len - n;
123 vmemread(void *buf, uintptr len, uintptr va)
127 memset(&req, 0, sizeof(VMemReq));
133 sendnotif(vmemread0, &req);
139 vmemwrite(void *buf, uintptr len, uintptr va)
143 memset(&req, 0, sizeof(VMemReq));
149 sendnotif(vmemread0, &req);
155 x86access(int seg, uintptr addr0, int asz, uvlong *val, int sz, int acc, TLB *tlb)
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"};
163 uintptr addr, base, szmax;
171 case 2: addr0 = (u16int)addr0; break;
172 case 4: addr0 = (u32int)addr0; break;
175 vmerror("invalid asz=%d in x86access", asz);
178 assert(seg < SEGMAX && (u8int)acc <= ACCX);
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;
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){
191 if((acc & ACCSAFE) == 0){
198 szmax = (1ULL<<48) - addr;
202 limit = rget(limitr[seg]);
203 perm = rget(permr[seg]);
204 if((perm & 0xc) == 0x4){
205 if((u32int)(addr + sz - 1) < addr || addr <= limit)
207 szmax = (u32int)-addr;
209 if((u64int)addr + sz - 1 >= limit){
211 if((acc & ACCSAFE) == 0){
212 vmdebug("limit fault");
213 postexc(seg == SEGSS ? "#ss" : "#gp", 0);
217 szmax = limit - addr + 1;
219 if((perm & 0x10080) != 0x80)
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;
226 base = rget(baser[seg]);
227 addr = (u32int)(addr + base);
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);
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);
242 if((cpl == 3 || wp) && (u8int)acc == ACCW && (pperm & 2) == 0)
244 if(cpl == 3 && (pperm & 4) == 0)
246 if(i == 0 && l < szmax) szmax = l;
247 while(i < sz && l-- > 0)
252 if(r == nil || pa[0]+sz > r->end) goto slow;
253 ptr = (uchar*)r->v + (pa[0] - r->start);
256 if(l < szmax) szmax = l;
259 tlb->acc = (u8int)acc;
261 tlb->end = addr0 + szmax;
263 tlb->base = ptr - addr0;
264 tlb->pabase = pa[0] - addr0;
268 r->mmio(pa[0], val, sz, (u8int)acc == ACCW);
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;
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;
289 for(i = 0; i < sz; i++){
292 vmerror("x86access: access to unmapped address %#p", pa[i]);
293 else if(acc == ACCW){
296 r->mmio(pa[i], &tval, 1, 1);
298 PUT8(r->v, pa[i] - r->start, tval);
301 r->mmio(pa[i], &tval, 1, 0);
303 tval = GET8(r->v, pa[i] - r->start);
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,
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"
329 #define enumconv(x,buf,tab) ((x)<nelem(tab)?(tab)[x]:(sprint(buf,"%d",(x)),buf))
334 1 v short/long/vlong (16-bit,32-bit,64-bit mode)
341 A1 = 1, /* constant 1 */
343 /* general purpose registers with size+1 in high nibble */
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,
351 ASEG = 0x40, ACS = 0x40, ADS = 0x41, AES = 0x42, AFS = 0x43, AGS = 0x44, ASS = 0x45,
353 /* below has valid size in lower nibble */
355 AOb = 0x50, AOv = 0x51,
358 AIb = 0x70, AIz = 0x72,
359 /* below involves modrm */
361 AEb = 0x80, AEv = 0x81,
362 AGb = 0x90, AGv = 0x91,
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",
374 /* typically b is dst and c is src */
375 #define O(a,b,c) ((a)|(b)<<8|(c)<<16)
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,
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),
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*/,
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*/,
391 /*4*/ 0, 0, 0, 0, 0, 0, 0, 0, /* rex prefixes */
392 0, 0, 0, 0, 0, 0, 0, 0,
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),
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,
400 /*7*/ 0, 0, 0, 0, 0, 0, 0, 0, /* jumps */
401 0, 0, 0, 0, 0, 0, 0, 0,
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,
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*/,
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,
412 /*B*/ 0, 0, 0, 0, 0, 0, 0, 0, /* move immediate to register */
413 0, 0, 0, 0, 0, 0, 0, 0,
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*/,
418 /*D*/ OEX, OEX, OEX, OEX, 0/*AAM*/, 0/*AAD*/, 0, OXLAT,
419 0, 0, 0, 0, 0, 0, 0, 0, /* fpu */
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*/,
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,
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};
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) */
450 enum { OPNONE, OPREG, OPSEG, OPIMM, OPMEM } type;
458 u8int opcode; /* first byte after the prefixes */
478 /* INSIMM64 = 0x4000, not yet */
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);
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);
509 step.bytes[step.nbytes++] = v;
518 if(r0 = fetch8(acc), r0 < 0) return -1;
519 if(r1 = fetch8(acc), r1 < 0) return -1;
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;
536 fetch64(int acc, uvlong *p)
540 if(r0 = fetch32(acc), r0 < 0) return -1;
541 if(r1 = fetch32(acc), r1 < 0) return -1;
547 machread(int, void *vb, long n, vlong 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);
566 extern Machdata i386mach;
571 setmap(m, -1, 0, -1, 0, "text");
572 m->seg[0].read = machread;
575 e = buf + sizeof(buf);
576 while(fetch8(ACCSAFE) >= 0)
578 if(rc = i386mach.das(m, step.pc, 0, buf, sizeof(buf)), rc >= 0){
580 p = seprint(p, e, " # ");
583 for(i = 0; i < rc; i++)
584 p = seprint(p, e, "%.2x ", step.bytes[i]);
585 vmerror("x86step: unimplemented instruction %s", buf);
599 if(op < 0) return -1;
601 if(inf == 0){ giveup(); return -1; }
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;
611 if((u8int)(inf >> 8) >= AMODRM || (u8int)(inf >> 16) >= AMODRM || inf == OEX){
613 if(rc < 0) return -1;
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;
619 step.flags |= INSSIB;
621 switch(step.modrm >> 6){
623 rc = fetch8(0); if(rc < 0) return -1;
624 step.disp = (s8int)rc;
625 step.flags |= INSDISP8;
628 if((step.modrm & 7) != (step.asz == 2) + 5 && (step.sib & 7) != 5)
633 rc = fetch16(0); if(rc < 0) return -1;
634 step.disp = (s16int)rc;
635 step.flags |= INSDISP16;
637 vrc = fetch32(0); if(vrc < 0) return -1;
638 step.disp = (s32int)vrc;
639 step.flags |= INSDISP32;
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;
664 if(tab == nil || (inf = tab[step.modrm >> 3 & 7]) == 0){
669 if(((u8int)(inf >> 8) & 0xf0) == AIMM){
674 rc = fetch8(0); if(rc < 0) return -1;
676 step.flags |= INSIMM8;
681 rc = fetch16(0); if(rc < 0) return -1;
683 step.flags |= INSIMM16;
687 vrc = fetch32(0); if(vrc < 0) return -1;
689 step.flags |= INSIMM32;
694 vmerror("x86step: grab: immediate size=%d, shouldn't happen", rc);
698 }else if((u8int)(inf >> 16 & 0xf0) == AIMM){
699 rc = inf >> 16 & 0xf;
702 if(((u8int)(inf >> 8) & 0xf0) == AOb || (u8int)(inf >> 16 & 0xf0) == AOb)
705 rc = fetch16(0); if(rc < 0) return -1;
707 step.flags |= INSDISP16;
710 vrc = fetch32(0); if(vrc < 0) return -1;
712 step.flags |= INSDISP32;
715 if(fetch64(0, (uvlong *) &step.disp) < 0) return -1;
716 step.flags |= INSDISP64;
724 decreg(Oper *o, int n, int sz)
728 if(sz == 1 && n >= 4){
730 o->val = (u8int)(rget(x86reg[n&3]) >> 8);
733 o->val = rgetsz(x86reg[n], sz);
738 decmodrm(Oper *o, int sz)
742 mod = step.modrm >> 6;
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;
761 o->addr = (u16int)(o->addr + step.disp);
763 if(m == 6 && mod != 0)
770 if((step.modrm & 0xc7) == 5)
773 o->addr = rget(x86reg[m]);
774 o->addr = (u32int)(o->addr + step.disp);
776 if(m == 5 && mod != 0)
782 if((step.sib >> 3 & 7) != 4)
783 o->addr = rget(x86reg[step.sib >> 3 & 7]);
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);
791 if((step.sib & 7) == 4 || (step.sib & 7) == 5 && mod != 0)
803 u8int sizes[4] = {1, step.osz, step.osz == 8 ? 4 : step.osz, 2};
805 for(i = 0; i < 2; i++){
806 f = step.inf >> 8 * (i + 1);
814 o->val = rget(x86reg[f & 0xf]);
815 o->sz = sizes[(f >> 4) - 1];
820 o->val = rget(x86segreg[f & 0xf]);
826 o->sz = sizes[f & 0xf];
833 o->sz = sizes[f & 0xf];
836 decmodrm(o, sizes[f & 0xf]);
844 decreg(o, step.modrm >> 3 & 7, sizes[f & 0xf]);
852 opwrite(Oper *o, uvlong v)
858 n = x86reg[o->addr & 0xf];
859 if((o->addr & 0x10) != 0)
860 rset(n, rget(n) & ~0xff00ULL | (u8int)v << 8);
865 if(x86access(step.seg, o->addr, step.asz, &v, o->sz, ACCW, &step.tlb) < 0)
872 vmerror("x86step: opwrite: unhandled o->type==%d, shouldn't happen", o->type);
879 opread(Oper *o, uvlong *v)
888 if(x86access(step.seg, o->addr, step.asz, v, o->sz, ACCR, &step.tlb) < 0)
892 vmerror("x86step: opread: unhandled o->type==%d, shouldn't happen", o->type);
899 alu(int op, vlong a, int asz, vlong b, int bsz, uvlong *flags)
907 amsk = (-1ULL)>>64-8*asz;
909 b = b << 64 - 8*bsz >> 64 - 8*bsz;
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;
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;
926 if((c & ~amsk) != 0) flout |= CF;
928 if((c & 1<<sbit) != 0) flout |= SF;
929 if((c & amsk) == 0) flout |= ZF;
931 if(0x69966996 << (p ^ p >> 4) < 0) flout |= PF;
933 case OAND: c = a & b; goto logic;
934 case OOR: c = a | b; goto logic;
935 case OXOR: c = a ^ b; goto logic;
937 vmerror("x86step: alu: unhandled case op==%d, shouldn't happen", op);
940 *flags ^= (*flags ^ flout) & (CF|SF|ZF|OF|AF|PF);
947 int sz, srcseg, rc, inc;
948 uvlong srcaddr, dstaddr;
953 if((step.opcode & 1) != 0)
957 srcseg = step.seg >= 0 ? step.seg : SEGDS;
960 if((step.flags & INSREP) != 0)
961 cx = rgetsz(RCX, step.asz);
964 if((rget(RFLAGS) & 0x400) != 0)
970 switch((u8int)step.inf){
973 if(x86access(srcseg, srcaddr, step.asz, &v, sz, ACCR, &step.tlb) < 0){
984 if(x86access(SEGES, dstaddr, step.asz, &v, sz, ACCW, &step.tlb) < 0){
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){
1003 vmerror("x86step: opcstring: unhandled case %s", enumconv((u8int)step.inf, buf, onames));
1007 rsetsz(RSI, srcaddr, step.asz);
1008 rsetsz(RDI, dstaddr, step.asz);
1010 if((step.flags & (INSREP|INSREPNE)) != 0)
1011 rsetsz(RCX, cx, step.asz);
1021 /* todo: get stack pointer size from stack segment */
1023 sp = rgetsz(RSP, spsz);
1024 switch((u8int)step.inf){
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;
1030 if(x86access(SEGSS, sp, spsz, &val, step.osz, ACCW, &step.tlb) < 0) return 0;
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;
1038 vmerror("x86step: stack: unhandled case op==%d, shouldn't happen", (u8int)step.inf);
1041 rsetsz(RSP, sp, spsz);
1052 memset(&step, 0, sizeof(step));
1054 step.pc = rget(RPC);
1057 step.asz = step.osz = step.mode;
1058 if(grab() < 0 || parseoper() < 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){
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;
1070 case OSTOS: case OLODS: case OMOVS:
1071 if((step.flags & (INSREPNE|INSLOCK)) != 0) {giveup(); return 0;}
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);
1082 case OPUSH: case OPOP:
1083 if((step.flags & (INSLOCK|INSREPNE|INSLOCK)) != 0) {giveup(); return 0;}
1086 vmerror("x86step: unhandled case %s", enumconv((u8int)step.inf, buf, onames));