static int emulator_cmpxchg_emulated(struct x86_emulate_ctxt *ctxt,
				     unsigned long addr,
				     const void *old,
				     const void *new,
				     unsigned int bytes,
				     struct x86_exception *exception)
{
	struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt);
	u64 page_line_mask;
	unsigned long hva;
	gpa_t gpa;
	int r;

	/* guests cmpxchg8b have to be emulated atomically */
	if (bytes > 8 || (bytes & (bytes - 1)))
		goto emul_write;

	gpa = kvm_mmu_gva_to_gpa_write(vcpu, addr, NULL);

	if (gpa == UNMAPPED_GVA ||
	    (gpa & PAGE_MASK) == APIC_DEFAULT_PHYS_BASE)
		goto emul_write;

	/*
	 * Emulate the atomic as a straight write to avoid #AC if SLD is
	 * enabled in the host and the access splits a cache line.
	 */
	if (boot_cpu_has(X86_FEATURE_SPLIT_LOCK_DETECT))
		page_line_mask = ~(cache_line_size() - 1);
	else
		page_line_mask = PAGE_MASK;

	if (((gpa + bytes - 1) & page_line_mask) != (gpa & page_line_mask))
		goto emul_write;

	hva = kvm_vcpu_gfn_to_hva(vcpu, gpa_to_gfn(gpa));
	if (kvm_is_error_hva(hva))
		goto emul_write;

	hva += offset_in_page(gpa);

	switch (bytes) {
	case 1:
		r = emulator_try_cmpxchg_user(u8, hva, old, new);
		break;
	case 2:
		r = emulator_try_cmpxchg_user(u16, hva, old, new);
		break;
	case 4:
		r = emulator_try_cmpxchg_user(u32, hva, old, new);
		break;
	case 8:
		r = emulator_try_cmpxchg_user(u64, hva, old, new);
		break;
	default:
		BUG();
	}

	if (r < 0)
		return X86EMUL_UNHANDLEABLE;
	if (r)
		return X86EMUL_CMPXCHG_FAILED;

	kvm_page_track_write(vcpu, gpa, new, bytes);

	return X86EMUL_CONTINUE;

emul_write:
	printk_once(KERN_WARNING "kvm: emulating exchange as write\n");

	return emulator_write_emulated(ctxt, addr, new, bytes, exception);
}
static int emulator_cmpxchg_emulated(struct x86_emulate_ctxt *ctxt,
				     unsigned long addr,
				     const void *old,
				     const void *new,
				     unsigned int bytes,
				     struct x86_exception *exception)
{
	struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt);
	u64 page_line_mask;
	unsigned long hva;
	gpa_t gpa;
	int r;

	 
	if (bytes > 8 || (bytes & (bytes - 1)))
		goto emul_write;

	gpa = kvm_mmu_gva_to_gpa_write(vcpu, addr, NULL);

	if (gpa == UNMAPPED_GVA ||
	    (gpa & PAGE_MASK) == APIC_DEFAULT_PHYS_BASE)
		goto emul_write;

	 
	if (boot_cpu_has(X86_FEATURE_SPLIT_LOCK_DETECT))
		page_line_mask = ~(cache_line_size() - 1);
	else
		page_line_mask = PAGE_MASK;

	if (((gpa + bytes - 1) & page_line_mask) != (gpa & page_line_mask))
		goto emul_write;

	hva = kvm_vcpu_gfn_to_hva(vcpu, gpa_to_gfn(gpa));
	if (kvm_is_error_hva(hva))
		goto emul_write;

	hva += offset_in_page(gpa);

	switch (bytes) {
	case 1:
		r = emulator_try_cmpxchg_user(u8, hva, old, new);
		break;
	case 2:
		r = emulator_try_cmpxchg_user(u16, hva, old, new);
		break;
	case 4:
		r = emulator_try_cmpxchg_user(u32, hva, old, new);
		break;
	case 8:
		r = emulator_try_cmpxchg_user(u64, hva, old, new);
		break;
	default:
		BUG();
	}

	if (r < 0)
		return X86EMUL_UNHANDLEABLE;
	if (r)
		return X86EMUL_CMPXCHG_FAILED;

	kvm_page_track_write(vcpu, gpa, new, bytes);

	return X86EMUL_CONTINUE;

emul_write:
	printk_once(KERN_WARNING "kvm: emulating exchange as write\n");

	return emulator_write_emulated(ctxt, addr, new, bytes, exception);
}