[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] Add support for MOVSX/MOVSXD/MOVZX (move-with-extend)



# HG changeset patch
# User kaf24@xxxxxxxxxxxxxxxxxxxx
# Node ID c259492dfb43d83fdb74bb4f4fd8be6ccfa926ee
# Parent  6e24488a89f7eade3857d1bc11fcc3e24857dc59
Add support for MOVSX/MOVSXD/MOVZX (move-with-extend)
instructions to the generic x86 emulator. Also add
preliminary support for 16-bit addressing: decode the
ModR/M byte properly but still need to access and update
implicit memory operands (esp,esi,edi) with correct width.
Work is also needed to support real-mode addressing.

Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>

diff -r 6e24488a89f7 -r c259492dfb43 tools/tests/Makefile
--- a/tools/tests/Makefile      Tue Dec 20 17:45:29 2005
+++ b/tools/tests/Makefile      Wed Dec 21 13:29:23 2005
@@ -6,6 +6,8 @@
 
 CC     := gcc
 CFLAGS := -O2 -Wall -Werror -D__TEST_HARNESS__
+
+all: $(TARGET)
 
 $(TARGET): x86_emulate.o test_x86_emulator.o
        $(CC) -o $@ $^
diff -r 6e24488a89f7 -r c259492dfb43 tools/tests/test_x86_emulator.c
--- a/tools/tests/test_x86_emulator.c   Tue Dec 20 17:45:29 2005
+++ b/tools/tests/test_x86_emulator.c   Wed Dec 21 13:29:23 2005
@@ -254,6 +254,36 @@
         goto fail;
     printf("okay\n");
 
+    printf("%-40s", "Testing movsxbd (%%eax),%%ecx...");
+    instr[0] = 0x0f; instr[1] = 0xbe; instr[2] = 0x08;
+    regs.eip    = (unsigned long)&instr[0];
+    regs.ecx    = 0x12345678;
+    cr2         = (unsigned long)&res;
+    res         = 0x82;
+    rc = x86_emulate_memop(&regs, cr2, &emulops, 4);
+    if ( (rc != 0) ||
+         (res != 0x82) ||
+         (regs.ecx != 0xFFFFFF82) ||
+         ((regs.eflags&0x240) != 0x200) ||
+         (regs.eip != (unsigned long)&instr[3]) )
+        goto fail;
+    printf("okay\n");
+
+    printf("%-40s", "Testing movzxwd (%%eax),%%ecx...");
+    instr[0] = 0x0f; instr[1] = 0xb7; instr[2] = 0x08;
+    regs.eip    = (unsigned long)&instr[0];
+    regs.ecx    = 0x12345678;
+    cr2         = (unsigned long)&res;
+    res         = 0x1234aa82;
+    rc = x86_emulate_memop(&regs, cr2, &emulops, 4);
+    if ( (rc != 0) ||
+         (res != 0x1234aa82) ||
+         (regs.ecx != 0xaa82) ||
+         ((regs.eflags&0x240) != 0x200) ||
+         (regs.eip != (unsigned long)&instr[3]) )
+        goto fail;
+    printf("okay\n");
+
     return 0;
 
  fail:
diff -r 6e24488a89f7 -r c259492dfb43 xen/arch/x86/x86_emulate.c
--- a/xen/arch/x86/x86_emulate.c        Tue Dec 20 17:45:29 2005
+++ b/xen/arch/x86/x86_emulate.c        Wed Dec 21 13:29:23 2005
@@ -9,14 +9,6 @@
 #ifdef __TEST_HARNESS__
 #include <stdio.h>
 #include <stdint.h>
-typedef uint8_t            u8;
-typedef uint16_t           u16;
-typedef uint32_t           u32;
-typedef uint64_t           u64;
-typedef int8_t             s8;
-typedef int16_t            s16;
-typedef int32_t            s32;
-typedef int64_t            s64;
 #include <public/xen.h>
 #define DPRINTF(_f, _a...) printf( _f , ## _a )
 #else
@@ -50,15 +42,17 @@
 #define SrcImplicit (0<<3) /* Source operand is implicit in the opcode. */
 #define SrcReg      (1<<3) /* Register operand. */
 #define SrcMem      (2<<3) /* Memory operand. */
