mirror of https://gitee.com/openkylin/linux.git
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,
|
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,
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue