about summary refs log tree commit diff stats
path: root/src/emu/x64run.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/x64run.c')
-rw-r--r--src/emu/x64run.c468
1 files changed, 370 insertions, 98 deletions
diff --git a/src/emu/x64run.c b/src/emu/x64run.c
index f064dfd1..6465ab5e 100644
--- a/src/emu/x64run.c
+++ b/src/emu/x64run.c
@@ -49,9 +49,10 @@ int Run(x64emu_t *emu, int step)
     int step = 0;
     #endif
     uintptr_t addr = R_RIP;
-    rex_t rex;
+    rex_t rex = {0};
     int rep;    // 0 none, 1=F2 prefix, 2=F3 prefix
     int unimp = 0;
+    int is32bits = (emu->segs[_CS]==0x23);
 
     if(emu->quit)
         return 0;
@@ -62,7 +63,7 @@ int Run(x64emu_t *emu, int step)
         return 0;
     }
     //ref opcode: http://ref.x64asm.net/geek32.html#xA1
-    printf_log(LOG_DEBUG, "Run X86 (%p), RIP=%p, Stack=%p\n", emu, (void*)addr, (void*)R_RSP);
+    printf_log(LOG_DEBUG, "Run X86 (%p), RIP=%p, Stack=%p is32bits=%d\n", emu, (void*)addr, (void*)R_RSP, is32bits);
 
 x64emurun:
 #ifndef TEST_INTERPRETER
@@ -86,13 +87,15 @@ x64emurun:
             rep = opcode-0xF1;
             opcode = F8;
         }
-        while((opcode==0x3E))   //Branch Taken Hint ignored
+        while((opcode==0x3E) || (opcode==0x26))   //Branch Taken Hint ignored
             opcode = F8;
         rex.rex = 0;