-#define SrcImm      (3<<3) /* Immediate operand. */
-#define SrcImmByte  (4<<3) /* 8-bit sign-extended immediate operand. */
+#define SrcMem16    (3<<3) /* Memory operand (16-bit). */
+#define SrcMem32    (4<<3) /* Memory operand (32-bit). */
+#define SrcImm      (5<<3) /* Immediate operand. */
+#define SrcImmByte  (6<<3) /* 8-bit sign-extended immediate operand. */
 #define SrcMask     (7<<3)
 /* Generic ModRM decode. */
 #define ModRM       (1<<6)
 /* Destination is only written; never read. */
 #define Mov         (1<<7)
 
-static u8 opcode_table[256] = {
+static uint8_t opcode_table[256] = {
     /* 0x00 - 0x07 */
     ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
     ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
@@ -96,7 +90,8 @@
     /* 0x50 - 0x5F */
     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
     /* 0x60 - 0x6F */
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, DstReg|SrcMem32|ModRM|Mov /* movsxd (x86/64) */,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
     /* 0x70 - 0x7F */
     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
     /* 0x80 - 0x87 */
@@ -142,7 +137,7 @@
     0, 0, ByteOp|DstMem|SrcNone|ModRM, DstMem|SrcNone|ModRM
 };
 
-static u8 twobyte_table[256] = {
+static uint8_t twobyte_table[256] = {
     /* 0x00 - 0x0F */
     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ImplicitOps|ModRM, 0, 0,
     /* 0x10 - 0x1F */
@@ -177,9 +172,10 @@
     0, 0, 0, DstMem|SrcReg|ModRM, 0, 0, 0, 0,
     /* 0xB0 - 0xB7 */
     ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, 0, DstMem|SrcReg|ModRM,
-    0, 0, 0, 0,
+    0, 0, ByteOp|DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem16|ModRM|Mov,
     /* 0xB8 - 0xBF */
-    0, 0, DstMem|SrcImmByte|ModRM, DstMem|SrcReg|ModRM, 0, 0, 0, 0,
+    0, 0, DstMem|SrcImmByte|ModRM, DstMem|SrcReg|ModRM,
+    0, 0, ByteOp|DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem16|ModRM|Mov,
     /* 0xC0 - 0xCF */
     0, 0, 0, 0, 0, 0, 0, ImplicitOps|ModRM, 0, 0, 0, 0, 0, 0, 0, 0,
     /* 0xD0 - 0xDF */
@@ -377,7 +373,7 @@
 
 void *
 decode_register(
-    u8 modrm_reg, struct cpu_user_regs *regs, int highbyte_regs)
+    uint8_t modrm_reg, struct cpu_user_regs *regs, int highbyte_regs)
 {
     void *p;
 
@@ -422,8 +418,8 @@
     struct x86_mem_emulator *ops,
     int mode)
 {
-    u8 b, d, sib, twobyte = 0, rex_prefix = 0;
-    u8 modrm, modrm_mod = 0, modrm_reg = 0, modrm_rm = 0;
+    uint8_t b, d, sib, twobyte = 0, rex_prefix = 0;
+    uint8_t modrm, modrm_mod = 0, modrm_reg = 0, modrm_rm = 0;
     unsigned int op_bytes = (mode == 8) ? 4 : mode, ad_bytes = mode;
     unsigned int lock_prefix = 0, rep_prefix = 0, i;
     int rc = 0;
@@ -435,7 +431,7 @@
     /* Legacy prefixes. */
     for ( i = 0; i < 8; i++ )
     {
-        switch ( b = insn_fetch(u8, 1, _regs.eip) )
+        switch ( b = insn_fetch(uint8_t, 1, _regs.eip) )
         {
         case 0x66: /* operand-size override */
             op_bytes ^= 6;                    /* switch between 2/4 bytes */
@@ -465,12 +461,6 @@
     }
  done_prefixes:
 
-    if ( ad_bytes == 2 )
-    {
-        DPRINTF("Cannot parse 16-bit effective addresses.\n");
-        goto cannot_emulate;
-    }
-
     /* REX prefix. */
     if ( (mode == 8) && ((b & 0xf0) == 0x40) )
     {
@@ -479,7 +469,7 @@
             op_bytes = 8;          /* REX.W */
         modrm_reg = (b & 4) << 1;  /* REX.R */
         /* REX.B and REX.X do not need to be decoded. */
-        b = insn_fetch(u8, 1, _regs.eip);
+        b = insn_fetch(uint8_t, 1, _regs.eip);
     }
 
     /* Opcode byte(s). */
@@ -490,7 +480,7 @@
         if ( b == 0x0f )
         {
             twobyte = 1;
-            b = insn_fetch(u8, 1, _regs.eip);
+            b = insn_fetch(uint8_t, 1, _regs.eip);
             d = twobyte_table[b];
         }
 
@@ -502,32 +492,57 @@
     /* ModRM and SIB bytes. */
     if ( d & ModRM )
     {
-        modrm = insn_fetch(u8, 1, _regs.eip);
+        modrm = insn_fetch(uint8_t, 1, _regs.eip);
         modrm_mod |= (modrm & 0xc0) >> 6;
         modrm_reg |= (modrm & 0x38) >> 3;
         modrm_rm  |= (modrm & 0x07);
-        switch ( modrm_mod )
-        {
-        case 0:
-            if ( (modrm_rm == 4) && 
-                 (((sib = insn_fetch(u8, 1, _regs.eip)) & 7) == 5) )
-                _regs.eip += 4; /* skip disp32 specified by SIB.base */
-            else if ( modrm_rm == 5 )
-                _regs.eip += 4; /* skip disp32 */
-            break;
-        case 1:
-            if ( modrm_rm == 4 )
-                sib = insn_fetch(u8, 1, _regs.eip);
-            _regs.eip += 1; /* skip disp8 */
-            break;
-        case 2:
-            if ( modrm_rm == 4 )
-                sib = insn_fetch(u8, 1, _regs.eip);
-            _regs.eip += 4; /* skip disp32 */
-            break;
-        case 3:
+
+        if ( modrm_mod == 3 )
+        {
             DPRINTF("Cannot parse ModRM.mod == 3.\n");
             goto cannot_emulate;
+        }
+
+        if ( ad_bytes == 2 )
+        {
+            /* 16-bit ModR/M decode. */
+            switch ( modrm_mod )
+            {
+            case 0:
+                if ( modrm_rm == 6 )
+                    _regs.eip += 2; /* skip disp16 */
+                break;
+            case 1:
+                _regs.eip += 1; /* skip disp8 */
+                break;
+            case 2:
+                _regs.eip += 2; /* skip disp16 */
+                break;
+            }
+        }
+        else
+        {
+            /* 32/64-bit ModR/M decode. */
+            switch ( modrm_mod )
+            {
+            case 0:
+                if ( (modrm_rm == 4) && 
+                     (((sib = insn_fetch(uint8_t, 1, _regs.eip)) & 7) == 5) )
+                    _regs.eip += 4; /* skip disp32 specified by SIB.base */
+                else if ( modrm_rm == 5 )
+                    _regs.eip += 4; /* skip disp32 */
+                break;
+            case 1:
+                if ( modrm_rm == 4 )
+                    sib = insn_fetch(uint8_t, 1, _regs.eip);
+                _regs.eip += 1; /* skip disp8 */
+                break;
+            case 2:
+                if ( modrm_rm == 4 )
+                    sib = insn_fetch(uint8_t, 1, _regs.eip);
+                _regs.eip += 4; /* skip disp32 */
+                break;
+            }
         }
     }
 
@@ -542,7 +557,7 @@
         if ( d & ByteOp )
         {
             dst.ptr = decode_register(modrm_reg, &_regs, (rex_prefix == 0));
-            dst.val = *(u8 *)dst.ptr;
+            dst.val = *(uint8_t *)dst.ptr;
             dst.bytes = 1;
         }
         else
@@ -550,9 +565,9 @@
             dst.ptr = decode_register(modrm_reg, &_regs, 0);
             switch ( (dst.bytes = op_bytes) )
             {
-            case 2: dst.val = *(u16 *)dst.ptr; break;
-            case 4: dst.val = *(u32 *)dst.ptr; break;
-            case 8: dst.val = *(u64 *)dst.ptr; break;
+            case 2: dst.val = *(uint16_t *)dst.ptr; break;
+            case 4: dst.val = *(uint32_t *)dst.ptr; break;
+            case 8: dst.val = *(uint64_t *)dst.ptr; break;
             }
         }
         break;
@@ -578,7 +593,7 @@
         if ( d & ByteOp )
         {
             src.ptr = decode_register(modrm_reg, &_regs, (rex_prefix == 0));
-            src.val = src.orig_val = *(u8 *)src.ptr;
+            src.val = src.orig_val = *(uint8_t *)src.ptr;
             src.bytes = 1;
         }
         else
@@ -586,16 +601,23 @@
             src.ptr = decode_register(modrm_reg, &_regs, 0);
             switch ( (src.bytes = op_bytes) )
             {
-            case 2: src.val = src.orig_val = *(u16 *)src.ptr; break;
-            case 4: src.val = src.orig_val = *(u32 *)src.ptr; break;
-            case 8: src.val = src.orig_val = *(u64 *)src.ptr; break;
+            case 2: src.val = src.orig_val = *(uint16_t *)src.ptr; break;
+            case 4: src.val = src.orig_val = *(uint32_t *)src.ptr; break;
+            case 8: src.val = src.orig_val = *(uint64_t *)src.ptr; break;
             }
         }
         break;
+    case SrcMem16:
+        src.bytes = 2;
+        goto srcmem_common;
+    case SrcMem32:
+        src.bytes = 4;
+        goto srcmem_common;
     case SrcMem:
+        src.bytes = (d & ByteOp) ? 1 : op_bytes;
+    srcmem_common:
         src.type  = OP_MEM;
         src.ptr   = (unsigned long *)cr2;
-        src.bytes = (d & ByteOp) ? 1 : op_bytes;
         if ( (rc = ops->read_emulated((unsigned long)src.ptr, 
                                       &src.val, src.bytes)) != 0 )
             goto done;
@@ -609,16 +631,16 @@
         /* NB. Immediates are sign-extended as necessary. */
         switch ( src.bytes )
         {
-        case 1: src.val = insn_fetch(s8,  1, _regs.eip); break;
-        case 2: src.val = insn_fetch(s16, 2, _regs.eip); break;
-        case 4: src.val = insn_fetch(s32, 4, _regs.eip); break;
+        case 1: src.val = insn_fetch(int8_t,  1, _regs.eip); break;
+        case 2: src.val = insn_fetch(int16_t, 2, _regs.eip); break;
+        case 4: src.val = insn_fetch(int32_t, 4, _regs.eip); break;
         }
         break;
     case SrcImmByte:
         src.type  = OP_IMM;
         src.ptr   = (unsigned long *)_regs.eip;
         src.bytes = 1;
-        src.val   = insn_fetch(s8,  1, _regs.eip);
+        src.val   = insn_fetch(int8_t,  1, _regs.eip);
         break;
     }
 
@@ -650,6 +672,11 @@
         break;
     case 0x38 ... 0x3d: cmp: /* cmp */
         emulate_2op_SrcV("cmp", src, dst, _regs.eflags);
+        break;
+    case 0x63: /* movsxd */
+        if ( mode != 8 ) /* x86/64 long mode only */
+            goto cannot_emulate;
+        dst.val = (int32_t)src.val;
         break;
     case 0x80 ... 0x83: /* Grp1 */
         switch ( modrm_reg )
@@ -671,9 +698,9 @@
         /* Write back the register source. */
         switch ( dst.bytes )
         {
-        case 1: *(u8  *)src.ptr = (u8)dst.val; break;
-        case 2: *(u16 *)src.ptr = (u16)dst.val; break;
-        case 4: *src.ptr = (u32)dst.val; break; /* 64b mode: zero-extend */
+        case 1: *(uint8_t  *)src.ptr = (uint8_t)dst.val; break;
+        case 2: *(uint16_t *)src.ptr = (uint16_t)dst.val; break;
+        case 4: *src.ptr = (uint32_t)dst.val; break; /* 64b reg: zero-extend */
         case 8: *src.ptr = dst.val; break;
         }
         /* Write back the memory destination with implicit LOCK prefix. */
@@ -745,9 +772,9 @@
             if ( src.bytes == 8 ) src.bytes = 4;
             switch ( src.bytes )
             {
-            case 1: src.val = insn_fetch(s8,  1, _regs.eip); break;
-            case 2: src.val = insn_fetch(s16, 2, _regs.eip); break;
-            case 4: src.val = insn_fetch(s32, 4, _regs.eip); break;
+            case 1: src.val = insn_fetch(int8_t,  1, _regs.eip); break;
+            case 2: src.val = insn_fetch(int16_t, 2, _regs.eip); break;
+            case 4: src.val = insn_fetch(int32_t, 4, _regs.eip); break;
             }
             goto test;
         case 2: /* not */
@@ -798,9 +825,9 @@
             /* The 4-byte case *is* correct: in 64-bit mode we zero-extend. */
             switch ( dst.bytes )
             {
-            case 1: *(u8  *)dst.ptr = (u8)dst.val; break;
-            case 2: *(u16 *)dst.ptr = (u16)dst.val; break;
-            case 4: *dst.ptr = (u32)dst.val; break; /* 64b mode: zero-extend */
+            case 1: *(uint8_t  *)dst.ptr = (uint8_t)dst.val; break;
+            case 2: *(uint16_t *)dst.ptr = (uint16_t)dst.val; break;
+            case 4: *dst.ptr = (uint32_t)dst.val; break; /* 64b: zero-ext */
             case 8: *dst.ptr = dst.val; break;
             }
             break;
@@ -953,6 +980,10 @@
         src.val &= (dst.bytes << 3) - 1; /* only subword offset */
         emulate_2op_SrcV_nobyte("bts", src, dst, _regs.eflags);
         break;
+    case 0xb6 ... 0xb7: /* movzx */
+        dst.bytes = op_bytes;
+        dst.val = (d & ByteOp) ? (uint8_t)src.val : (uint16_t)src.val;
+        break;
     case 0xbb: btc: /* btc */
         src.val &= (dst.bytes << 3) - 1; /* only subword offset */
         emulate_2op_SrcV_nobyte("btc", src, dst, _regs.eflags);
@@ -965,6 +996,10 @@
         case 2: goto btr;
         case 3: goto btc;
         }
+        break;
+    case 0xbe ... 0xbf: /* movsx */
+        dst.bytes = op_bytes;
+        dst.val = (d & ByteOp) ? (int8_t)src.val : (int16_t)src.val;
         break;
     }
     goto writeback;
