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:
Avi Kivity 2007-04-22 15:28:19 +03:00
parent 1165f5fec1
commit 4c690a1e86
3 changed files with 24 additions and 99 deletions

View File

@ -970,7 +970,7 @@ void mark_page_dirty(struct kvm *kvm, gfn_t gfn)
} }
static int emulator_read_std(unsigned long addr, static int emulator_read_std(unsigned long addr,
unsigned long *val, void *val,
unsigned int bytes, unsigned int bytes,
struct x86_emulate_ctxt *ctxt) 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, static int emulator_write_std(unsigned long addr,
unsigned long val, const void *val,
unsigned int bytes, unsigned int bytes,
struct x86_emulate_ctxt *ctxt) 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, static int emulator_read_emulated(unsigned long addr,
unsigned long *val, void *val,
unsigned int bytes, unsigned int bytes,
struct x86_emulate_ctxt *ctxt) 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, 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; struct page *page;
void *virt; 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); kvm_mmu_pre_write(vcpu, gpa, bytes);
mark_page_dirty(vcpu->kvm, gpa >> PAGE_SHIFT); mark_page_dirty(vcpu->kvm, gpa >> PAGE_SHIFT);
virt = kmap_atomic(page, KM_USER0); 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); kunmap_atomic(virt, KM_USER0);
kvm_mmu_post_write(vcpu, gpa, bytes); kvm_mmu_post_write(vcpu, gpa, bytes);
return 1; return 1;
} }
static int emulator_write_emulated(unsigned long addr, static int emulator_write_emulated(unsigned long addr,
unsigned long val, const void *val,
unsigned int bytes, unsigned int bytes,
struct x86_emulate_ctxt *ctxt) struct x86_emulate_ctxt *ctxt)
{ {
@ -1083,14 +1083,14 @@ static int emulator_write_emulated(unsigned long addr,
vcpu->mmio_phys_addr = gpa; vcpu->mmio_phys_addr = gpa;
vcpu->mmio_size = bytes; vcpu->mmio_size = bytes;
vcpu->mmio_is_write = 1; vcpu->mmio_is_write = 1;
memcpy(vcpu->mmio_data, &val, bytes); memcpy(vcpu->mmio_data, val, bytes);
return X86EMUL_CONTINUE; return X86EMUL_CONTINUE;
} }
static int emulator_cmpxchg_emulated(unsigned long addr, static int emulator_cmpxchg_emulated(unsigned long addr,
unsigned long old, const void *old,
unsigned long new, const void *new,
unsigned int bytes, unsigned int bytes,
struct x86_emulate_ctxt *ctxt) 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); 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) static unsigned long get_segment_base(struct kvm_vcpu *vcpu, int seg)
{ {
return kvm_arch_ops->get_segment_base(vcpu, 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, .read_emulated = emulator_read_emulated,
.write_emulated = emulator_write_emulated, .write_emulated = emulator_write_emulated,
.cmpxchg_emulated = emulator_cmpxchg_emulated, .cmpxchg_emulated = emulator_cmpxchg_emulated,
#ifdef CONFIG_X86_32
.cmpxchg8b_emulated = emulator_cmpxchg8b_emulated,
#endif
}; };
int emulate_instruction(struct kvm_vcpu *vcpu, int emulate_instruction(struct kvm_vcpu *vcpu,

View File

@ -1045,7 +1045,7 @@ x86_emulate_memop(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
if ((rc = ops->write_std( if ((rc = ops->write_std(
register_address(ctxt->ss_base, register_address(ctxt->ss_base,
_regs[VCPU_REGS_RSP]), _regs[VCPU_REGS_RSP]),
dst.val, dst.bytes, ctxt)) != 0) &dst.val, dst.bytes, ctxt)) != 0)
goto done; goto done;
dst.val = dst.orig_val; /* skanky: disable writeback */ dst.val = dst.orig_val; /* skanky: disable writeback */
break; break;
@ -1078,12 +1078,12 @@ x86_emulate_memop(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
case OP_MEM: case OP_MEM:
if (lock_prefix) if (lock_prefix)
rc = ops->cmpxchg_emulated((unsigned long)dst. rc = ops->cmpxchg_emulated((unsigned long)dst.
ptr, dst.orig_val, ptr, &dst.orig_val,
dst.val, dst.bytes, &dst.val, dst.bytes,
ctxt); ctxt);
else else
rc = ops->write_emulated((unsigned long)dst.ptr, rc = ops->write_emulated((unsigned long)dst.ptr,
dst.val, dst.bytes, &dst.val, dst.bytes,
ctxt); ctxt);
if (rc != 0) if (rc != 0)
goto done; goto done;
@ -1321,36 +1321,8 @@ x86_emulate_memop(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
realmode_set_cr(ctxt->vcpu, modrm_reg, modrm_val, &_eflags); realmode_set_cr(ctxt->vcpu, modrm_reg, modrm_val, &_eflags);
break; break;
case 0xc7: /* Grp9 (cmpxchg8b) */ case 0xc7: /* Grp9 (cmpxchg8b) */
#if defined(__i386__)
{ {
unsigned long old_lo, old_hi; u64 old, new;
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;
if ((rc = ops->read_emulated(cr2, &old, 8, ctxt)) != 0) if ((rc = ops->read_emulated(cr2, &old, 8, ctxt)) != 0)
goto done; goto done;
if (((u32) (old >> 0) != (u32) _regs[VCPU_REGS_RAX]) || if (((u32) (old >> 0) != (u32) _regs[VCPU_REGS_RAX]) ||
@ -1359,15 +1331,15 @@ x86_emulate_memop(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
_regs[VCPU_REGS_RDX] = (u32) (old >> 32); _regs[VCPU_REGS_RDX] = (u32) (old >> 32);
_eflags &= ~EFLG_ZF; _eflags &= ~EFLG_ZF;
} else { } else {
new = (_regs[VCPU_REGS_RCX] << 32) | (u32) _regs[VCPU_REGS_RBX]; new = ((u64)_regs[VCPU_REGS_RCX] << 32)
if ((rc = ops->cmpxchg_emulated(cr2, old, | (u32) _regs[VCPU_REGS_RBX];
new, 8, ctxt)) != 0) if ((rc = ops->cmpxchg_emulated(cr2, &old,
&new, 8, ctxt)) != 0)
goto done; goto done;
_eflags |= EFLG_ZF; _eflags |= EFLG_ZF;
} }
break; break;
} }
#endif
} }
goto writeback; goto writeback;

View File

@ -59,8 +59,7 @@ struct x86_emulate_ops {
* @val: [OUT] Value read from memory, zero-extended to 'u_long'. * @val: [OUT] Value read from memory, zero-extended to 'u_long'.
* @bytes: [IN ] Number of bytes to read from memory. * @bytes: [IN ] Number of bytes to read from memory.
*/ */
int (*read_std)(unsigned long addr, int (*read_std)(unsigned long addr, void *val,
unsigned long *val,
unsigned int bytes, struct x86_emulate_ctxt * ctxt); unsigned int bytes, struct x86_emulate_ctxt * ctxt);
/* /*
@ -71,8 +70,7 @@ struct x86_emulate_ops {
* required). * required).
* @bytes: [IN ] Number of bytes to write to memory. * @bytes: [IN ] Number of bytes to write to memory.
*/ */
int (*write_std)(unsigned long addr, int (*write_std)(unsigned long addr, const void *val,
unsigned long val,
unsigned int bytes, struct x86_emulate_ctxt * ctxt); 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. * @bytes: [IN ] Number of bytes to read from memory.
*/ */
int (*read_emulated) (unsigned long addr, int (*read_emulated) (unsigned long addr,
unsigned long *val, void *val,
unsigned int bytes, unsigned int bytes,
struct x86_emulate_ctxt * ctxt); struct x86_emulate_ctxt * ctxt);
@ -94,7 +92,7 @@ struct x86_emulate_ops {
* @bytes: [IN ] Number of bytes to write to memory. * @bytes: [IN ] Number of bytes to write to memory.
*/ */
int (*write_emulated) (unsigned long addr, int (*write_emulated) (unsigned long addr,
unsigned long val, const void *val,
unsigned int bytes, unsigned int bytes,
struct x86_emulate_ctxt * ctxt); struct x86_emulate_ctxt * ctxt);
@ -107,29 +105,11 @@ struct x86_emulate_ops {
* @bytes: [IN ] Number of bytes to access using CMPXCHG. * @bytes: [IN ] Number of bytes to access using CMPXCHG.
*/ */
int (*cmpxchg_emulated) (unsigned long addr, int (*cmpxchg_emulated) (unsigned long addr,
unsigned long old, const void *old,
unsigned long new, const void *new,
unsigned int bytes, unsigned int bytes,
struct x86_emulate_ctxt * ctxt); 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; struct cpu_user_regs;