[XEN] Add LOOP{,Z,NZ} and CBW/CWD/... emulation.
authorkfraser@localhost.localdomain <kfraser@localhost.localdomain>
Thu, 11 Jan 2007 19:01:28 +0000 (19:01 +0000)
committerkfraser@localhost.localdomain <kfraser@localhost.localdomain>
Thu, 11 Jan 2007 19:01:28 +0000 (19:01 +0000)
Signed-off-by: Keir Fraser <keir@xensource.com>
xen/arch/x86/x86_emulate.c

index e96e981b21b92f8589e2c9d48a92f227b978678c..200b6c4aac0c6d77256649ee80e3c6e7534fe9be 100644 (file)
@@ -109,7 +109,7 @@ static uint8_t opcode_table[256] = {
     ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
     ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
     /* 0x98 - 0x9F */
-    0, 0, 0, 0, 0, 0, ImplicitOps, ImplicitOps,
+    ImplicitOps, ImplicitOps, 0, 0, 0, 0, ImplicitOps, ImplicitOps,
     /* 0xA0 - 0xA7 */
     ByteOp|ImplicitOps|Mov, ImplicitOps|Mov,
     ByteOp|ImplicitOps|Mov, ImplicitOps|Mov,
@@ -139,7 +139,7 @@ static uint8_t opcode_table[256] = {
     /* 0xD8 - 0xDF */
     0, 0, 0, 0, 0, 0, 0, 0,
     /* 0xE0 - 0xE7 */
-    0, 0, 0, ImplicitOps, 0, 0, 0, 0,
+    ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, 0, 0, 0, 0,
     /* 0xE8 - 0xEF */
     ImplicitOps, ImplicitOps, 0, ImplicitOps, 0, 0, 0, 0,
     /* 0xF0 - 0xF7 */
@@ -1339,6 +1339,30 @@ x86_emulate(
         dst.val  = *dst.reg;
         goto xchg;
 
+    case 0x98: /* cbw/cwde/cdqe */
+        switch ( op_bytes )
+        {
+        case 2: *(int16_t *)&_regs.eax = (int8_t)_regs.eax; break; /* cbw */
+        case 4: _regs.eax = (uint32_t)(int16_t)_regs.eax; break; /* cwde */
+        case 8: _regs.eax = (int32_t)_regs.eax; break; /* cdqe */
+        }
+        break;
+
+    case 0x99: /* cwd/cdq/cqo */
+        switch ( op_bytes )
+        {
+        case 2:
+            *(int16_t *)&_regs.edx = ((int16_t)_regs.eax < 0) ? -1 : 0;
+            break;
+        case 4:
+            _regs.edx = (uint32_t)(((int32_t)_regs.eax < 0) ? -1 : 0);
+            break;
+        case 8:
+            _regs.edx = (_regs.eax < 0) ? -1 : 0;
+            break;
+        }
+        break;
+
     case 0x9e: /* sahf */
         *(uint8_t *)_regs.eflags = (((uint8_t *)&_regs.eax)[1] & 0xd7) | 0x02;
         break;
@@ -1452,6 +1476,31 @@ x86_emulate(
         break;
     }
 
+    case 0xe0 ... 0xe2: /* loop{,z,nz} */ {
+        int rel = insn_fetch_type(int8_t);
+        int do_jmp = !(_regs.eflags & EFLG_ZF); /* loopnz */
+        if ( b == 0xe1 )
+            do_jmp = !do_jmp; /* loopz */
+        else if ( b == 0xe2 )
+            do_jmp = 1; /* loop */
+        switch ( ad_bytes )
+        {
+        case 2:
+            do_jmp &= --(*(uint16_t *)&_regs.ecx) != 0;
+            break;
+        case 4:
+            do_jmp &= --(*(uint32_t *)&_regs.ecx) != 0;
+            _regs.ecx = (uint32_t)_regs.ecx; /* zero extend in x86/64 mode */
+            break;
+        default: /* case 8: */
+            do_jmp &= --_regs.ecx != 0;
+            break;
+        }
+        if ( do_jmp )
+            jmp_rel(rel);
+        break;
+    }
+
     case 0xe3: /* jcxz/jecxz (short) */ {
         int rel = insn_fetch_type(int8_t);
         if ( (ad_bytes == 2) ? !(uint16_t)_regs.ecx :