[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(®s, 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(®s, 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
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |