KVM: Allow passing 64-bit values to the emulated read/write API
This simplifies the API somewhat (by eliminating the special-case cmpxchg8b on i386). Signed-off-by: Avi Kivity <avi@qumranet.com>
This commit is contained in:
parent
1165f5fec1
commit
4c690a1e86
|
@ -970,7 +970,7 @@ void mark_page_dirty(struct kvm *kvm, gfn_t gfn)
|
|||
}
|
||||
|
||||
static int emulator_read_std(unsigned long addr,
|
||||
unsigned long *val,
|
||||
void *val,
|
||||
unsigned int bytes,
|
||||
struct x86_emulate_ctxt *ctxt)
|
||||
{
|
||||
|
@ -1006,7 +1006,7 @@ static int emulator_read_std(unsigned long addr,
|
|||
}
|
||||
|
||||
static int emulator_write_std(unsigned long addr,
|
||||
unsigned long val,
|
||||
const void *val,
|
||||
unsigned int bytes,
|
||||
struct x86_emulate_ctxt *ctxt)
|
||||
{
|
||||
|
@ -1016,7 +1016,7 @@ static int emulator_write_std(unsigned long addr,
|
|||
}
|
||||
|
||||
static int emulator_read_emulated(unsigned long addr,
|
||||
unsigned long *val,
|
||||
void *val,
|
||||
unsigned int bytes,
|
||||
struct x86_emulate_ctxt *ctxt)
|
||||
{
|
||||
|
@ -1044,7 +1044,7 @@ static int emulator_read_emulated(unsigned long addr,
|
|||
}
|
||||
|
||||
static int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa,
|
||||
unsigned long val, int bytes)
|
||||
const void *val, int bytes)
|
||||
{
|
||||
struct page *page;
|
||||
void *virt;
|
||||
|
@ -1057,14 +1057,14 @@ static int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa,
|
|||
kvm_mmu_pre_write(vcpu, gpa, bytes);
|
||||
mark_page_dirty(vcpu->kvm, gpa >> PAGE_SHIFT);
|
||||
virt = kmap_atomic(page, KM_USER0);
|
||||
memcpy(virt + offset_in_page(gpa), &val, bytes);
|
||||
memcpy(virt + offset_in_page(gpa), val, bytes);
|
||||
kunmap_atomic(virt, KM_USER0);
|
||||
kvm_mmu_post_write(vcpu, gpa, bytes);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int emulator_write_emulated(unsigned long addr,
|
||||
unsigned long val,
|
||||
const void *val,
|
||||
unsigned int bytes,
|
||||
struct x86_emulate_ctxt *ctxt)
|
||||
{
|
||||
|
@ -1083,14 +1083,14 @@ static int emulator_write_emulated(unsigned long addr,
|
|||
vcpu->mmio_phys_addr = gpa;
|
||||
vcpu->mmio_size = bytes;
|
||||
vcpu->mmio_is_write = 1;
|
||||
memcpy(vcpu->mmio_data, &val, bytes);
|
||||
memcpy(vcpu->mmio_data, val, bytes);
|
||||
|
||||
return X86EMUL_CONTINUE;
|
||||
}
|
||||
|
||||
static int emulator_cmpxchg_emulated(unsigned long addr,
|
||||
unsigned long old,
|
||||
unsigned long new,
|
||||
const void *old,
|
||||
const void *new,
|
||||
unsigned int bytes,
|
||||
struct x86_emulate_ctxt *ctxt)
|
||||
{
|
||||
|
@ -1103,30 +1103,6 @@ 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);
|
||||
|
@ -1201,9 +1177,6 @@ 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,
|
||||
|
|
|
@ -1045,7 +1045,7 @@ done_prefixes:
|
|||
if ((rc = ops->write_std(
|
||||
register_address(ctxt->ss_base,
|
||||
_regs[VCPU_REGS_RSP]),
|
||||
dst.val, dst.bytes, ctxt)) != 0)
|
||||
&dst.val, dst.bytes, ctxt)) != 0)
|
||||
goto done;
|
||||
dst.val = dst.orig_val; /* skanky: disable writeback */
|
||||
break;
|
||||
|
@ -1078,12 +1078,12 @@ writeback:
|
|||
case OP_MEM:
|
||||
if (lock_prefix)
|
||||
rc = ops->cmpxchg_emulated((unsigned long)dst.
|
||||
ptr, dst.orig_val,
|
||||
dst.val, dst.bytes,
|
||||
ptr, &dst.orig_val,
|
||||
&dst.val, dst.bytes,
|
||||
ctxt);
|
||||
else
|
||||
rc = ops->write_emulated((unsigned long)dst.ptr,
|
||||
dst.val, dst.bytes,
|
||||
&dst.val, dst.bytes,
|
||||
ctxt);
|
||||
if (rc != 0)
|
||||
goto done;
|
||||
|
@ -1321,36 +1321,8 @@ twobyte_special_insn:
|
|||
realmode_set_cr(ctxt->vcpu, modrm_reg, modrm_val, &_eflags);
|
||||
break;
|
||||
case 0xc7: /* Grp9 (cmpxchg8b) */
|
||||
#if defined(__i386__)
|
||||
{
|
||||
unsigned long old_lo, old_hi;
|
||||
if (((rc = ops->read_emulated(cr2 + 0, &old_lo, 4,
|
||||
ctxt)) != 0)
|
||||
|| ((rc = ops->read_emulated(cr2 + 4, &old_hi, 4,
|
||||
ctxt)) != 0))
|
||||
goto done;
|
||||
if ((old_lo != _regs[VCPU_REGS_RAX])
|
||||
|| (old_hi != _regs[VCPU_REGS_RDX])) {
|
||||
_regs[VCPU_REGS_RAX] = old_lo;
|
||||
_regs[VCPU_REGS_RDX] = old_hi;
|
||||
_eflags &= ~EFLG_ZF;
|
||||
} else if (ops->cmpxchg8b_emulated == NULL) {
|
||||
rc = X86EMUL_UNHANDLEABLE;
|
||||
goto done;
|
||||
} else {
|
||||
if ((rc = ops->cmpxchg8b_emulated(cr2, old_lo,
|
||||
old_hi,
|
||||
_regs[VCPU_REGS_RBX],
|
||||
_regs[VCPU_REGS_RCX],
|
||||
ctxt)) != 0)
|
||||
goto done;
|
||||
_eflags |= EFLG_ZF;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#elif defined(CONFIG_X86_64)
|
||||
{
|
||||
unsigned long old, new;
|
||||
u64 old, new;
|
||||
if ((rc = ops->read_emulated(cr2, &old, 8, ctxt)) != 0)
|
||||
goto done;
|
||||
if (((u32) (old >> 0) != (u32) _regs[VCPU_REGS_RAX]) ||
|
||||
|
@ -1359,15 +1331,15 @@ twobyte_special_insn:
|
|||
_regs[VCPU_REGS_RDX] = (u32) (old >> 32);
|
||||
_eflags &= ~EFLG_ZF;
|
||||
} else {
|
||||
new = (_regs[VCPU_REGS_RCX] << 32) | (u32) _regs[VCPU_REGS_RBX];
|
||||
if ((rc = ops->cmpxchg_emulated(cr2, old,
|
||||
new, 8, ctxt)) != 0)
|
||||
new = ((u64)_regs[VCPU_REGS_RCX] << 32)
|
||||
| (u32) _regs[VCPU_REGS_RBX];
|
||||
if ((rc = ops->cmpxchg_emulated(cr2, &old,
|
||||
&new, 8, ctxt)) != 0)
|
||||
goto done;
|
||||
_eflags |= EFLG_ZF;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
goto writeback;
|
||||
|
||||
|
|
|
@ -59,8 +59,7 @@ struct x86_emulate_ops {
|
|||
* @val: [OUT] Value read from memory, zero-extended to 'u_long'.
|
||||
* @bytes: [IN ] Number of bytes to read from memory.
|
||||
*/
|
||||
int (*read_std)(unsigned long addr,
|
||||
unsigned long *val,
|
||||
int (*read_std)(unsigned long addr, void *val,
|
||||
unsigned int bytes, struct x86_emulate_ctxt * ctxt);
|
||||
|
||||
/*
|
||||
|
@ -71,8 +70,7 @@ struct x86_emulate_ops {
|
|||
* required).
|
||||
* @bytes: [IN ] Number of bytes to write to memory.
|
||||
*/
|
||||
int (*write_std)(unsigned long addr,
|
||||
unsigned long val,
|
||||
int (*write_std)(unsigned long addr, const void *val,
|
||||
unsigned int bytes, struct x86_emulate_ctxt * ctxt);
|
||||
|
||||
/*
|
||||
|
@ -82,7 +80,7 @@ struct x86_emulate_ops {
|
|||
* @bytes: [IN ] Number of bytes to read from memory.
|
||||
*/
|
||||
int (*read_emulated) (unsigned long addr,
|
||||
unsigned long *val,
|
||||
void *val,
|
||||
unsigned int bytes,
|
||||
struct x86_emulate_ctxt * ctxt);
|
||||
|
||||
|
@ -94,7 +92,7 @@ struct x86_emulate_ops {
|
|||
* @bytes: [IN ] Number of bytes to write to memory.
|
||||
*/
|
||||
int (*write_emulated) (unsigned long addr,
|
||||
unsigned long val,
|
||||
const void *val,
|
||||
unsigned int bytes,
|
||||
struct x86_emulate_ctxt * ctxt);
|
||||
|
||||
|
@ -107,29 +105,11 @@ struct x86_emulate_ops {
|
|||
* @bytes: [IN ] Number of bytes to access using CMPXCHG.
|
||||
*/
|
||||
int (*cmpxchg_emulated) (unsigned long addr,
|
||||
unsigned long old,
|
||||
unsigned long new,
|
||||
const void *old,
|
||||
const void *new,
|
||||
unsigned int bytes,
|
||||
struct x86_emulate_ctxt * ctxt);
|
||||
|
||||
/*
|
||||
* cmpxchg8b_emulated: Emulate an atomic (LOCKed) CMPXCHG8B operation on an
|
||||
* emulated/special memory area.
|
||||
* @addr: [IN ] Linear address to access.
|
||||
* @old: [IN ] Value expected to be current at @addr.
|
||||
* @new: [IN ] Value to write to @addr.
|
||||
* NOTES:
|
||||
* 1. This function is only ever called when emulating a real CMPXCHG8B.
|
||||
* 2. This function is *never* called on x86/64 systems.
|
||||
* 2. Not defining this function (i.e., specifying NULL) is equivalent
|
||||
* to defining a function that always returns X86EMUL_UNHANDLEABLE.
|
||||
*/
|
||||
int (*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);
|
||||
};
|
||||
|
||||
struct cpu_user_regs;
|
||||
|
|
Loading…
Reference in a new issue