@@ -1009,16 +1044,16 @@
         unsigned long old, new;
         if ( (rc = ops->read_emulated(cr2, &old, 8)) != 0 )
             goto done;
-        if ( ((u32)(old>>0) != (u32)_regs.eax) ||
-             ((u32)(old>>32) != (u32)_regs.edx) )
-        {
-            _regs.eax = (u32)(old>>0);
-            _regs.edx = (u32)(old>>32);
+        if ( ((uint32_t)(old>>0) != (uint32_t)_regs.eax) ||
+             ((uint32_t)(old>>32) != (uint32_t)_regs.edx) )
+        {
+            _regs.eax = (uint32_t)(old>>0);
+            _regs.edx = (uint32_t)(old>>32);
             _regs.eflags &= ~EFLG_ZF;
         }
         else
         {
-            new = (_regs.ecx<<32)|(u32)_regs.ebx;
+            new = (_regs.ecx<<32)|(uint32_t)_regs.ebx;
             if ( (rc = ops->cmpxchg_emulated(cr2, old, new, 8)) != 0 )
                 goto done;
             _regs.eflags |= EFLG_ZF;
diff -r 6e24488a89f7 -r c259492dfb43 xen/include/asm-x86/x86_emulate.h
--- a/xen/include/asm-x86/x86_emulate.h Tue Dec 20 17:45:29 2005
+++ b/xen/include/asm-x86/x86_emulate.h Wed Dec 21 13:29:23 2005
@@ -164,6 +164,6 @@
  */
 extern void *
 decode_register(
-    u8 modrm_reg, struct cpu_user_regs *regs, int highbyte_regs);
+    uint8_t modrm_reg, struct cpu_user_regs *regs, int highbyte_regs);
 
 #endif /* __X86_EMULATE_H__ */

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.