-        while(opcode>=0x40 && opcode<=0x4f) {
-            rex.rex = opcode;
-            opcode = F8;
-        }
+        rex.is32bits = is32bits;
+        if(!is32bits)
+            while(opcode>=0x40 && opcode<=0x4f) {
+                rex.rex = opcode;
+                opcode = F8;
+            }
 
         switch(opcode) {
 
@@ -142,6 +145,21 @@ x64emurun:
             break;
 
         GO(0x00, add)                   /* ADD 0x00 -> 0x05 */
+        case 0x06:                      /* PUSH ES */
+            if(!rex.is32bits) {
+                unimp = 1;
+                goto fini;
+            }
+            Push32(emu, emu->segs[_ES]);  // even if a segment is a 16bits, a 32bits push/pop is done
+            break;
+        case 0x07:                      /* POP ES */
+            if(!rex.is32bits) {
+                unimp = 1;
+                goto fini;
+            }
+            emu->segs[_ES] = Pop32(emu);    // no check, no use....
+            emu->segs_serial[_ES] = 0;
+            break;
         GO(0x08, or)                    /*  OR 0x08 -> 0x0D */
         case 0x0F:                      /* More instructions */
             switch(rep) {
@@ -193,7 +211,24 @@ x64emurun:
         GO(0x30, xor)                   /* XOR 0x30 -> 0x35 */
         #undef GO
 
+        case 0x1E:                      /* PUSH DS */
+            if(!rex.is32bits) {
+                unimp = 1;
+                goto fini;
+            }
+            Push32(emu, emu->segs[_DS]);  // even if a segment is a 16bits, a 32bits push/pop is done
+            break;
+        case 0x1F:                      /* POP DS */
+            if(!rex.is32bits) {
+                unimp = 1;
+                goto fini;
+            }
+            emu->segs[_DS] = Pop32(emu);    // no check, no use....
+            emu->segs_serial[_DS] = 0;
+            break;
+
 	    case 0x2E:	    /* segments are ignored */
+        case 0x26:
         case 0x36:          /* SS: (ignored) */
             break;
 
@@ -236,13 +271,39 @@ x64emurun:
             else
                 cmp32(emu, R_EAX, F32);
             break;
-
+        case 0x40:
+        case 0x41:
+        case 0x42:
+        case 0x43:
+        case 0x44:
+        case 0x45:
+        case 0x46:
+        case 0x47:                      /* INC Reg (32bits only)*/
+            tmp8u = opcode&7;
+            emu->regs[tmp8u].dword[0] = inc32(emu, emu->regs[tmp8u].dword[0]);
+            break;
+        case 0x48:
+        case 0x49:
+        case 0x4A:
+        case 0x4B:
+        case 0x4C:
+        case 0x4D:
+        case 0x4E:
+        case 0x4F:                      /* DEC Reg (32bits only)*/
+            tmp8u = opcode&7;
+            emu->regs[tmp8u].dword[0] = dec32(emu, emu->regs[tmp8u].dword[0]);
+            break;
         case 0x54:                      /* PUSH ESP */
             if(rex.b)
-                Push(emu, R_R12);
+                Push64(emu, R_R12);
             else {
-                tmp64u = R_RSP;
-                Push(emu, tmp64u);
+                if(rex.is32bits) {
+                    tmp32u = R_ESP;
+                    Push32(emu, tmp32u);
+                } else {
+                    tmp64u = R_RSP;
+                    Push64(emu, tmp64u);
+                }
             }
             break;
         case 0x50:
@@ -253,7 +314,10 @@ x64emurun:
         case 0x56:
         case 0x57:                      /* PUSH Reg */
             tmp8u = (opcode&7)+(rex.b<<3);
-            Push(emu, emu->regs[tmp8u].q[0]);
+            if(rex.is32bits)
+                Push32(emu, emu->regs[tmp8u].dword[0]);
+            else
+                Push64(emu, emu->regs[tmp8u].q[0]);
             break;
         case 0x58:
         case 0x59:
@@ -264,20 +328,57 @@ x64emurun:
         case 0x5E:
         case 0x5F:                      /* POP Reg */
             tmp8u = (opcode&7)+(rex.b<<3);
-            emu->regs[tmp8u].q[0] = Pop(emu);
+            emu->regs[tmp8u].q[0] = is32bits?Pop32(emu):Pop64(emu);
+            break;
+        case 0x60:                      /* PUSHAD */
+            if(rex.is32bits) {
+                tmp32u = R_ESP;
+                Push32(emu, R_EAX);
+                Push32(emu, R_ECX);
+                Push32(emu, R_EDX);
+                Push32(emu, R_EBX);
+                Push32(emu, tmp32u);
+                Push32(emu, R_EBP);
+                Push32(emu, R_ESI);
+                Push32(emu, R_EDI);
+            } else {
+                unimp = 1;
+                goto fini;
+            }
+            break;
+        case 0x61:                      /* POPAD */
+            if(rex.is32bits) {
+                R_EDI = Pop32(emu);
+                R_ESI = Pop32(emu);
+                R_EBP = Pop32(emu);
+                R_ESP+=4;   // POP ESP
+                R_EBX = Pop32(emu);
+                R_EDX = Pop32(emu);
+                R_ECX = Pop32(emu);
+                R_EAX = Pop32(emu);
+            } else {
+                unimp = 1;
+                goto fini;
+            }
             break;
 
         case 0x63:                      /* MOVSXD Gd,Ed */
             nextop = F8;
             GETED(0);
             GETGD;
-            if(rex.w)
-                GD->sq[0] = ED->sdword[0];
-            else
-                if(MODREG)
-                    GD->q[0] = ED->dword[0];    // not really a sign extension
+            if(rex.is32bits) {
+                // ARPL here
+                // faking to always happy...
+                SET_FLAG(F_ZF);
+            } else {
+                if(rex.w)
+                    GD->sq[0] = ED->sdword[0];
                 else
-                    GD->sdword[0] = ED->sdword[0];  // meh?
+                    if(MODREG)
+                        GD->q[0] = ED->dword[0];    // not really a sign extension
+                    else
+                        GD->sdword[0] = ED->sdword[0];  // meh?
+            }
             break;
         case 0x64:                      /* FS: prefix */
             #ifdef TEST_INTERPRETER
@@ -292,6 +393,7 @@ x64emurun:
                 R_RIP = addr;
                 goto fini;
             }
+            is32bits = (emu->segs[_CS]==0x23);
             #endif
             break;
         case 0x65:                      /* GS: prefix */
@@ -307,6 +409,7 @@ x64emurun:
                 R_RIP = addr;
                 goto fini;
             }
+            is32bits = (emu->segs[_CS]==0x23);
             #endif
             break;
         case 0x66:                      /* 16bits prefix */
@@ -340,7 +443,10 @@ x64emurun:
             #endif
             break;
         case 0x68:                      /* Push Id */
-            Push(emu, F32S64);
+            if(rex.is32bits)
+                Push32(emu, F32);
+            else
+                Push64(emu, F32S64);
             break;
         case 0x69:                      /* IMUL Gd,Ed,Id */
             nextop = F8;
@@ -353,8 +459,13 @@ x64emurun:
                 GD->q[0] = imul32(emu, ED->dword[0], tmp64u);
             break;
         case 0x6A:                      /* Push Ib */
-            tmp64s = F8S;
-            Push(emu, (uint64_t)tmp64s);
+            if(rex.is32bits) {
+                tmp32s = F8S;
+                Push32(emu, (uint32_t)tmp32s);
+            } else {
+                tmp64s = F8S;
+                Push64(emu, (uint64_t)tmp64s);
+            }
             break;
         case 0x6B:                      /* IMUL Gd,Ed,Ib */
             nextop = F8;
@@ -367,14 +478,78 @@ x64emurun:
                 GD->q[0] = imul32(emu, ED->dword[0], (uint32_t)tmp64s);
             break;
         case 0x6C:                      /* INSB DX */
+            if(rex.is32bits) {
+                tmp32u = rep?R_ECX:1;
+                while(tmp32u--) {
+                    *(int8_t*)(R_EDI+GetESBaseEmu(emu)) = 0;   // faking port read, using explicit ES segment
+                    if(ACCESS_FLAG(F_DF))
+                        R_EDI-=1;
+                    else
+                        R_EDI+=1;
+                }
+                if(rep)
+                    R_ECX = 0;
+            } else {
+                // this is a privilege opcode in 64bits, but not in 32bits...
+                #ifndef TEST_INTERPRETOR
+                emit_signal(emu, SIGSEGV, (void*)R_RIP, 0);
+                STEP;
+                #endif
+            }
+            break;
         case 0x6D:                      /* INSL DX */
+            if(rex.is32bits) {
+                tmp32u = rep?R_ECX:1;
+                while(tmp32u--) {
+                    *(int32_t*)(R_EDI+GetESBaseEmu(emu)) = 0;   // faking port read, using explicit ES segment
+                    if(ACCESS_FLAG(F_DF))
+                        R_EDI-=4;
+                    else
+                        R_EDI+=4;
+                }
+                if(rep)
+                    R_ECX = 0;
+            } else {
+                // this is a privilege opcode in 64bits, but not in 32bits...
+                #ifndef TEST_INTERPRETOR
+                emit_signal(emu, SIGSEGV, (void*)R_RIP, 0);
+                STEP;
+                #endif
+            }
+            break;
         case 0x6E:                      /* OUTSB DX */
+            if(rex.is32bits) {
+                // faking port write, using explicit ES segment
+                if(ACCESS_FLAG(F_DF))
+                    R_ESI-=rep?R_ECX:1;
+                else
+                    R_ESI+=1?R_ECX:1;
+                if(rep)
+                    R_ECX = 0;
+            } else {
+                // this is a privilege opcode in 64bits, but not in 32bits...
+                #ifndef TEST_INTERPRETOR
+                emit_signal(emu, SIGSEGV, (void*)R_RIP, 0);
+                STEP;
+                #endif
+            }
+            break;
         case 0x6F:                      /* OUTSL DX */
-            // this is a privilege opcode...
-            #ifndef TEST_INTERPRETOR
-            emit_signal(emu, SIGSEGV, (void*)R_RIP, 0);
-            STEP;
-            #endif
+            if(rex.is32bits) {
+                // faking port write, using explicit ES segment
+                if(ACCESS_FLAG(F_DF))
+                    R_ESI-=(rep?R_ECX:1)*4;
+                else
+                    R_ESI+=(rep?R_ECX:1)*4;
+                if(rep)
+                    R_ECX = 0;
+            } else {
+                // this is a privilege opcode in 64bits, but not in 32bits...
+                #ifndef TEST_INTERPRETOR
+                emit_signal(emu, SIGSEGV, (void*)R_RIP, 0);
+                STEP;
+                #endif
+            }
             break;
 
         GOCOND(0x70
@@ -383,6 +558,12 @@ x64emurun:
             ,,STEP2
             )                           /* Jxx Ib */
         
+        case 0x82:
+            if(!rex.is32bits) {
+                unimp = 1;
+                goto fini;
+            }
+            // fallthru
         case 0x80:                      /* GRP Eb,Ib */
             nextop = F8;
             GETEB(1);
@@ -581,17 +762,30 @@ x64emurun:
             else
                 GD->q[0] = tmp64u&0xffffffff;
             break;
-
+        case 0x8E:                      /* MOV Seg, Ew */
+            nextop = F8;
+            GETED(0);
+            emu->segs[((nextop&0x38)>>3)] = ED->word[0];
+            emu->segs_serial[((nextop&0x38)>>3)] = 0;
+            break;
         case 0x8F:                      /* POP Ed */
             nextop = F8;
             if(MODREG) {
-                emu->regs[(nextop&7)+(rex.b<<3)].q[0] = Pop(emu);
+                emu->regs[(nextop&7)+(rex.b<<3)].q[0] = rex.is32bits?Pop32(emu):Pop64(emu);
             } else {
-                tmp64u = Pop(emu);  // this order allows handling POP [ESP] and variant
-                GETED(0);
-                R_ESP -= sizeof(void*); // to prevent issue with SEGFAULT
-                ED->q[0] = tmp64u;
-                R_ESP += sizeof(void*);
+                if(rex.is32bits) {
+                    tmp32u = Pop32(emu);  // this order allows handling POP [ESP] and variant
+                    GETED(0);
+                    R_ESP -= 4; // to prevent issue with SEGFAULT
+                    ED->dword[0] = tmp32u;
+                    R_ESP += 4;
+                } else {
+                    tmp64u = Pop64(emu);  // this order allows handling POP [ESP] and variant
+                    GETED(0);
+                    R_RSP -= sizeof(void*); // to prevent issue with SEGFAULT
+                    ED->q[0] = tmp64u;
+                    R_RSP += sizeof(void*);
+                }
             }
             break;
         case 0x90:                      /* NOP or XCHG R8, RAX*/
@@ -635,11 +829,23 @@ x64emurun:
             break;
         case 0x9C:                      /* PUSHF */
             CHECK_FLAGS(emu);
-            Push(emu, emu->eflags.x64);
+            if(rex.is32bits)
+                Push32(emu, emu->eflags.x64);
+            else
+                Push64(emu, emu->eflags.x64);
             break;
         case 0x9D:                      /* POPF */
-            emu->eflags.x64 = ((Pop(emu) & 0x3F7FD7)/* & (0xffff-40)*/ ) | 0x2; // mask off res2 and res3 and on res1
+            emu->eflags.x64 = (((rex.is32bits?Pop32(emu):Pop64(emu)) & 0x3F7FD7)/* & (0xffff-40)*/ ) | 0x2; // mask off res2 and res3 and on res1
             RESET_FLAGS(emu);
+            #ifndef TEST_INTERPRETER
+            if(ACCESS_FLAG(F_TF)) {
+                R_RIP = addr;
+                emit_signal(emu, SIGTRAP, (void*)addr, 1);
+                if(emu->quit) goto fini;
+                CLEAR_FLAG(F_TF);
+                STEP;
+            }
+            #endif
             break;
         case 0x9E:                      /* SAHF */
             CHECK_FLAGS(emu);
@@ -656,22 +862,36 @@ x64emurun:
             R_AH = (uint8_t)emu->eflags.x64;
             break;
         case 0xA0:                      /* MOV AL,Ob */
-            R_AL = *(uint8_t*)F64;
+            if(rex.is32bits)
+                R_AL = *(uint8_t*)(uintptr_t)F32;
+            else
+                R_AL = *(uint8_t*)F64;
             break;
         case 0xA1:                      /* MOV EAX,Od */
-            if(rex.w)
-                R_RAX = *(uint64_t*)F64;
-            else
-                R_RAX = *(uint32_t*)F64;
+            if(rex.is32bits)
+                R_EAX = *(int32_t*)(uintptr_t)F32;
+            else {
+                if(rex.w)
+                    R_RAX = *(uint64_t*)F64;
+                else
+                    R_RAX = *(uint32_t*)F64;
+            }
             break;
         case 0xA2:                      /* MOV Ob,AL */
