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/x86.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/x86.c')
-rw-r--r-- | arch/x86/kvm/x86.c | 213 |
1 files changed, 131 insertions, 82 deletions
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index f69854c8f339..6624ad13ee99 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
@@ -3404,6 +3404,86 @@ emul_write: | |||
3404 | return emulator_write_emulated(addr, new, bytes, vcpu); | 3404 | return emulator_write_emulated(addr, new, bytes, vcpu); |
3405 | } | 3405 | } |
3406 | 3406 | ||
3407 | static int kernel_pio(struct kvm_vcpu *vcpu, void *pd) | ||
3408 | { | ||
3409 | /* TODO: String I/O for in kernel device */ | ||
3410 | int r; | ||
3411 | |||
3412 | if (vcpu->arch.pio.in) | ||
3413 | r = kvm_io_bus_read(vcpu->kvm, KVM_PIO_BUS, vcpu->arch.pio.port, | ||
3414 | vcpu->arch.pio.size, pd); | ||
3415 | else | ||
3416 | r = kvm_io_bus_write(vcpu->kvm, KVM_PIO_BUS, | ||
3417 | vcpu->arch.pio.port, vcpu->arch.pio.size, | ||
3418 | pd); | ||
3419 | return r; | ||
3420 | } | ||
3421 | |||
3422 | |||
3423 | static int emulator_pio_in_emulated(int size, unsigned short port, void *val, | ||
3424 | unsigned int count, struct kvm_vcpu *vcpu) | ||
3425 | { | ||
3426 | if (vcpu->arch.pio.cur_count) | ||
3427 | goto data_avail; | ||
3428 | |||
3429 | trace_kvm_pio(1, port, size, 1); | ||
3430 | |||
3431 | vcpu->arch.pio.port = port; | ||
3432 | vcpu->arch.pio.in = 1; | ||
3433 | vcpu->arch.pio.string = 0; | ||
3434 | vcpu->arch.pio.down = 0; | ||
3435 | vcpu->arch.pio.rep = 0; | ||
3436 | vcpu->arch.pio.count = vcpu->arch.pio.cur_count = count; | ||
3437 | vcpu->arch.pio.size = size; | ||
3438 | |||
3439 | if (!kernel_pio(vcpu, vcpu->arch.pio_data)) { | ||
3440 | data_avail: | ||
3441 | memcpy(val, vcpu->arch.pio_data, size * count); | ||
3442 | vcpu->arch.pio.cur_count = 0; | ||
3443 | return 1; | ||
3444 | } | ||
3445 | |||
3446 | vcpu->run->exit_reason = KVM_EXIT_IO; | ||
3447 | vcpu->run->io.direction = KVM_EXIT_IO_IN; | ||
3448 | vcpu->run->io.size = size; | ||
3449 | vcpu->run->io.data_offset = KVM_PIO_PAGE_OFFSET * PAGE_SIZE; | ||
3450 | vcpu->run->io.count = count; | ||
3451 | vcpu->run->io.port = port; | ||
3452 | |||
3453 | return 0; | ||
3454 | } | ||
3455 | |||
3456 | static int emulator_pio_out_emulated(int size, unsigned short port, | ||
3457 | const void *val, unsigned int count, | ||
3458 | struct kvm_vcpu *vcpu) | ||
3459 | { | ||
3460 | trace_kvm_pio(0, port, size, 1); | ||
3461 | |||
3462 | vcpu->arch.pio.port = port; | ||
3463 | vcpu->arch.pio.in = 0; | ||
3464 | vcpu->arch.pio.string = 0; | ||
3465 | vcpu->arch.pio.down = 0; | ||
3466 | vcpu->arch.pio.rep = 0; | ||
3467 | vcpu->arch.pio.count = vcpu->arch.pio.cur_count = count; | ||
3468 | vcpu->arch.pio.size = size; | ||
3469 | |||
3470 | memcpy(vcpu->arch.pio_data, val, size * count); | ||
3471 | |||
3472 | if (!kernel_pio(vcpu, vcpu->arch.pio_data)) { | ||
3473 | vcpu->arch.pio.cur_count = 0; | ||
3474 | return 1; | ||
3475 | } | ||
3476 | |||
3477 | vcpu->run->exit_reason = KVM_EXIT_IO; | ||
3478 | vcpu->run->io.direction = KVM_EXIT_IO_OUT; | ||
3479 | vcpu->run->io.size = size; | ||
3480 | vcpu->run->io.data_offset = KVM_PIO_PAGE_OFFSET * PAGE_SIZE; | ||
3481 | vcpu->run->io.count = count; | ||
3482 | vcpu->run->io.port = port; | ||
3483 | |||
3484 | return 0; | ||
3485 | } | ||
3486 | |||
3407 | static unsigned long get_segment_base(struct kvm_vcpu *vcpu, int seg) | 3487 | static unsigned long get_segment_base(struct kvm_vcpu *vcpu, int seg) |
3408 | { | 3488 | { |
3409 | return kvm_x86_ops->get_segment_base(vcpu, seg); | 3489 | return kvm_x86_ops->get_segment_base(vcpu, seg); |
@@ -3597,6 +3677,8 @@ static struct x86_emulate_ops emulate_ops = { | |||
3597 | .read_emulated = emulator_read_emulated, | 3677 | .read_emulated = emulator_read_emulated, |
3598 | .write_emulated = emulator_write_emulated, | 3678 | .write_emulated = emulator_write_emulated, |
3599 | .cmpxchg_emulated = emulator_cmpxchg_emulated, | 3679 | .cmpxchg_emulated = emulator_cmpxchg_emulated, |
3680 | .pio_in_emulated = emulator_pio_in_emulated, | ||
3681 | .pio_out_emulated = emulator_pio_out_emulated, | ||
3600 | .get_cached_descriptor = emulator_get_cached_descriptor, | 3682 | .get_cached_descriptor = emulator_get_cached_descriptor, |
3601 | .set_cached_descriptor = emulator_set_cached_descriptor, | 3683 | .set_cached_descriptor = emulator_set_cached_descriptor, |
3602 | .get_segment_selector = emulator_get_segment_selector, | 3684 | .get_segment_selector = emulator_get_segment_selector, |
@@ -3704,6 +3786,12 @@ int emulate_instruction(struct kvm_vcpu *vcpu, | |||
3704 | if (vcpu->arch.pio.string) | 3786 | if (vcpu->arch.pio.string) |
3705 | return EMULATE_DO_MMIO; | 3787 | return EMULATE_DO_MMIO; |
3706 | 3788 | ||
3789 | if (vcpu->arch.pio.cur_count && !vcpu->arch.pio.string) { | ||
3790 | if (!vcpu->arch.pio.in) | ||
3791 | vcpu->arch.pio.cur_count = 0; | ||
3792 | return EMULATE_DO_MMIO; | ||
3793 | } | ||
3794 | |||
3707 | if (r || vcpu->mmio_is_write) { | 3795 | if (r || vcpu->mmio_is_write) { |
3708 | run->exit_reason = KVM_EXIT_MMIO; | 3796 | run->exit_reason = KVM_EXIT_MMIO; |
3709 | run->mmio.phys_addr = vcpu->mmio_phys_addr; | 3797 | run->mmio.phys_addr = vcpu->mmio_phys_addr; |
@@ -3760,43 +3848,36 @@ int complete_pio(struct kvm_vcpu *vcpu) | |||
3760 | int r; | 3848 | int r; |
3761 | unsigned long val; | 3849 | unsigned long val; |
3762 | 3850 | ||
3763 | if (!io->string) { | 3851 | if (io->in) { |
3764 | if (io->in) { | 3852 | r = pio_copy_data(vcpu); |
3765 | val = kvm_register_read(vcpu, VCPU_REGS_RAX); | 3853 | if (r) |
3766 | memcpy(&val, vcpu->arch.pio_data, io->size); | 3854 | goto out; |
3767 | kvm_register_write(vcpu, VCPU_REGS_RAX, val); | 3855 | } |
3768 | } | ||
3769 | } else { | ||
3770 | if (io->in) { | ||
3771 | r = pio_copy_data(vcpu); | ||
3772 | if (r) | ||
3773 | goto out; | ||
3774 | } | ||
3775 | 3856 | ||
3776 | delta = 1; | 3857 | delta = 1; |
3777 | if (io->rep) { | 3858 | if (io->rep) { |
3778 | delta *= io->cur_count; | 3859 | delta *= io->cur_count; |
3779 | /* | 3860 | /* |
3780 | * The size of the register should really depend on | 3861 | * The size of the register should really depend on |
3781 | * current address size. | 3862 | * current address size. |
3782 | */ | 3863 | */ |
3783 | val = kvm_register_read(vcpu, VCPU_REGS_RCX); | 3864 | val = kvm_register_read(vcpu, VCPU_REGS_RCX); |
3784 | val -= delta; | 3865 | val -= delta; |
3785 | kvm_register_write(vcpu, VCPU_REGS_RCX, val); | 3866 | kvm_register_write(vcpu, VCPU_REGS_RCX, val); |
3786 | } | 3867 | } |
3787 | if (io->down) | 3868 | if (io->down) |
3788 | delta = -delta; | 3869 | delta = -delta; |
3789 | delta *= io->size; | 3870 | delta *= io->size; |
3790 | if (io->in) { | 3871 | if (io->in) { |
3791 | val = kvm_register_read(vcpu, VCPU_REGS_RDI); | 3872 | val = kvm_register_read(vcpu, VCPU_REGS_RDI); |
3792 | val += delta; | 3873 | val += delta; |
3793 | kvm_register_write(vcpu, VCPU_REGS_RDI, val); | 3874 | kvm_register_write(vcpu, VCPU_REGS_RDI, val); |
3794 | } else { | 3875 | } else { |
3795 | val = kvm_register_read(vcpu, VCPU_REGS_RSI); | 3876 | val = kvm_register_read(vcpu, VCPU_REGS_RSI); |
3796 | val += delta; | 3877 | val += delta; |
3797 | kvm_register_write(vcpu, VCPU_REGS_RSI, val); | 3878 | kvm_register_write(vcpu, VCPU_REGS_RSI, val); |
3798 | } | ||
3799 | } | 3879 | } |
3880 | |||
3800 | out: | 3881 | out: |
3801 | io->count -= io->cur_count; | 3882 | io->count -= io->cur_count; |
3802 | io->cur_count = 0; | 3883 | io->cur_count = 0; |
@@ -3804,21 +3885,6 @@ out: | |||
3804 | return 0; | 3885 | return 0; |
3805 | } | 3886 | } |
3806 | 3887 | ||
3807 | static int kernel_pio(struct kvm_vcpu *vcpu, void *pd) | ||
3808 | { | ||
3809 | /* TODO: String I/O for in kernel device */ | ||
3810 | int r; | ||
3811 | |||
3812 | if (vcpu->arch.pio.in) | ||
3813 | r = kvm_io_bus_read(vcpu->kvm, KVM_PIO_BUS, vcpu->arch.pio.port, | ||
3814 | vcpu->arch.pio.size, pd); | ||
3815 | else | ||
3816 | r = kvm_io_bus_write(vcpu->kvm, KVM_PIO_BUS, | ||
3817 | vcpu->arch.pio.port, vcpu->arch.pio.size, | ||
3818 | pd); | ||
3819 | return r; | ||
3820 | } | ||
3821 | |||
3822 | static int pio_string_write(struct kvm_vcpu *vcpu) | 3888 | static int pio_string_write(struct kvm_vcpu *vcpu) |
3823 | { | 3889 | { |
3824 | struct kvm_pio_request *io = &vcpu->arch.pio; | 3890 | struct kvm_pio_request *io = &vcpu->arch.pio; |
@@ -3836,36 +3902,6 @@ static int pio_string_write(struct kvm_vcpu *vcpu) | |||
3836 | return r; | 3902 | return r; |
3837 | } | 3903 | } |
3838 | 3904 | ||
3839 | int kvm_emulate_pio(struct kvm_vcpu *vcpu, int in, int size, unsigned port) | ||
3840 | { | ||
3841 | unsigned long val; | ||
3842 | |||
3843 | trace_kvm_pio(!in, port, size, 1); | ||
3844 | |||
3845 | vcpu->run->exit_reason = KVM_EXIT_IO; | ||
3846 | vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT; | ||
3847 | vcpu->run->io.size = vcpu->arch.pio.size = size; | ||
3848 | vcpu->run->io.data_offset = KVM_PIO_PAGE_OFFSET * PAGE_SIZE; | ||
3849 | vcpu->run->io.count = vcpu->arch.pio.count = vcpu->arch.pio.cur_count = 1; | ||
3850 | vcpu->run->io.port = vcpu->arch.pio.port = port; | ||
3851 | vcpu->arch.pio.in = in; | ||
3852 | vcpu->arch.pio.string = 0; | ||
3853 | vcpu->arch.pio.down = 0; | ||
3854 | vcpu->arch.pio.rep = 0; | ||
3855 | |||
3856 | if (!vcpu->arch.pio.in) { | ||
3857 | val = kvm_register_read(vcpu, VCPU_REGS_RAX); | ||
3858 | memcpy(vcpu->arch.pio_data, &val, 4); | ||
3859 | } | ||
3860 | |||
3861 | if (!kernel_pio(vcpu, vcpu->arch.pio_data)) { | ||
3862 | complete_pio(vcpu); | ||
3863 | return 1; | ||
3864 | } | ||
3865 | return 0; | ||
3866 | } | ||
3867 | EXPORT_SYMBOL_GPL(kvm_emulate_pio); | ||
3868 | |||
3869 | int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, int in, | 3905 | int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, int in, |
3870 | int size, unsigned long count, int down, | 3906 | int size, unsigned long count, int down, |
3871 | gva_t address, int rep, unsigned port) | 3907 | gva_t address, int rep, unsigned port) |
@@ -3931,6 +3967,16 @@ int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, int in, | |||
3931 | } | 3967 | } |
3932 | EXPORT_SYMBOL_GPL(kvm_emulate_pio_string); | 3968 | EXPORT_SYMBOL_GPL(kvm_emulate_pio_string); |
3933 | 3969 | ||
3970 | int kvm_fast_pio_out(struct kvm_vcpu *vcpu, int size, unsigned short port) | ||
3971 | { | ||
3972 | unsigned long val = kvm_register_read(vcpu, VCPU_REGS_RAX); | ||
3973 | int ret = emulator_pio_out_emulated(size, port, &val, 1, vcpu); | ||
3974 | /* do not return to emulator after return from userspace */ | ||
3975 | vcpu->arch.pio.cur_count = 0; | ||
3976 | return ret; | ||
3977 | } | ||
3978 | EXPORT_SYMBOL_GPL(kvm_fast_pio_out); | ||
3979 | |||
3934 | static void bounce_off(void *info) | 3980 | static void bounce_off(void *info) |
3935 | { | 3981 | { |
3936 | /* nothing */ | 3982 | /* nothing */ |
@@ -4661,9 +4707,12 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
4661 | 4707 | ||
4662 | if (vcpu->arch.pio.cur_count) { | 4708 | if (vcpu->arch.pio.cur_count) { |
4663 | vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu); | 4709 | vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu); |
4664 | r = complete_pio(vcpu); | 4710 | if (!vcpu->arch.pio.string) |
4711 | r = emulate_instruction(vcpu, 0, 0, EMULTYPE_NO_DECODE); | ||
4712 | else | ||
4713 | r = complete_pio(vcpu); | ||
4665 | srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx); | 4714 | srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx); |
4666 | if (r) | 4715 | if (r == EMULATE_DO_MMIO) |
4667 | goto out; | 4716 | goto out; |
4668 | } | 4717 | } |
4669 | if (vcpu->mmio_needed) { | 4718 | if (vcpu->mmio_needed) { |