diff options
author | Gleb Natapov <gleb@redhat.com> | 2010-03-18 09:20:23 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2010-05-17 05:16:25 -0400 |
commit | cf8f70bfe38b326bb80b10f76d6544f571040229 (patch) | |
tree | d646456d773a887ca592d174b3d45a57d2779d85 /arch/x86/kvm/svm.c | |
parent | d9271123a46011af26da680baeb7fdf67b498abf (diff) |
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>
Diffstat (limited to 'arch/x86/kvm/svm.c')
-rw-r--r-- | arch/x86/kvm/svm.c | 20 |
1 files changed, 7 insertions, 13 deletions
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index abbc3f9d03b2..e9f79619e185 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c | |||
@@ -1494,29 +1494,23 @@ static int shutdown_interception(struct vcpu_svm *svm) | |||
1494 | 1494 | ||
1495 | static int io_interception(struct vcpu_svm *svm) | 1495 | static int io_interception(struct vcpu_svm *svm) |
1496 | { | 1496 | { |
1497 | struct kvm_vcpu *vcpu = &svm->vcpu; | ||
1497 | u32 io_info = svm->vmcb->control.exit_info_1; /* address size bug? */ | 1498 | u32 io_info = svm->vmcb->control.exit_info_1; /* address size bug? */ |
1498 | int size, in, string; | 1499 | int size, in, string; |
1499 | unsigned port; | 1500 | unsigned port; |
1500 | 1501 | ||
1501 | ++svm->vcpu.stat.io_exits; | 1502 | ++svm->vcpu.stat.io_exits; |
1502 | |||
1503 | svm->next_rip = svm->vmcb->control.exit_info_2; | ||
1504 | |||
1505 | string = (io_info & SVM_IOIO_STR_MASK) != 0; | 1503 | string = (io_info & SVM_IOIO_STR_MASK) != 0; |
1506 | |||
1507 | if (string) { | ||
1508 | if (emulate_instruction(&svm->vcpu, | ||
1509 | 0, 0, 0) == EMULATE_DO_MMIO) | ||
1510 | return 0; | ||
1511 | return 1; | ||
1512 | } | ||
1513 | |||
1514 | in = (io_info & SVM_IOIO_TYPE_MASK) != 0; | 1504 | in = (io_info & SVM_IOIO_TYPE_MASK) != 0; |
1505 | if (string || in) | ||
1506 | return !(emulate_instruction(vcpu, 0, 0, 0) == EMULATE_DO_MMIO); | ||
1507 | |||
1515 | port = io_info >> 16; | 1508 | port = io_info >> 16; |
1516 | size = (io_info & SVM_IOIO_SIZE_MASK) >> SVM_IOIO_SIZE_SHIFT; | 1509 | size = (io_info & SVM_IOIO_SIZE_MASK) >> SVM_IOIO_SIZE_SHIFT; |
1517 | 1510 | svm->next_rip = svm->vmcb->control.exit_info_2; | |
1518 | skip_emulated_instruction(&svm->vcpu); | 1511 | skip_emulated_instruction(&svm->vcpu); |
1519 | return kvm_emulate_pio(&svm->vcpu, in, size, port); | 1512 | |
1513 | return kvm_fast_pio_out(vcpu, size, port); | ||
1520 | } | 1514 | } |
1521 | 1515 | ||
1522 | static int nmi_interception(struct vcpu_svm *svm) | 1516 | static int nmi_interception(struct vcpu_svm *svm) |