-            *(uint8_t*)F64 = R_AL;
+            if(rex.is32bits)
+                *(uint8_t*)(uintptr_t)F32 = R_AL;
+            else
+                *(uint8_t*)F64 = R_AL;
             break;
         case 0xA3:                      /* MOV Od,EAX */
-            if(rex.w)
-                *(uint64_t*)F64 = R_RAX;
-            else
-                *(uint32_t*)F64 = R_EAX;
+            if(rex.is32bits)
+                *(uint32_t*)(uintptr_t)F32 = R_EAX;
+            else {
+                if(rex.w)
+                    *(uint64_t*)F64 = R_RAX;
+                else
+                    *(uint32_t*)F64 = R_EAX;
+            }
             break;
         case 0xA4:                      /* MOVSB */
             tmp8s = ACCESS_FLAG(F_DF)?-1:+1;
@@ -746,7 +966,6 @@ x64emurun:
                     R_RCX = tmp64u;
                     break;
                 default:
-                    tmp8s = ACCESS_FLAG(F_DF)?-1:+1;
                     tmp8u  = *(uint8_t*)R_RDI;
                     tmp8u2 = *(uint8_t*)R_RSI;
                     R_RDI += tmp8s;
@@ -816,14 +1035,12 @@ x64emurun:
                     break;
                 default:
                     if(rex.w) {
-                        tmp8s = ACCESS_FLAG(F_DF)?-8:+8;
                         tmp64u  = *(uint64_t*)R_RDI;
                         tmp64u2 = *(uint64_t*)R_RSI;
                         R_RDI += tmp8s;
                         R_RSI += tmp8s;
                         cmp64(emu, tmp64u2, tmp64u);
                     } else {
-                        tmp8s = ACCESS_FLAG(F_DF)?-4:+4;
                         tmp32u  = *(uint32_t*)R_RDI;
                         tmp32u2 = *(uint32_t*)R_RSI;
                         R_RDI += tmp8s;
@@ -1090,12 +1307,12 @@ x64emurun:
             break;
         case 0xC2:                      /* RETN Iw */
             tmp16u = F16;
-            addr = Pop(emu);
+            addr = rex.is32bits?Pop32(emu):Pop64(emu);
             R_RSP += tmp16u;
             STEP2
             break;
         case 0xC3:                      /* RET */
-            addr = Pop(emu);
+            addr = rex.is32bits?Pop32(emu):Pop64(emu);
             STEP2
             break;
 
@@ -1118,21 +1335,34 @@ x64emurun:
         case 0xC8:                      /* ENTER Iw,Ib */
             tmp16u = F16;
             tmp8u = (F8) & 0x1f;
-            tmp64u = R_RBP;
-            Push(emu, R_RBP);
-            R_RBP = R_RSP;
-            if (tmp8u) {
-                for (tmp8u2 = 1; tmp8u2 < tmp8u; tmp8u2++) {
-                    tmp64u -= sizeof(void*);
-                    Push(emu, *((uintptr_t*)tmp64u));
+            if(rex.is32bits) {
+                tmp64u = R_EBP;
+                Push32(emu, R_EBP);
+                R_EBP = R_ESP;
+                if (tmp8u) {
+                    for (tmp8u2 = 1; tmp8u2 < tmp8u; tmp8u2++) {
+                        tmp64u -= 4;
+                        Push32(emu, *((uint32_t*)tmp64u));
+                    }
+                    Push32(emu, R_EBP);
+                }
+            } else {
+                tmp64u = R_RBP;
+                Push64(emu, R_RBP);
+                R_RBP = R_RSP;
+                if (tmp8u) {
+                    for (tmp8u2 = 1; tmp8u2 < tmp8u; tmp8u2++) {
+                        tmp64u -= sizeof(void*);
+                        Push64(emu, *((uintptr_t*)tmp64u));
+                    }
+                    Push64(emu, R_RBP);
                 }
-                Push(emu, R_RBP);
             }
             R_RSP -= tmp16u;
             break;
         case 0xC9:                      /* LEAVE */
             R_RSP = R_RBP;
-            R_RBP = Pop(emu);
+            R_RBP = rex.is32bits?Pop32(emu):Pop64(emu);
             break;
 
         case 0xCC:                      /* INT 3 */
@@ -1143,26 +1373,44 @@ x64emurun:
             #endif
             break;
         case 0xCD:                      /* INT n */
+            tmp8u = F8;
             // this is a privilege opcode...
-            #ifndef TEST_INTERPRETER
-            emit_signal(emu, SIGSEGV, (void*)R_RIP, 0);
-            STEP;
-            #endif
+            if(box64_wine && tmp8u==0x2D) {
+                // lets ignore the INT 2D
+                printf_log(LOG_DEBUG, "INT 2D called\n");
+            } else if(box64_wine && tmp8u==0x29) {
+                // INT 29 is __fastfail
+                printf_log(LOG_DEBUG, "INT 29 called => __fastfail(0x%x)\n", R_ECX);
+                emu->quit = 1;
+                R_RIP = addr;
+                goto fini;
+            } else if (tmp8u==0x80) {
+                // 32bits syscall
+                #ifndef TEST_INTERPRETER
+                x86Syscall(emu);
+                STEP;
+                #endif
+            } else {
+                #ifndef TEST_INTERPRETER
+                emit_signal(emu, SIGSEGV, (void*)R_RIP, 0);
+                STEP;
+                #endif
+            }
             break;
 
-
         case 0xCF:                      /* IRET */
-            addr = Pop(emu);
-            emu->segs[_CS] = Pop(emu)&0xffff;
+            addr = rex.is32bits?Pop32(emu):Pop64(emu);
+            emu->segs[_CS] = (rex.is32bits?Pop32(emu):Pop64(emu))&0xffff;
             emu->segs_serial[_CS] = 0;
-            emu->eflags.x64 = ((Pop(emu) & 0x3F7FD7)/* & (0xffff-40)*/ ) | 0x2; // mask off res2 and res3 and on res1
-            tmp64u = Pop(emu);  //RSP
-            emu->segs[_SS] = Pop(emu)&0xffff;
+            emu->eflags.x64 = (((rex.is32bits?Pop32(emu):Pop64(emu)) & 0x3F7FD7)/* & (0xffff-40)*/ ) | 0x2; // mask off res2 and res3 and on res1
+            tmp64u = rex.is32bits?Pop32(emu):Pop64(emu);  //RSP
+            emu->segs[_SS] = (rex.is32bits?Pop32(emu):Pop64(emu))&0xffff;
             emu->segs_serial[_SS] = 0;
-            R_RSP= tmp64u;
+            R_RSP = tmp64u;
             RESET_FLAGS(emu);
             R_RIP = addr;
-            goto fini;      // exit, to recompute CS if needed
+            STEP;
+            is32bits = (emu->segs[_CS]==0x23);
             break;
         case 0xD0:                      /* GRP2 Eb,1 */
         case 0xD2:                      /* GRP2 Eb,CL */
@@ -1386,13 +1634,17 @@ x64emurun:
             break;
         case 0xE8:                      /* CALL Id */
             tmp32s = F32S; // call is relative
-            Push(emu, addr);
+            if(rex.is32bits)
+                Push32(emu, addr);
+            else
+                Push64(emu, addr);
             addr += tmp32s;
             STEP2
             break;
         case 0xE9:                      /* JMP Id */
             tmp32s = F32S; // jmp is relative
             addr += tmp32s;
+            addr = (uintptr_t)getAlternate((void*)addr);
             STEP2
             break;
 
@@ -1549,12 +1801,12 @@ x64emurun:
             SET_FLAG(F_CF);
             break;
         case 0xFA:                      /* CLI */
-            // this is a privilege opcode...
+            // this is a privilege opcode
             emit_signal(emu, SIGSEGV, (void*)R_RIP, 0);
             STEP;
             break;
         case 0xFB:                      /* STI */
-            // this is a privilege opcode...
+            // this is a privilege opcode
             emit_signal(emu, SIGSEGV, (void*)R_RIP, 0);
             STEP;
             break;
@@ -1606,8 +1858,13 @@ x64emurun:
                     break;
                 case 2:                 /* CALL NEAR Ed */
                     GETE8(0);
-                    tmp64u = (uintptr_t)getAlternate((void*)ED->q[0]);
-                    Push(emu, addr);
+                    if(rex.is32bits) {
+                        tmp64u = (uintptr_t)ED->dword[0];
+                        Push32(emu, addr);
+                    } else {
+                        tmp64u = (uintptr_t)getAlternate((void*)ED->q[0]);
+                        Push64(emu, addr);
+                    }
                     addr = tmp64u;
                     STEP2
                     break;
@@ -1619,16 +1876,27 @@ x64emurun:
                         emu->error |= ERR_ILLEGAL;
                         goto fini;
                     } else {
-                        Push(emu, R_CS);
-                        Push(emu, addr);
-                        R_RIP = addr = (uintptr_t)getAlternate((void*)ED->q[0]);   // check CS?
-                        R_CS = (ED+1)->word[0];
-                        goto fini;  // exit loop to recompute new CS...
+                        if(rex.is32bits || !rex.w) {
+                            Push32(emu, R_CS);
+                            Push32(emu, addr);
+                            addr = (uintptr_t)getAlternate((void*)(uintptr_t)ED->dword[0]);
+                            R_CS = ED->word[2];
+                        } else {
+                            Push64(emu, R_CS);
+                            Push64(emu, addr);
+                            addr = (uintptr_t)getAlternate((void*)ED->q[0]);
+                            R_CS = (ED+1)->word[0];
+                        }
+                        STEP2;
+                        is32bits = (emu->segs[_CS]==0x23);
                     }
                     break;
                 case 4:                 /* JMP NEAR Ed */
                     GETE8(0);
-                    addr = (uintptr_t)getAlternate((void*)ED->q[0]);
+                    if(rex.is32bits)
+                        addr = (uintptr_t)ED->dword[0];
+                    else
+                        addr = (uintptr_t)getAlternate((void*)ED->q[0]);
                     STEP2
                     break;
                 case 5:                 /* JMP FAR Ed */
@@ -1639,23 +1907,26 @@ x64emurun:
                         emu->error |= ERR_ILLEGAL;
                         goto fini;
                     } else {
-                        R_RIP = (uintptr_t)getAlternate((void*)ED->q[0]);   //check CS?
-                        R_CS = (ED+1)->word[0];
-                        goto fini;  // exit loop to recompute CS...
+                        if(rex.is32bits || !rex.w) {
+                            addr = (uintptr_t)getAlternate((void*)(uintptr_t)ED->dword[0]);
+                            R_CS = ED->word[2];
+                        } else {
+                            addr = (uintptr_t)getAlternate((void*)ED->q[0]);
+                            R_CS = (ED+1)->word[0];
+                        }
+                        STEP2;
+                        is32bits = (emu->segs[_CS]==0x23);
                     }
                     break;
                 case 6:                 /* Push Ed */
-                    GETE8(0);
-                    tmp64u = ED->q[0];  // rex.w ignored
-                    #ifdef TEST_INTERPRETER
-                    R_RSP -=8;
-                    if(test->memsize!=8)
-                        *(uint64_t*)test->mem = *(uint64_t*)test->memaddr;
-                    test->memsize = 8;
-                    test->memaddr = R_RSP;
-                    #else
-                    Push(emu, tmp64u);  // avoid potential issue with push [esp+...]
-                    #endif
+                    _GETED(0);
+                    if(rex.is32bits) {
+                        tmp32u = ED->dword[0];
+                        Push32(emu, tmp32u);  // avoid potential issue with push [esp+...]
+                    } else {
+                        tmp64u = ED->q[0];  // rex.w ignored
+                        Push64(emu, tmp64u);  // avoid potential issue with push [esp+...]
+                    }
                     break;
                 default:
                     printf_log(LOG_NONE, "Illegal Opcode %p: %02X %02X %02X %02X %02X %02X\n",(void*)R_RIP, opcode, nextop, PK(2), PK(3), PK(4), PK(5));
@@ -1673,11 +1944,12 @@ x64emurun:
 
 
 fini:
+if(emu->segs[_CS]!=0x33 && emu->segs[_CS]!=0x23) printf_log(LOG_NONE, "Warning, CS is not default value: 0x%x\n", emu->segs[_CS]);
 #ifndef TEST_INTERPRETER
     printf_log(LOG_DEBUG, "End of X86 run (%p), RIP=%p, Stack=%p, unimp=%d, emu->fork=%d, emu->uc_link=%p, emu->quit=%d\n", emu, (void*)R_RIP, (void*)R_RSP, unimp, emu->fork, emu->uc_link, emu->quit);
     if(unimp) {
         emu->quit = 1;
-        UnimpOpcode(emu);
+        UnimpOpcode(emu, is32bits);
     }
     // fork handling
     if(emu->fork) {