Commit c3cd7ffa authored by Gleb Natapov's avatar Gleb Natapov Committed by Avi Kivity

KVM: x86 emulator: x86_emulate_insn() return -1 only in case of emulation failure

Currently emulator returns -1 when emulation failed or IO is needed.
Caller tries to guess whether emulation failed by looking at other
variables. Make it easier for caller to recognise error condition by
always returning -1 in case of failure. For this new emulator
internal return value X86EMUL_IO_NEEDED is introduced. It is used to
distinguish between error condition (which returns X86EMUL_UNHANDLEABLE)
and condition that requires IO exit to userspace to continue emulation.
Signed-off-by: default avatarGleb Natapov <gleb@redhat.com>
Signed-off-by: default avatarAvi Kivity <avi@redhat.com>
parent 411c35b7
...@@ -53,6 +53,7 @@ struct x86_emulate_ctxt; ...@@ -53,6 +53,7 @@ struct x86_emulate_ctxt;
#define X86EMUL_PROPAGATE_FAULT 2 /* propagate a generated fault to guest */ #define X86EMUL_PROPAGATE_FAULT 2 /* propagate a generated fault to guest */
#define X86EMUL_RETRY_INSTR 3 /* retry the instruction for some reason */ #define X86EMUL_RETRY_INSTR 3 /* retry the instruction for some reason */
#define X86EMUL_CMPXCHG_FAILED 4 /* cmpxchg did not see expected value */ #define X86EMUL_CMPXCHG_FAILED 4 /* cmpxchg did not see expected value */
#define X86EMUL_IO_NEEDED 5 /* IO is needed to complete emulation */
struct x86_emulate_ops { struct x86_emulate_ops {
/* /*
......
...@@ -3275,7 +3275,7 @@ static int kvm_read_guest_virt_helper(gva_t addr, void *val, unsigned int bytes, ...@@ -3275,7 +3275,7 @@ static int kvm_read_guest_virt_helper(gva_t addr, void *val, unsigned int bytes,
} }
ret = kvm_read_guest(vcpu->kvm, gpa, data, toread); ret = kvm_read_guest(vcpu->kvm, gpa, data, toread);
if (ret < 0) { if (ret < 0) {
r = X86EMUL_UNHANDLEABLE; r = X86EMUL_IO_NEEDED;
goto out; goto out;
} }
...@@ -3331,7 +3331,7 @@ static int kvm_write_guest_virt_system(gva_t addr, void *val, ...@@ -3331,7 +3331,7 @@ static int kvm_write_guest_virt_system(gva_t addr, void *val,
} }
ret = kvm_write_guest(vcpu->kvm, gpa, data, towrite); ret = kvm_write_guest(vcpu->kvm, gpa, data, towrite);
if (ret < 0) { if (ret < 0) {
r = X86EMUL_UNHANDLEABLE; r = X86EMUL_IO_NEEDED;
goto out; goto out;
} }
...@@ -3391,7 +3391,7 @@ static int emulator_read_emulated(unsigned long addr, ...@@ -3391,7 +3391,7 @@ static int emulator_read_emulated(unsigned long addr,
vcpu->run->mmio.len = vcpu->mmio_size = bytes; vcpu->run->mmio.len = vcpu->mmio_size = bytes;
vcpu->run->mmio.is_write = vcpu->mmio_is_write = 0; vcpu->run->mmio.is_write = vcpu->mmio_is_write = 0;
return X86EMUL_UNHANDLEABLE; return X86EMUL_IO_NEEDED;
} }
int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa, int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa,
...@@ -3863,8 +3863,6 @@ int emulate_instruction(struct kvm_vcpu *vcpu, ...@@ -3863,8 +3863,6 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
*/ */
cache_all_regs(vcpu); cache_all_regs(vcpu);
vcpu->mmio_is_write = 0;
if (!(emulation_type & EMULTYPE_NO_DECODE)) { if (!(emulation_type & EMULTYPE_NO_DECODE)) {
int cs_db, cs_l; int cs_db, cs_l;
kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l); kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l);
...@@ -3938,24 +3936,26 @@ int emulate_instruction(struct kvm_vcpu *vcpu, ...@@ -3938,24 +3936,26 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
return EMULATE_DO_MMIO; return EMULATE_DO_MMIO;
} }
if (r) { if (vcpu->mmio_needed) {
if (kvm_mmu_unprotect_page_virt(vcpu, cr2)) if (vcpu->mmio_is_write)
goto done; vcpu->mmio_needed = 0;
if (!vcpu->mmio_needed) {
++vcpu->stat.insn_emulation_fail;
trace_kvm_emulate_insn_failed(vcpu);
kvm_report_emulation_failure(vcpu, "mmio");
return EMULATE_FAIL;
}
return EMULATE_DO_MMIO; return EMULATE_DO_MMIO;
} }
if (vcpu->mmio_is_write) { if (r) { /* emulation failed */
vcpu->mmio_needed = 0; /*
return EMULATE_DO_MMIO; * if emulation was due to access to shadowed page table
* and it failed try to unshadow page and re-entetr the
* guest to let CPU execute the instruction.
*/
if (kvm_mmu_unprotect_page_virt(vcpu, cr2))
return EMULATE_DONE;
trace_kvm_emulate_insn_failed(vcpu);
kvm_report_emulation_failure(vcpu, "mmio");
return EMULATE_FAIL;
} }
done:
if (vcpu->arch.exception.pending) if (vcpu->arch.exception.pending)
vcpu->arch.emulate_ctxt.restart = false; vcpu->arch.emulate_ctxt.restart = false;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment