# HG changeset patch
# User kfraser@xxxxxxxxxxxxxxxxxxxxx
# Date 1166627773 0
# Node ID 4fb80f21c77df84f6a6d7f61fdce4c337d538291
# Parent ed815cbdc90e4991da69ec57a4b9e2793bb43b7b
[XEN] Emulator extensions to decode ModRM.MOD == 3.
This allows emulation of register-only instructions.
Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>
---
tools/tests/test_x86_emulator.c | 44 +++----
xen/arch/x86/x86_32/seg_fixup.c | 5
xen/arch/x86/x86_emulate.c | 229 +++++++++++++++++++++++-----------------
3 files changed, 155 insertions(+), 123 deletions(-)
diff -r ed815cbdc90e -r 4fb80f21c77d tools/tests/test_x86_emulator.c
--- a/tools/tests/test_x86_emulator.c Wed Dec 20 13:54:04 2006 +0000
+++ b/tools/tests/test_x86_emulator.c Wed Dec 20 15:16:13 2006 +0000
@@ -15,8 +15,6 @@ typedef int64_t s64;
#include <asm-x86/x86_emulate.h>
#include <sys/mman.h>
-#define PFEC_write_access (1U<<1)
-
static int read(
unsigned int seg,
unsigned long offset,
@@ -119,12 +117,26 @@ int main(int argc, char **argv)
regs.eflags = 0x200;
regs.eip = (unsigned long)&instr[0];
regs.ecx = 0x12345678;
- regs.error_code = PFEC_write_access;
regs.eax = (unsigned long)res;
*res = 0x7FFFFFFF;
rc = x86_emulate_memop(&ctxt, &emulops);
if ( (rc != 0) ||
(*res != 0x92345677) ||
+ (regs.eflags != 0xa94) ||
+ (regs.eip != (unsigned long)&instr[2]) )
+ goto fail;
+ printf("okay\n");
+
+ printf("%-40s", "Testing addl %%ecx,%%eax...");
+ instr[0] = 0x01; instr[1] = 0xc8;
+ regs.eflags = 0x200;
+ regs.eip = (unsigned long)&instr[0];
+ regs.ecx = 0x12345678;
+ regs.eax = 0x7FFFFFFF;
+ rc = x86_emulate_memop(&ctxt, &emulops);
+ if ( (rc != 0) ||
+ (regs.ecx != 0x12345678) ||
+ (regs.eax != 0x92345677) ||
(regs.eflags != 0xa94) ||
(regs.eip != (unsigned long)&instr[2]) )
goto fail;
@@ -140,7 +152,6 @@ int main(int argc, char **argv)
regs.ecx = 0x12345678UL;
#endif
regs.eax = (unsigned long)res;
- regs.error_code = 0;
rc = x86_emulate_memop(&ctxt, &emulops);
if ( (rc != 0) ||
(*res != 0x92345677) ||
@@ -155,7 +166,6 @@ int main(int argc, char **argv)
regs.eip = (unsigned long)&instr[0];
regs.ecx = ~0UL;
regs.eax = (unsigned long)res;
- regs.error_code = 0;
rc = x86_emulate_memop(&ctxt, &emulops);
if ( (rc != 0) ||
(*res != 0x92345677) ||
@@ -171,7 +181,6 @@ int main(int argc, char **argv)
regs.eax = 0x92345677UL;
regs.ecx = 0xAA;
regs.ebx = (unsigned long)res;
- regs.error_code = PFEC_write_access;
rc = x86_emulate_memop(&ctxt, &emulops);
if ( (rc != 0) ||
(*res != 0x923456AA) ||
@@ -188,7 +197,6 @@ int main(int argc, char **argv)
regs.eax = 0xAABBCC77UL;
regs.ecx = 0xFF;
regs.ebx = (unsigned long)res;
- regs.error_code = PFEC_write_access;
rc = x86_emulate_memop(&ctxt, &emulops);
if ( (rc != 0) ||
(*res != 0x923456AA) ||
@@ -205,7 +213,6 @@ int main(int argc, char **argv)
regs.eip = (unsigned long)&instr[0];
regs.ecx = 0x12345678;
regs.eax = (unsigned long)res;
- regs.error_code = PFEC_write_access;
rc = x86_emulate_memop(&ctxt, &emulops);
if ( (rc != 0) ||
(*res != 0x12345678) ||
@@ -223,7 +230,6 @@ int main(int argc, char **argv)
regs.eax = 0x923456AAUL;
regs.ecx = 0xDDEEFF00L;
regs.ebx = (unsigned long)res;
- regs.error_code = PFEC_write_access;
rc = x86_emulate_memop(&ctxt, &emulops);
if ( (rc != 0) ||
(*res != 0xDDEEFF00) ||
@@ -241,7 +247,6 @@ int main(int argc, char **argv)
regs.eip = (unsigned long)&instr[0];
regs.esi = (unsigned long)res + 0;
regs.edi = (unsigned long)res + 2;
- regs.error_code = 0; /* read fault */
rc = x86_emulate_memop(&ctxt, &emulops);
if ( (rc != 0) ||
(*res != 0x44554455) ||
@@ -259,9 +264,8 @@ int main(int argc, char **argv)
regs.eflags = 0x200;
regs.eip = (unsigned long)&instr[0];
regs.edi = (unsigned long)res;
- regs.error_code = PFEC_write_access;
- rc = x86_emulate_memop(&ctxt, &emulops);
- if ( (rc != 0) ||
+ rc = x86_emulate_memop(&ctxt, &emulops);
+ if ( (rc != 0) ||
(*res != 0x2233445D) ||
((regs.eflags&0x201) != 0x201) ||
(regs.eip != (unsigned long)&instr[4]) )
@@ -275,9 +279,8 @@ int main(int argc, char **argv)
regs.eip = (unsigned long)&instr[0];
regs.eax = -32;
regs.edi = (unsigned long)(res+1);
- regs.error_code = PFEC_write_access;
- rc = x86_emulate_memop(&ctxt, &emulops);
- if ( (rc != 0) ||
+ rc = x86_emulate_memop(&ctxt, &emulops);
+ if ( (rc != 0) ||
(*res != 0x2233445E) ||
((regs.eflags&0x201) != 0x201) ||
(regs.eip != (unsigned long)&instr[3]) )
@@ -296,9 +299,8 @@ int main(int argc, char **argv)
regs.ecx = 0xCCCCFFFF;
regs.eip = (unsigned long)&instr[0];
regs.edi = (unsigned long)res;
- regs.error_code = PFEC_write_access;
- rc = x86_emulate_memop(&ctxt, &emulops);
- if ( (rc != 0) ||
+ rc = x86_emulate_memop(&ctxt, &emulops);
+ if ( (rc != 0) ||
(res[0] != 0x9999AAAA) ||
(res[1] != 0xCCCCFFFF) ||
((regs.eflags&0x240) != 0x240) ||
@@ -311,7 +313,6 @@ int main(int argc, char **argv)
regs.eflags = 0x200;
regs.eip = (unsigned long)&instr[0];
regs.edi = (unsigned long)res;
- regs.error_code = PFEC_write_access;
rc = x86_emulate_memop(&ctxt, &emulops);
if ( (rc != 0) ||
(res[0] != 0x9999AAAA) ||
@@ -330,7 +331,6 @@ int main(int argc, char **argv)
regs.ecx = 0x12345678;
regs.eax = (unsigned long)res;
*res = 0x82;
- regs.error_code = 0;
rc = x86_emulate_memop(&ctxt, &emulops);
if ( (rc != 0) ||
(*res != 0x82) ||
@@ -347,7 +347,6 @@ int main(int argc, char **argv)
regs.ecx = 0x12345678;
regs.eax = (unsigned long)res;
*res = 0x1234aa82;
- regs.error_code = 0;
rc = x86_emulate_memop(&ctxt, &emulops);
if ( (rc != 0) ||
(*res != 0x1234aa82) ||
@@ -364,7 +363,6 @@ int main(int argc, char **argv)
regs.ecx = (unsigned long)res;
regs.eax = 0x12345678;
*res = 0x11111111;
- regs.error_code = 0;
rc = x86_emulate_memop(&ctxt, &emulops);
if ( (rc != 0) ||
(*res != 0x11116789) ||
diff -r ed815cbdc90e -r 4fb80f21c77d xen/arch/x86/x86_32/seg_fixup.c
--- a/xen/arch/x86/x86_32/seg_fixup.c Wed Dec 20 13:54:04 2006 +0000
+++ b/xen/arch/x86/x86_32/seg_fixup.c Wed Dec 20 15:16:13 2006 +0000
@@ -268,7 +268,7 @@ int gpf_emulate_4gb(struct cpu_user_regs
struct trap_info *ti;
struct trap_bounce *tb;
u8 modrm, mod, reg, rm, decode;
- void *memreg, *regreg;
+ void *memreg;
unsigned long offset;
u8 disp8;
u32 disp32 = 0;
@@ -384,8 +384,7 @@ int gpf_emulate_4gb(struct cpu_user_regs
goto fixme;
}
- /* Decode Reg and R/M fields. */
- regreg = decode_register(reg, regs, 0);
+ /* Decode R/M field. */
memreg = decode_register(rm, regs, 0);
/* Decode Mod field. */
diff -r ed815cbdc90e -r 4fb80f21c77d xen/arch/x86/x86_emulate.c
--- a/xen/arch/x86/x86_emulate.c Wed Dec 20 13:54:04 2006 +0000
+++ b/xen/arch/x86/x86_emulate.c Wed Dec 20 15:16:13 2006 +0000
@@ -192,11 +192,15 @@ struct operand {
enum { OP_REG, OP_MEM, OP_IMM } type;
unsigned int bytes;
unsigned long val, orig_val;
- /* OP_REG: Pointer to register field. */
- unsigned long *reg;
- /* OP_MEM: Segment and offset. */
- enum x86_segment mem_seg;
- unsigned long mem_off;
+ union {
+ /* OP_REG: Pointer to register field. */
+ unsigned long *reg;
+ /* OP_MEM: Segment and offset. */
+ struct {
+ enum x86_segment seg;
+ unsigned long off;
+ } mem;
+ };
};
/* EFLAGS bit definitions. */
@@ -451,8 +455,13 @@ x86_emulate_memop(
struct operand src, dst;
int mode = ctxt->mode;
- enum x86_segment ea_seg = x86_seg_ds;
- unsigned long ea_off = 0;
+ /* Data operand effective address (usually computed from ModRM). */
+ struct operand ea;
+
+ /* Default is a memory operand relative to segment DS. */
+ ea.type = OP_MEM;
+ ea.mem.seg = x86_seg_ds;
+ ea.mem.off = 0;
switch ( mode )
{
@@ -488,22 +497,22 @@ x86_emulate_memop(
ad_bytes ^= 6; /* switch between 2/4 bytes */
break;
case 0x2e: /* CS override */
- ea_seg = x86_seg_cs;
+ ea.mem.seg = x86_seg_cs;
break;
case 0x3e: /* DS override */
- ea_seg = x86_seg_ds;
+ ea.mem.seg = x86_seg_ds;
break;
case 0x26: /* ES override */
- ea_seg = x86_seg_es;
+ ea.mem.seg = x86_seg_es;
break;
case 0x64: /* FS override */
- ea_seg = x86_seg_fs;
+ ea.mem.seg = x86_seg_fs;
break;
case 0x65: /* GS override */
- ea_seg = x86_seg_gs;
+ ea.mem.seg = x86_seg_gs;
break;
case 0x36: /* SS override */
- ea_seg = x86_seg_ss;
+ ea.mem.seg = x86_seg_ss;
break;
case 0xf0: /* LOCK */
lock_prefix = 1;
@@ -554,35 +563,39 @@ x86_emulate_memop(
modrm_rm = modrm & 0x07;
if ( modrm_mod == 3 )
- goto cannot_emulate;
-
- if ( ad_bytes == 2 )
+ {
+ ea.type = OP_REG;
+ ea.reg = decode_register(
+ modrm_rm, &_regs, (d & ByteOp) && (rex_prefix == 0));
+ }
+ else if ( ad_bytes == 2 )
{
/* 16-bit ModR/M decode. */
switch ( modrm_rm )
{
- case 0: ea_off = _regs.ebx + _regs.esi; break;
- case 1: ea_off = _regs.ebx + _regs.edi; break;
- case 2: ea_off = _regs.ebp + _regs.esi; break;
- case 3: ea_off = _regs.ebp + _regs.edi; break;
- case 4: ea_off = _regs.esi; break;
- case 5: ea_off = _regs.edi; break;
- case 6: ea_off = _regs.ebp; break;
- case 7: ea_off = _regs.ebx; break;
+ case 0: ea.mem.off = _regs.ebx + _regs.esi; break;
+ case 1: ea.mem.off = _regs.ebx + _regs.edi; break;
+ case 2: ea.mem.off = _regs.ebp + _regs.esi; break;
+ case 3: ea.mem.off = _regs.ebp + _regs.edi; break;
+ case 4: ea.mem.off = _regs.esi; break;
+ case 5: ea.mem.off = _regs.edi; break;
+ case 6: ea.mem.off = _regs.ebp; break;
+ case 7: ea.mem.off = _regs.ebx; break;
}
switch ( modrm_mod )
{
case 0:
if ( modrm_rm == 6 )
- ea_off = insn_fetch_type(int16_t);
+ ea.mem.off = insn_fetch_type(int16_t);
break;
case 1:
- ea_off += insn_fetch_type(int8_t);
+ ea.mem.off += insn_fetch_type(int8_t);
break;
case 2:
- ea_off += insn_fetch_type(int16_t);
+ ea.mem.off += insn_fetch_type(int16_t);
break;
}
+ ea.mem.off = truncate_ea(ea.mem.off);
}
else
{
@@ -593,49 +606,48 @@ x86_emulate_memop(
sib_index = ((sib >> 3) & 7) | ((rex_prefix << 2) & 8);
sib_base = (sib & 7) | ((rex_prefix << 3) & 8);
if ( sib_index != 4 )
- ea_off = *(long *)decode_register(sib_index, &_regs, 0);
- ea_off <<= (sib >> 6) & 3;
+ ea.mem.off = *(long*)decode_register(sib_index, &_regs, 0);
+ ea.mem.off <<= (sib >> 6) & 3;
if ( (modrm_mod == 0) && ((sib_base & 7) == 5) )
- ea_off += insn_fetch_type(int32_t);
+ ea.mem.off += insn_fetch_type(int32_t);
else
- ea_off += *(long *)decode_register(sib_base, &_regs, 0);
+ ea.mem.off += *(long*)decode_register(sib_base, &_regs, 0);
}
else
{
modrm_rm |= (rex_prefix & 1) << 3;
- ea_off = *(long *)decode_register(modrm_rm, &_regs, 0);
+ ea.mem.off = *(long *)decode_register(modrm_rm, &_regs, 0);
}
switch ( modrm_mod )
{
case 0:
if ( (modrm_rm & 7) != 5 )
break;
- ea_off = insn_fetch_type(int32_t);
+ ea.mem.off = insn_fetch_type(int32_t);
if ( mode != X86EMUL_MODE_PROT64 )
break;
/* Relative to RIP of next instruction. Argh! */
- ea_off += _regs.eip;
+ ea.mem.off += _regs.eip;
if ( (d & SrcMask) == SrcImm )
- ea_off += (d & ByteOp) ? 1 :
+ ea.mem.off += (d & ByteOp) ? 1 :
((op_bytes == 8) ? 4 : op_bytes);
else if ( (d & SrcMask) == SrcImmByte )
- ea_off += 1;
+ ea.mem.off += 1;
else if ( ((b == 0xf6) || (b == 0xf7)) &&
((modrm_reg & 7) <= 1) )
/* Special case in Grp3: test has immediate operand. */
- ea_off += (d & ByteOp) ? 1
+ ea.mem.off += (d & ByteOp) ? 1
: ((op_bytes == 8) ? 4 : op_bytes);
break;
case 1:
- ea_off += insn_fetch_type(int8_t);
+ ea.mem.off += insn_fetch_type(int8_t);
break;
case 2:
- ea_off += insn_fetch_type(int32_t);
+ ea.mem.off += insn_fetch_type(int32_t);
break;
}
- }
-
- ea_off = truncate_ea(ea_off);
+ ea.mem.off = truncate_ea(ea.mem.off);
+ }
}
/* Special instructions do their own operand decoding. */
@@ -652,7 +664,7 @@ x86_emulate_memop(
if ( d & ByteOp )
{
src.reg = decode_register(modrm_reg, &_regs, (rex_prefix == 0));
- src.val = src.orig_val = *(uint8_t *)src.reg;
+ src.val = *(uint8_t *)src.reg;
src.bytes = 1;
}
else
@@ -660,28 +672,35 @@ x86_emulate_memop(
src.reg = decode_register(modrm_reg, &_regs, 0);
switch ( (src.bytes = op_bytes) )
{
- case 2: src.val = src.orig_val = *(uint16_t *)src.reg; break;
- case 4: src.val = src.orig_val = *(uint32_t *)src.reg; break;
- case 8: src.val = src.orig_val = *(uint64_t *)src.reg; break;
+ case 2: src.val = *(uint16_t *)src.reg; break;
+ case 4: src.val = *(uint32_t *)src.reg; break;
+ case 8: src.val = *(uint64_t *)src.reg; break;
}
}
break;
case SrcMem16:
- src.bytes = 2;
+ ea.bytes = 2;
goto srcmem_common;
case SrcMem32:
- src.bytes = 4;
+ ea.bytes = 4;
goto srcmem_common;
case SrcMem:
- src.bytes = (d & ByteOp) ? 1 : op_bytes;
+ ea.bytes = (d & ByteOp) ? 1 : op_bytes;
srcmem_common:
- src.type = OP_MEM;
- src.mem_seg = ea_seg;
- src.mem_off = ea_off;
- if ( (rc = ops->read(src.mem_seg, src.mem_off,
- &src.val, src.bytes, ctxt)) != 0 )
+ src = ea;
+ if ( src.type == OP_REG )
+ {
+ switch ( src.bytes )
+ {
+ case 1: src.val = *(uint8_t *)src.reg; break;
+ case 2: src.val = *(uint16_t *)src.reg; break;
+ case 4: src.val = *(uint32_t *)src.reg; break;
+ case 8: src.val = *(uint64_t *)src.reg; break;
+ }
+ }
+ else if ( (rc = ops->read(src.mem.seg, src.mem.off,
+ &src.val, src.bytes, ctxt)) )
goto done;
- src.orig_val = src.val;
break;
case SrcImm:
src.type = OP_IMM;
@@ -725,8 +744,7 @@ x86_emulate_memop(
}
break;
case DstBitBase:
- dst.mem_off = ea_off;
- if ( (d & SrcMask) == SrcImmByte )
+ if ( ((d & SrcMask) == SrcImmByte) || (ea.type == OP_REG) )
{
src.val &= (op_bytes << 3) - 1;
}
@@ -746,28 +764,34 @@ x86_emulate_memop(
{
unsigned long byte_offset;
byte_offset = op_bytes + (((-src.val-1) >> 3) & ~(op_bytes-1));
- dst.mem_off -= byte_offset;
+ ea.mem.off -= byte_offset;
src.val = (byte_offset << 3) + src.val;
}
else
{
- dst.mem_off += (src.val >> 3) & ~(op_bytes - 1);
+ ea.mem.off += (src.val >> 3) & ~(op_bytes - 1);
src.val &= (op_bytes << 3) - 1;
}
}
/* Becomes a normal DstMem operation from here on. */
d = (d & ~DstMask) | DstMem;
- goto dstmem_common;
case DstMem:
- dst.mem_off = ea_off;
- dstmem_common:
- dst.mem_seg = ea_seg;
- dst.type = OP_MEM;
- dst.bytes = (d & ByteOp) ? 1 : op_bytes;
- if ( !(d & Mov) && /* optimisation - avoid slow emulated read */
- ((rc = ops->read(dst.mem_seg, dst.mem_off,
- &dst.val, dst.bytes, ctxt)) != 0) )
- goto done;
+ ea.bytes = (d & ByteOp) ? 1 : op_bytes;
+ dst = ea;
+ if ( dst.type == OP_REG )
+ {
+ switch ( dst.bytes )
+ {
+ case 1: dst.val = *(uint8_t *)dst.reg; break;
+ case 2: dst.val = *(uint16_t *)dst.reg; break;
+ case 4: dst.val = *(uint32_t *)dst.reg; break;
+ case 8: dst.val = *(uint64_t *)dst.reg; break;
+ }
+ }
+ else if ( !(d & Mov) && /* optimisation - avoid slow emulated read */
+ (rc = ops->read(dst.mem.seg, dst.mem.off,
+ &dst.val, dst.bytes, ctxt)) )
+ goto done;
break;
}
dst.orig_val = dst.val;
@@ -920,7 +944,7 @@ x86_emulate_memop(
if ( mode == X86EMUL_MODE_PROT64 )
{
dst.bytes = 8;
- if ( (rc = ops->read(dst.mem_seg, dst.mem_off,
+ if ( (rc = ops->read(dst.mem.seg, dst.mem.off,
&dst.val, 8, ctxt)) != 0 )
goto done;
}
@@ -954,11 +978,11 @@ x86_emulate_memop(
case OP_MEM:
if ( lock_prefix )
rc = ops->cmpxchg(
- dst.mem_seg, dst.mem_off, dst.orig_val,
+ dst.mem.seg, dst.mem.off, dst.orig_val,
dst.val, dst.bytes, ctxt);
else
rc = ops->write(
- dst.mem_seg, dst.mem_off, dst.val, dst.bytes, ctxt);
+ dst.mem.seg, dst.mem.off, dst.val, dst.bytes, ctxt);
if ( rc != 0 )
goto done;
default:
@@ -987,29 +1011,29 @@ x86_emulate_memop(
}
switch ( b )
{
- case 0xa0 ... 0xa1: /* mov moffs,{%al,%ax,%eax,%rax} */
+ case 0xa0 ... 0xa1: /* mov mem.offs,{%al,%ax,%eax,%rax} */
/* Source EA is not encoded via ModRM. */
dst.type = OP_REG;
dst.reg = (unsigned long *)&_regs.eax;
dst.bytes = (d & ByteOp) ? 1 : op_bytes;
- if ( (rc = ops->read(ea_seg, insn_fetch_bytes(ad_bytes),
+ if ( (rc = ops->read(ea.mem.seg, insn_fetch_bytes(ad_bytes),
&dst.val, dst.bytes, ctxt)) != 0 )
goto done;
break;
- case 0xa2 ... 0xa3: /* mov {%al,%ax,%eax,%rax},moffs */
+ case 0xa2 ... 0xa3: /* mov {%al,%ax,%eax,%rax},mem.offs */
/* Destination EA is not encoded via ModRM. */
- dst.type = OP_MEM;
- dst.mem_seg = ea_seg;
- dst.mem_off = insn_fetch_bytes(ad_bytes);
- dst.bytes = (d & ByteOp) ? 1 : op_bytes;
- dst.val = (unsigned long)_regs.eax;
+ dst.type = OP_MEM;
+ dst.mem.seg = ea.mem.seg;
+ dst.mem.off = insn_fetch_bytes(ad_bytes);
+ dst.bytes = (d & ByteOp) ? 1 : op_bytes;
+ dst.val = (unsigned long)_regs.eax;
break;
case 0xa4 ... 0xa5: /* movs */
dst.type = OP_MEM;
dst.bytes = (d & ByteOp) ? 1 : op_bytes;
- dst.mem_seg = x86_seg_es;
- dst.mem_off = truncate_ea(_regs.edi);
- if ( (rc = ops->read(ea_seg, truncate_ea(_regs.esi),
+ dst.mem.seg = x86_seg_es;
+ dst.mem.off = truncate_ea(_regs.edi);
+ if ( (rc = ops->read(ea.mem.seg, truncate_ea(_regs.esi),
&dst.val, dst.bytes, ctxt)) != 0 )
goto done;
register_address_increment(
@@ -1020,8 +1044,8 @@ x86_emulate_memop(
case 0xaa ... 0xab: /* stos */
dst.type = OP_MEM;
dst.bytes = (d & ByteOp) ? 1 : op_bytes;
- dst.mem_seg = x86_seg_es;
- dst.mem_off = truncate_ea(_regs.edi);
+ dst.mem.seg = x86_seg_es;
+ dst.mem.off = truncate_ea(_regs.edi);
dst.val = _regs.eax;
register_address_increment(
_regs.edi, (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
@@ -1030,7 +1054,7 @@ x86_emulate_memop(
dst.type = OP_REG;
dst.bytes = (d & ByteOp) ? 1 : op_bytes;
dst.reg = (unsigned long *)&_regs.eax;
- if ( (rc = ops->read(ea_seg, truncate_ea(_regs.esi),
+ if ( (rc = ops->read(ea.mem.seg, truncate_ea(_regs.esi),
&dst.val, dst.bytes, ctxt)) != 0 )
goto done;
register_address_increment(
@@ -1105,9 +1129,14 @@ x86_emulate_memop(
case 0xab: bts: /* bts */
emulate_2op_SrcV_nobyte("bts", src, dst, _regs.eflags);
break;
- case 0xb6 ... 0xb7: /* movzx */
+ case 0xb6: /* movzx rm8,r{16,32,64} */
+ /* Recompute DstReg as we may have decoded AH/BH/CH/DH. */
+ dst.reg = decode_register(modrm_reg, &_regs, 0);
dst.bytes = op_bytes;
- dst.val = (d & ByteOp) ? (uint8_t)src.val : (uint16_t)src.val;
+ dst.val = (uint8_t)src.val;
+ break;
+ case 0xb7: /* movzx rm16,r{16,32,64} */
+ dst.val = (uint16_t)src.val;
break;
case 0xbb: btc: /* btc */
emulate_2op_SrcV_nobyte("btc", src, dst, _regs.eflags);
@@ -1121,9 +1150,14 @@ x86_emulate_memop(
case 3: goto btc;
}
break;
- case 0xbe ... 0xbf: /* movsx */
+ case 0xbe: /* movsx rm8,r{16,32,64} */
+ /* Recompute DstReg as we may have decoded AH/BH/CH/DH. */
+ dst.reg = decode_register(modrm_reg, &_regs, 0);
dst.bytes = op_bytes;
- dst.val = (d & ByteOp) ? (int8_t)src.val : (int16_t)src.val;
+ dst.val = (int8_t)src.val;
+ break;
+ case 0xbf: /* movsx rm16,r{16,32,64} */
+ dst.val = (int16_t)src.val;
break;
case 0xc0 ... 0xc1: /* xadd */
/* Write back the register source. */
@@ -1150,8 +1184,8 @@ x86_emulate_memop(
#if defined(__i386__)
{
unsigned long old_lo, old_hi;
- if ( ((rc = ops->read(ea_seg, ea_off+0, &old_lo, 4, ctxt)) != 0) ||
- ((rc = ops->read(ea_seg, ea_off+4, &old_hi, 4, ctxt)) != 0) )
+ if ( (rc = ops->read(ea.mem.seg, ea.mem.off+0, &old_lo, 4, ctxt)) ||
+ (rc = ops->read(ea.mem.seg, ea.mem.off+4, &old_hi, 4, ctxt)) )
goto done;
if ( (old_lo != _regs.eax) || (old_hi != _regs.edx) )
{
@@ -1166,7 +1200,7 @@ x86_emulate_memop(
}
else
{
- if ( (rc = ops->cmpxchg8b(ea_seg, ea_off, old_lo, old_hi,
+ if ( (rc = ops->cmpxchg8b(ea.mem.seg, ea.mem.off, old_lo, old_hi,
_regs.ebx, _regs.ecx, ctxt)) != 0 )
goto done;
_regs.eflags |= EFLG_ZF;
@@ -1176,7 +1210,7 @@ x86_emulate_memop(
#elif defined(__x86_64__)
{
unsigned long old, new;
- if ( (rc = ops->read(ea_seg, ea_off, &old, 8, ctxt)) != 0 )
+ if ( (rc = ops->read(ea.mem.seg, ea.mem.off, &old, 8, ctxt)) != 0 )
goto done;
if ( ((uint32_t)(old>>0) != (uint32_t)_regs.eax) ||
((uint32_t)(old>>32) != (uint32_t)_regs.edx) )
@@ -1188,7 +1222,8 @@ x86_emulate_memop(
else
{
new = (_regs.ecx<<32)|(uint32_t)_regs.ebx;
- if ( (rc = ops->cmpxchg(ea_seg, ea_off, old, new, 8, ctxt)) != 0 )
+ if ( (rc = ops->cmpxchg(ea.mem.seg, ea.mem.off, old,
+ new, 8, ctxt)) != 0 )
goto done;
_regs.eflags |= EFLG_ZF;
}
@@ -1201,10 +1236,10 @@ x86_emulate_memop(
cannot_emulate:
#ifdef __XEN__
gdprintk(XENLOG_DEBUG, "Instr:");
- for ( ea_off = ctxt->regs->eip; ea_off < _regs.eip; ea_off++ )
+ for ( ea.mem.off = ctxt->regs->eip; ea.mem.off < _regs.eip; ea.mem.off++ )
{
unsigned long x;
- ops->insn_fetch(x86_seg_cs, ea_off, &x, 1, ctxt);
+ ops->insn_fetch(x86_seg_cs, ea.mem.off, &x, 1, ctxt);
printk(" %02x", (uint8_t)x);
}
printk("\n");
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|