# HG changeset patch
# User kfraser@xxxxxxxxxxxxxxxxxxxxx
# Date 1168515704 0
# Node ID a84fc0de350d276cb2b3359102f6fda32bc18922
# Parent c8bfa8d94cf662ae1c5d37309f07002a36725a2b
[XEN] More emulator fixes and emulate BSWAP.
Better handling of LOCK prefix.
Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>
---
xen/arch/x86/x86_emulate.c | 167 ++++++++++++++++++++++++++++++---------------
1 files changed, 112 insertions(+), 55 deletions(-)
diff -r c8bfa8d94cf6 -r a84fc0de350d xen/arch/x86/x86_emulate.c
--- a/xen/arch/x86/x86_emulate.c Thu Jan 11 10:36:41 2007 +0000
+++ b/xen/arch/x86/x86_emulate.c Thu Jan 11 11:41:44 2007 +0000
@@ -178,8 +178,16 @@ static uint8_t twobyte_table[256] = {
/* 0x88 - 0x8F */
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
- /* 0x90 - 0x9F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x90 - 0x97 */
+ ByteOp|DstMem|SrcNone|ModRM|Mov, ByteOp|DstMem|SrcNone|ModRM|Mov,
+ ByteOp|DstMem|SrcNone|ModRM|Mov, ByteOp|DstMem|SrcNone|ModRM|Mov,
+ ByteOp|DstMem|SrcNone|ModRM|Mov, ByteOp|DstMem|SrcNone|ModRM|Mov,
+ ByteOp|DstMem|SrcNone|ModRM|Mov, ByteOp|DstMem|SrcNone|ModRM|Mov,
+ /* 0x98 - 0x9F */
+ ByteOp|DstMem|SrcNone|ModRM|Mov, ByteOp|DstMem|SrcNone|ModRM|Mov,
+ ByteOp|DstMem|SrcNone|ModRM|Mov, ByteOp|DstMem|SrcNone|ModRM|Mov,
+ ByteOp|DstMem|SrcNone|ModRM|Mov, ByteOp|DstMem|SrcNone|ModRM|Mov,
+ ByteOp|DstMem|SrcNone|ModRM|Mov, ByteOp|DstMem|SrcNone|ModRM|Mov,
/* 0xA0 - 0xA7 */
0, 0, 0, DstBitBase|SrcReg|ModRM, 0, 0, 0, 0,
/* 0xA8 - 0xAF */
@@ -195,7 +203,8 @@ static uint8_t twobyte_table[256] = {
ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, 0, 0,
0, 0, 0, ImplicitOps|ModRM,
/* 0xC8 - 0xCF */
- 0, 0, 0, 0, 0, 0, 0, 0,
+ ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
+ ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
/* 0xD0 - 0xDF */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xE0 - 0xEF */
@@ -206,7 +215,7 @@ static uint8_t twobyte_table[256] = {
/* Type, address-of, and value of an instruction's operand. */
struct operand {
- enum { OP_REG, OP_MEM, OP_IMM } type;
+ enum { OP_REG, OP_MEM, OP_IMM, OP_NONE } type;
unsigned int bytes;
unsigned long val, orig_val;
union {
@@ -635,6 +644,9 @@ x86_emulate(
goto cannot_emulate;
}
+ /* Lock prefix is allowed only on RMW instructions. */
+ generate_exception_if((d & Mov) && lock_prefix, EXC_GP);
+
/* ModRM and SIB bytes. */
if ( d & ModRM )
{
@@ -874,13 +886,18 @@ x86_emulate(
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;
+ else if ( !(d & Mov) ) /* optimisation - avoid slow emulated read */
+ {
+ if ( (rc = ops->read(dst.mem.seg, dst.mem.off,
+ &dst.val, dst.bytes, ctxt)) )
+ goto done;
+ dst.orig_val = dst.val;
+ }
+ break;
+ }
+
+ /* LOCK prefix allowed only on instructions with memory destination. */
+ generate_exception_if(lock_prefix && (dst.type != OP_MEM), EXC_GP);
if ( twobyte )
goto twobyte_insn;
@@ -889,56 +906,56 @@ x86_emulate(
{
case 0x04 ... 0x05: /* add imm,%%eax */
dst.reg = (unsigned long *)&_regs.eax;
- dst.val = dst.orig_val = _regs.eax;
+ dst.val = _regs.eax;
case 0x00 ... 0x03: add: /* add */
emulate_2op_SrcV("add", src, dst, _regs.eflags);
break;
case 0x0c ... 0x0d: /* or imm,%%eax */
dst.reg = (unsigned long *)&_regs.eax;
- dst.val = dst.orig_val = _regs.eax;
+ dst.val = _regs.eax;
case 0x08 ... 0x0b: or: /* or */
emulate_2op_SrcV("or", src, dst, _regs.eflags);
break;
case 0x14 ... 0x15: /* adc imm,%%eax */
dst.reg = (unsigned long *)&_regs.eax;
- dst.val = dst.orig_val = _regs.eax;
+ dst.val = _regs.eax;
case 0x10 ... 0x13: adc: /* adc */
emulate_2op_SrcV("adc", src, dst, _regs.eflags);
break;
case 0x1c ... 0x1d: /* sbb imm,%%eax */
dst.reg = (unsigned long *)&_regs.eax;
- dst.val = dst.orig_val = _regs.eax;
+ dst.val = _regs.eax;
case 0x18 ... 0x1b: sbb: /* sbb */
emulate_2op_SrcV("sbb", src, dst, _regs.eflags);
break;
case 0x24 ... 0x25: /* and imm,%%eax */
dst.reg = (unsigned long *)&_regs.eax;
- dst.val = dst.orig_val = _regs.eax;
+ dst.val = _regs.eax;
case 0x20 ... 0x23: and: /* and */
emulate_2op_SrcV("and", src, dst, _regs.eflags);
break;
case 0x2c ... 0x2d: /* sub imm,%%eax */
dst.reg = (unsigned long *)&_regs.eax;
- dst.val = dst.orig_val = _regs.eax;
+ dst.val = _regs.eax;
case 0x28 ... 0x2b: sub: /* sub */
emulate_2op_SrcV("sub", src, dst, _regs.eflags);
break;
case 0x34 ... 0x35: /* xor imm,%%eax */
dst.reg = (unsigned long *)&_regs.eax;
- dst.val = dst.orig_val = _regs.eax;
+ dst.val = _regs.eax;
case 0x30 ... 0x33: xor: /* xor */
emulate_2op_SrcV("xor", src, dst, _regs.eflags);
break;
case 0x3c ... 0x3d: /* cmp imm,%%eax */
dst.reg = (unsigned long *)&_regs.eax;
- dst.val = dst.orig_val = _regs.eax;
+ dst.val = _regs.eax;
case 0x38 ... 0x3b: cmp: /* cmp */
emulate_2op_SrcV("cmp", src, dst, _regs.eflags);
break;
@@ -965,7 +982,7 @@ x86_emulate(
case 0xa8 ... 0xa9: /* test imm,%%eax */
dst.reg = (unsigned long *)&_regs.eax;
- dst.val = dst.orig_val = _regs.eax;
+ dst.val = _regs.eax;
case 0x84 ... 0x85: test: /* test */
emulate_2op_SrcV("test", src, dst, _regs.eflags);
break;
@@ -1106,7 +1123,7 @@ x86_emulate(
if ( (rc = ops->write(x86_seg_ss, truncate_ea(_regs.esp),
dst.val, dst.bytes, ctxt)) != 0 )
goto done;
- dst.val = dst.orig_val; /* skanky: disable writeback */
+ dst.type = OP_NONE;
break;
case 7:
fail_if(1);
@@ -1117,33 +1134,32 @@ x86_emulate(
}
writeback:
- if ( (d & Mov) || (dst.orig_val != dst.val) )
- {
- switch ( dst.type )
- {
- case OP_REG:
- /* The 4-byte case *is* correct: in 64-bit mode we zero-extend. */
- switch ( dst.bytes )
- {
- case 1: *(uint8_t *)dst.reg = (uint8_t)dst.val; break;
- case 2: *(uint16_t *)dst.reg = (uint16_t)dst.val; break;
- case 4: *dst.reg = (uint32_t)dst.val; break; /* 64b: zero-ext */
- case 8: *dst.reg = dst.val; break;
- }
- break;
- case OP_MEM:
- if ( lock_prefix )
- rc = ops->cmpxchg(
- 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);
- if ( rc != 0 )
- goto done;
- default:
- break;
- }
+ switch ( dst.type )
+ {
+ case OP_REG:
+ /* The 4-byte case *is* correct: in 64-bit mode we zero-extend. */
+ switch ( dst.bytes )
+ {
+ case 1: *(uint8_t *)dst.reg = (uint8_t)dst.val; break;
+ case 2: *(uint16_t *)dst.reg = (uint16_t)dst.val; break;
+ case 4: *dst.reg = (uint32_t)dst.val; break; /* 64b: zero-ext */
+ case 8: *dst.reg = dst.val; break;
+ }
+ break;
+ case OP_MEM:
+ if ( !(d & Mov) && (dst.orig_val == dst.val) )
+ /* nothing to do */;
+ else if ( lock_prefix )
+ rc = ops->cmpxchg(
+ 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);
+ if ( rc != 0 )
+ goto done;
+ default:
+ break;
}
/* Commit shadow register state. */
@@ -1153,8 +1169,13 @@ x86_emulate(
return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0;
special_insn:
- /* Default action: disable writeback. There may be no dest operand. */
- dst.orig_val = dst.val;
+ dst.type = OP_NONE;
+
+ /*
+ * The only implicit-operands instruction allowed a LOCK prefix is
+ * CMPXCHG{8,16}B.
+ */
+ generate_exception_if(lock_prefix && (b != 0xc7), EXC_GP);
if ( twobyte )
goto twobyte_special_insn;
@@ -1235,7 +1256,7 @@ x86_emulate(
dst.type = OP_REG;
dst.reg = decode_register(b & 7, &_regs, 0);
dst.bytes = op_bytes;
- dst.orig_val = dst.val = *dst.reg;
+ dst.val = *dst.reg;
if ( b & 8 )
emulate_1op("dec", dst, _regs.eflags);
else
@@ -1285,7 +1306,7 @@ x86_emulate(
src.val = *src.reg;
dst.reg = decode_register(
(b & 7) | ((rex_prefix & 1) << 3), &_regs, 0);
- dst.val = dst.orig_val = *dst.reg;
+ dst.val = *dst.reg;
goto xchg;
case 0x9e: /* sahf */
@@ -1430,9 +1451,14 @@ x86_emulate(
twobyte_insn:
switch ( b )
{
- case 0x40 ... 0x4f: /* cmov */
- dst.val = dst.orig_val = src.val;
- d = (d & ~Mov) | (test_cc(b, _regs.eflags) ? Mov : 0);
+ case 0x40 ... 0x4f: /* cmovcc */
+ dst.val = src.val;
+ if ( !test_cc(b, _regs.eflags) )
+ dst.type = OP_NONE;
+ break;
+
+ case 0x90 ... 0x9f: /* setcc */
+ dst.val = test_cc(b, _regs.eflags);
break;
case 0xb0 ... 0xb1: /* cmpxchg */
@@ -1580,6 +1606,37 @@ x86_emulate(
break;
}
#endif
+
+ case 0xc8 ... 0xcf: /* bswap */
+ dst.type = OP_REG;
+ dst.reg = decode_register(b & 7, &_regs, 0);
+ dst.val = *dst.reg;
+ switch ( dst.bytes = op_bytes )
+ {
+ case 2:
+ dst.val = (((dst.val & 0x00FFUL) << 8) |
+ ((dst.val & 0xFF00UL) >> 8));
+ break;
+ case 4:
+ dst.val = (((dst.val & 0x000000FFUL) << 24) |
+ ((dst.val & 0x0000FF00UL) << 8) |
+ ((dst.val & 0x00FF0000UL) >> 8) |
+ ((dst.val & 0xFF000000UL) >> 24));
+ break;
+#ifdef __x86_64__
+ case 8:
+ dst.val = (((dst.val & 0x00000000000000FFUL) << 56) |
+ ((dst.val & 0x000000000000FF00UL) << 40) |
+ ((dst.val & 0x0000000000FF0000UL) << 24) |
+ ((dst.val & 0x00000000FF000000UL) << 8) |
+ ((dst.val & 0x000000FF00000000UL) >> 8) |
+ ((dst.val & 0x0000FF0000000000UL) >> 24) |
+ ((dst.val & 0x00FF000000000000UL) >> 40) |
+ ((dst.val & 0xFF00000000000000UL) >> 56));
+ break;
+#endif
+ }
+ break;
}
goto writeback;
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|