aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGleb Natapov <gleb@redhat.com>2010-03-21 07:08:21 -0400
committerAvi Kivity <avi@redhat.com>2010-05-17 05:16:37 -0400
commit6550e1f165f384f3a46b60a1be9aba4bc3c2adad (patch)
tree791d9eb4de4a87eb77cc49e5035e1508bf4bad22
parent482ac18ae293a3a0b1e1eea95c10dcc9ceeb4708 (diff)
KVM: x86 emulator: add decoding of CMPXCHG8B dst operand
Decode CMPXCHG8B destination operand in decoding stage. Fixes regression introduced by "If LOCK prefix is used dest arg should be memory" commit. This commit relies on dst operand be decoded at the beginning of an instruction emulation. Signed-off-by: Gleb Natapov <gleb@redhat.com> Signed-off-by: Avi Kivity <avi@redhat.com>
-rw-r--r--arch/x86/kvm/emulate.c24
1 files changed, 10 insertions, 14 deletions
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 48de4b890055..b8ce53861f68 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -52,6 +52,7 @@
52#define DstMem (3<<1) /* Memory operand. */ 52#define DstMem (3<<1) /* Memory operand. */
53#define DstAcc (4<<1) /* Destination Accumulator */ 53#define DstAcc (4<<1) /* Destination Accumulator */
54#define DstDI (5<<1) /* Destination is in ES:(E)DI */ 54#define DstDI (5<<1) /* Destination is in ES:(E)DI */
55#define DstMem64 (6<<1) /* 64bit memory operand */
55#define DstMask (7<<1) 56#define DstMask (7<<1)
56/* Source operand type. */ 57/* Source operand type. */
57#define SrcNone (0<<4) /* No source operand. */ 58#define SrcNone (0<<4) /* No source operand. */
@@ -360,7 +361,7 @@ static u32 group_table[] = {
360 DstMem | SrcImmByte | ModRM, DstMem | SrcImmByte | ModRM | Lock, 361 DstMem | SrcImmByte | ModRM, DstMem | SrcImmByte | ModRM | Lock,
361 DstMem | SrcImmByte | ModRM | Lock, DstMem | SrcImmByte | ModRM | Lock, 362 DstMem | SrcImmByte | ModRM | Lock, DstMem | SrcImmByte | ModRM | Lock,
362 [Group9*8] = 363 [Group9*8] =
363 0, ImplicitOps | ModRM | Lock, 0, 0, 0, 0, 0, 0, 364 0, DstMem64 | ModRM | Lock, 0, 0, 0, 0, 0, 0,
364}; 365};
365 366
366static u32 group2_table[] = { 367static u32 group2_table[] = {
@@ -1205,6 +1206,7 @@ done_prefixes:
1205 c->twobyte && (c->b == 0xb6 || c->b == 0xb7)); 1206 c->twobyte && (c->b == 0xb6 || c->b == 0xb7));
1206 break; 1207 break;
1207 case DstMem: 1208 case DstMem:
1209 case DstMem64:
1208 if ((c->d & ModRM) && c->modrm_mod == 3) { 1210 if ((c->d & ModRM) && c->modrm_mod == 3) {
1209 c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; 1211 c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
1210 c->dst.type = OP_REG; 1212 c->dst.type = OP_REG;
@@ -1214,7 +1216,10 @@ done_prefixes:
1214 } 1216 }
1215 c->dst.type = OP_MEM; 1217 c->dst.type = OP_MEM;
1216 c->dst.ptr = (unsigned long *)c->modrm_ea; 1218 c->dst.ptr = (unsigned long *)c->modrm_ea;
1217 c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; 1219 if ((c->d & DstMask) == DstMem64)
1220 c->dst.bytes = 8;
1221 else
1222 c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
1218 c->dst.val = 0; 1223 c->dst.val = 0;
1219 if (c->d & BitOp) { 1224 if (c->d & BitOp) {
1220 unsigned long mask = ~(c->dst.bytes * 8 - 1); 1225 unsigned long mask = ~(c->dst.bytes * 8 - 1);
@@ -1706,12 +1711,7 @@ static inline int emulate_grp9(struct x86_emulate_ctxt *ctxt,
1706 struct x86_emulate_ops *ops) 1711 struct x86_emulate_ops *ops)
1707{ 1712{
1708 struct decode_cache *c = &ctxt->decode; 1713 struct decode_cache *c = &ctxt->decode;
1709 u64 old, new; 1714 u64 old = c->dst.orig_val;
1710 int rc;
1711
1712 rc = ops->read_emulated(c->modrm_ea, &old, 8, ctxt->vcpu);
1713 if (rc != X86EMUL_CONTINUE)
1714 return rc;
1715 1715
1716 if (((u32) (old >> 0) != (u32) c->regs[VCPU_REGS_RAX]) || 1716 if (((u32) (old >> 0) != (u32) c->regs[VCPU_REGS_RAX]) ||
1717 ((u32) (old >> 32) != (u32) c->regs[VCPU_REGS_RDX])) { 1717 ((u32) (old >> 32) != (u32) c->regs[VCPU_REGS_RDX])) {
@@ -1719,15 +1719,12 @@ static inline int emulate_grp9(struct x86_emulate_ctxt *ctxt,
1719 c->regs[VCPU_REGS_RAX] = (u32) (old >> 0); 1719 c->regs[VCPU_REGS_RAX] = (u32) (old >> 0);
1720 c->regs[VCPU_REGS_RDX] = (u32) (old >> 32); 1720 c->regs[VCPU_REGS_RDX] = (u32) (old >> 32);
1721 ctxt->eflags &= ~EFLG_ZF; 1721 ctxt->eflags &= ~EFLG_ZF;
1722
1723 } else { 1722 } else {
1724 new = ((u64)c->regs[VCPU_REGS_RCX] << 32) | 1723 c->dst.val = ((u64)c->regs[VCPU_REGS_RCX] << 32) |
1725 (u32) c->regs[VCPU_REGS_RBX]; 1724 (u32) c->regs[VCPU_REGS_RBX];
1726 1725
1727 rc = ops->cmpxchg_emulated(c->modrm_ea, &old, &new, 8, ctxt->vcpu);
1728 if (rc != X86EMUL_CONTINUE)
1729 return rc;
1730 ctxt->eflags |= EFLG_ZF; 1726 ctxt->eflags |= EFLG_ZF;
1727 c->lock_prefix = 1;
1731 } 1728 }
1732 return X86EMUL_CONTINUE; 1729 return X86EMUL_CONTINUE;
1733} 1730}
@@ -3245,7 +3242,6 @@ twobyte_insn:
3245 rc = emulate_grp9(ctxt, ops); 3242 rc = emulate_grp9(ctxt, ops);
3246 if (rc != X86EMUL_CONTINUE) 3243 if (rc != X86EMUL_CONTINUE)
3247 goto done; 3244 goto done;
3248 c->dst.type = OP_NONE;
3249 break; 3245 break;
3250 } 3246 }
3251 goto writeback; 3247 goto writeback;