Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 32b35627 authored by Avi Kivity's avatar Avi Kivity Committed by Linus Torvalds
Browse files

[PATCH] KVM: MMU: Fix cmpxchg8b emulation



cmpxchg8b uses edx:eax as the compare operand, not edi:eax.

cmpxchg8b is used by 32-bit pae guests to set page table entries atomically,
and this is emulated touching shadowed guest page tables.

Also, implement it for 32-bit hosts.

Signed-off-by: default avatarAvi Kivity <avi@qumranet.com>
Acked-by: default avatarIngo Molnar <mingo@elte.hu>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 3bb65a22
Loading
Loading
Loading
Loading
+27 −0
Original line number Diff line number Diff line
@@ -936,6 +936,30 @@ static int emulator_cmpxchg_emulated(unsigned long addr,
	return emulator_write_emulated(addr, new, bytes, ctxt);
}

#ifdef CONFIG_X86_32

static int emulator_cmpxchg8b_emulated(unsigned long addr,
				       unsigned long old_lo,
				       unsigned long old_hi,
				       unsigned long new_lo,
				       unsigned long new_hi,
				       struct x86_emulate_ctxt *ctxt)
{
	static int reported;
	int r;

	if (!reported) {
		reported = 1;
		printk(KERN_WARNING "kvm: emulating exchange8b as write\n");
	}
	r = emulator_write_emulated(addr, new_lo, 4, ctxt);
	if (r != X86EMUL_CONTINUE)
		return r;
	return emulator_write_emulated(addr+4, new_hi, 4, ctxt);
}

#endif

static unsigned long get_segment_base(struct kvm_vcpu *vcpu, int seg)
{
	return kvm_arch_ops->get_segment_base(vcpu, seg);
@@ -1010,6 +1034,9 @@ struct x86_emulate_ops emulate_ops = {
	.read_emulated       = emulator_read_emulated,
	.write_emulated      = emulator_write_emulated,
	.cmpxchg_emulated    = emulator_cmpxchg_emulated,
#ifdef CONFIG_X86_32
	.cmpxchg8b_emulated  = emulator_cmpxchg8b_emulated,
#endif
};

int emulate_instruction(struct kvm_vcpu *vcpu,
+1 −1
Original line number Diff line number Diff line
@@ -1323,7 +1323,7 @@ twobyte_special_insn:
							 ctxt)) != 0))
				goto done;
			if ((old_lo != _regs[VCPU_REGS_RAX])
			    || (old_hi != _regs[VCPU_REGS_RDI])) {
			    || (old_hi != _regs[VCPU_REGS_RDX])) {
				_regs[VCPU_REGS_RAX] = old_lo;
				_regs[VCPU_REGS_RDX] = old_hi;
				_eflags &= ~EFLG_ZF;