From: Mihai Donțu <mdo...@bitdefender.com>

As it was the case for lock cmpxchg, lock cmpxchg8b was emulated in two
steps the first one setting/clearing the zero flag and the last one
making the actual atomic operation.

This patch fixes that by combining the two, ie. the writeback step is
no longer necessary as the first step made the changes directly in
memory.

Signed-off-by: Mihai Donțu <mdo...@bitdefender.com>
Signed-off-by: Adalbert Lazăr <ala...@bitdefender.com>
---
 arch/x86/kvm/emulate.c | 42 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 41 insertions(+), 1 deletion(-)

diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index dac4c0ca1ee3..2038e42c1eae 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -2320,7 +2320,47 @@ static int em_call_near_abs(struct x86_emulate_ctxt 
*ctxt)
 
 static int em_cmpxchg8b(struct x86_emulate_ctxt *ctxt)
 {
-       u64 old = ctxt->dst.orig_val64;
+       u64 old;
+
+       if (ctxt->lock_prefix) {
+               int rc;
+               ulong linear;
+               u64 new = (reg_read(ctxt, VCPU_REGS_RBX) & (u32)-1) |
+                       ((reg_read(ctxt, VCPU_REGS_RCX) & (u32)-1) << 32);
+
+               old = (reg_read(ctxt, VCPU_REGS_RAX) & (u32)-1) |
+                       ((reg_read(ctxt, VCPU_REGS_RDX) & (u32)-1) << 32);
+
+               /* disable writeback altogether */
+               ctxt->d &= ~SrcWrite;
+               ctxt->d |= NoWrite;
+
+               rc = linearize(ctxt, ctxt->dst.addr.mem, 8, true, &linear);
+               if (rc != X86EMUL_CONTINUE)
+                       return rc;
+
+               rc = ctxt->ops->cmpxchg_emulated(ctxt, linear, &old, &new,
+                                                ctxt->dst.bytes,
+                                                &ctxt->exception);
+
+               switch (rc) {
+               case X86EMUL_CONTINUE:
+                       ctxt->eflags |= X86_EFLAGS_ZF;
+                       break;
+               case X86EMUL_CMPXCHG_FAILED:
+                       *reg_write(ctxt, VCPU_REGS_RAX) = old & (u32)-1;
+                       *reg_write(ctxt, VCPU_REGS_RDX) = (old >> 32) & (u32)-1;
+
+                       ctxt->eflags &= ~X86_EFLAGS_ZF;
+
+                       rc = X86EMUL_CONTINUE;
+                       break;
+               }
+
+               return rc;
+       }
+
+       old = ctxt->dst.orig_val64;
 
        if (ctxt->dst.bytes == 16)
                return X86EMUL_UNHANDLEABLE;
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

Reply via email to