KVM: x86 emulator: fix in/out emulation.
in/out emulation is broken now. The breakage is different depending on where IO device resides. If it is in userspace emulator reports emulation failure since it incorrectly interprets kvm_emulate_pio() return value. If IO device is in the kernel emulation of 'in' will do nothing since kvm_emulate_pio() stores result directly into vcpu registers, so emulator will overwrite result of emulation during commit of shadowed register. Signed-off-by: Gleb Natapov <gleb@redhat.com> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
This commit is contained in:
@@ -1494,29 +1494,23 @@ static int shutdown_interception(struct vcpu_svm *svm)
|
||||
|
||||
static int io_interception(struct vcpu_svm *svm)
|
||||
{
|
||||
struct kvm_vcpu *vcpu = &svm->vcpu;
|
||||
u32 io_info = svm->vmcb->control.exit_info_1; /* address size bug? */
|
||||
int size, in, string;
|
||||
unsigned port;
|
||||
|
||||
++svm->vcpu.stat.io_exits;
|
||||
|
||||
svm->next_rip = svm->vmcb->control.exit_info_2;
|
||||
|
||||
string = (io_info & SVM_IOIO_STR_MASK) != 0;
|
||||
|
||||
if (string) {
|
||||
if (emulate_instruction(&svm->vcpu,
|
||||
0, 0, 0) == EMULATE_DO_MMIO)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
in = (io_info & SVM_IOIO_TYPE_MASK) != 0;
|
||||
if (string || in)
|
||||
return !(emulate_instruction(vcpu, 0, 0, 0) == EMULATE_DO_MMIO);
|
||||
|
||||
port = io_info >> 16;
|
||||
size = (io_info & SVM_IOIO_SIZE_MASK) >> SVM_IOIO_SIZE_SHIFT;
|
||||
|
||||
svm->next_rip = svm->vmcb->control.exit_info_2;
|
||||
skip_emulated_instruction(&svm->vcpu);
|
||||
return kvm_emulate_pio(&svm->vcpu, in, size, port);
|
||||
|
||||
return kvm_fast_pio_out(vcpu, size, port);
|
||||
}
|
||||
|
||||
static int nmi_interception(struct vcpu_svm *svm)
|
||||
|
Reference in New Issue
Block a user