aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGleb Natapov <gleb@redhat.com>2010-03-18 09:20:24 -0400
committerAvi Kivity <avi@redhat.com>2010-05-17 05:16:26 -0400
commit7972995b0c346de76fe260ce0fd6bcc8ffab724a (patch)
treea2522988d8cd465b836c0a32399d8eeb7a3ed545
parentcf8f70bfe38b326bb80b10f76d6544f571040229 (diff)
KVM: x86 emulator: Move string pio emulation into emulator.c
Currently emulation is done outside of emulator so things like doing ins/outs to/from mmio are broken it also makes it hard (if not impossible) to implement single stepping in the future. The implementation in this patch is not efficient since it exits to userspace for each IO while previous implementation did 'ins' in batches. Further patch that implements pio in string read ahead address this problem. Signed-off-by: Gleb Natapov <gleb@redhat.com> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
-rw-r--r--arch/x86/include/asm/kvm_host.h8
-rw-r--r--arch/x86/kvm/emulate.c48
-rw-r--r--arch/x86/kvm/x86.c206
3 files changed, 32 insertions, 230 deletions
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 776d3e202b56..26c629a062db 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -224,14 +224,9 @@ struct kvm_pv_mmu_op_buffer {
224 224
225struct kvm_pio_request { 225struct kvm_pio_request {
226 unsigned long count; 226 unsigned long count;
227 int cur_count;
228 gva_t guest_gva;
229 int in; 227 int in;
230 int port; 228 int port;
231 int size; 229 int size;
232 int string;
233 int down;
234 int rep;
235}; 230};
236 231
237/* 232/*
@@ -591,9 +586,6 @@ int kvm_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data);
591struct x86_emulate_ctxt; 586struct x86_emulate_ctxt;
592 587
593int kvm_fast_pio_out(struct kvm_vcpu *vcpu, int size, unsigned short port); 588int kvm_fast_pio_out(struct kvm_vcpu *vcpu, int size, unsigned short port);
594int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, int in,
595 int size, unsigned long count, int down,
596 gva_t address, int rep, unsigned port);
597void kvm_emulate_cpuid(struct kvm_vcpu *vcpu); 589void kvm_emulate_cpuid(struct kvm_vcpu *vcpu);
598int kvm_emulate_halt(struct kvm_vcpu *vcpu); 590int kvm_emulate_halt(struct kvm_vcpu *vcpu);
599int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address); 591int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address);
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 2d095ce9dc87..2c66e097d916 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -153,8 +153,8 @@ static u32 opcode_table[256] = {
153 0, 0, 0, 0, 153 0, 0, 0, 0,
154 /* 0x68 - 0x6F */ 154 /* 0x68 - 0x6F */
155 SrcImm | Mov | Stack, 0, SrcImmByte | Mov | Stack, 0, 155 SrcImm | Mov | Stack, 0, SrcImmByte | Mov | Stack, 0,
156 SrcNone | ByteOp | ImplicitOps, SrcNone | ImplicitOps, /* insb, insw/insd */ 156 DstDI | ByteOp | Mov | String, DstDI | Mov | String, /* insb, insw/insd */
157 SrcNone | ByteOp | ImplicitOps, SrcNone | ImplicitOps, /* outsb, outsw/outsd */ 157 SrcSI | ByteOp | ImplicitOps | String, SrcSI | ImplicitOps | String, /* outsb, outsw/outsd */
158 /* 0x70 - 0x77 */ 158 /* 0x70 - 0x77 */
159 SrcImmByte, SrcImmByte, SrcImmByte, SrcImmByte, 159 SrcImmByte, SrcImmByte, SrcImmByte, SrcImmByte,
160 SrcImmByte, SrcImmByte, SrcImmByte, SrcImmByte, 160 SrcImmByte, SrcImmByte, SrcImmByte, SrcImmByte,
@@ -2615,47 +2615,29 @@ special_insn:
2615 break; 2615 break;
2616 case 0x6c: /* insb */ 2616 case 0x6c: /* insb */
2617 case 0x6d: /* insw/insd */ 2617 case 0x6d: /* insw/insd */
2618 c->dst.bytes = min(c->dst.bytes, 4u);
2618 if (!emulator_io_permited(ctxt, ops, c->regs[VCPU_REGS_RDX], 2619 if (!emulator_io_permited(ctxt, ops, c->regs[VCPU_REGS_RDX],
2619 (c->d & ByteOp) ? 1 : c->op_bytes)) { 2620 c->dst.bytes)) {
2620 kvm_inject_gp(ctxt->vcpu, 0); 2621 kvm_inject_gp(ctxt->vcpu, 0);
2621 goto done; 2622 goto done;
2622 } 2623 }
2623 if (kvm_emulate_pio_string(ctxt->vcpu, 2624 if (!ops->pio_in_emulated(c->dst.bytes, c->regs[VCPU_REGS_RDX],
2624 1, 2625 &c->dst.val, 1, ctxt->vcpu))
2625 (c->d & ByteOp) ? 1 : c->op_bytes, 2626 goto done; /* IO is needed, skip writeback */
2626 c->rep_prefix ? 2627 break;
2627 address_mask(c, c->regs[VCPU_REGS_RCX]) : 1,
2628 (ctxt->eflags & EFLG_DF),
2629 register_address(c, es_base(ctxt),
2630 c->regs[VCPU_REGS_RDI]),
2631 c->rep_prefix,
2632 c->regs[VCPU_REGS_RDX]) == 0) {
2633 c->eip = saved_eip;
2634 return -1;
2635 }
2636 return 0;
2637 case 0x6e: /* outsb */ 2628 case 0x6e: /* outsb */
2638 case 0x6f: /* outsw/outsd */ 2629 case 0x6f: /* outsw/outsd */
2630 c->src.bytes = min(c->src.bytes, 4u);
2639 if (!emulator_io_permited(ctxt, ops, c->regs[VCPU_REGS_RDX], 2631 if (!emulator_io_permited(ctxt, ops, c->regs[VCPU_REGS_RDX],
2640 (c->d & ByteOp) ? 1 : c->op_bytes)) { 2632 c->src.bytes)) {
2641 kvm_inject_gp(ctxt->vcpu, 0); 2633 kvm_inject_gp(ctxt->vcpu, 0);
2642 goto done; 2634 goto done;
2643 } 2635 }
2644 if (kvm_emulate_pio_string(ctxt->vcpu, 2636 ops->pio_out_emulated(c->src.bytes, c->regs[VCPU_REGS_RDX],
2645 0, 2637 &c->src.val, 1, ctxt->vcpu);
2646 (c->d & ByteOp) ? 1 : c->op_bytes, 2638
2647 c->rep_prefix ? 2639 c->dst.type = OP_NONE; /* nothing to writeback */
2648 address_mask(c, c->regs[VCPU_REGS_RCX]) : 1, 2640 break;
2649 (ctxt->eflags & EFLG_DF),
2650 register_address(c,
2651 seg_override_base(ctxt, c),
2652 c->regs[VCPU_REGS_RSI]),
2653 c->rep_prefix,
2654 c->regs[VCPU_REGS_RDX]) == 0) {
2655 c->eip = saved_eip;
2656 return -1;
2657 }
2658 return 0;
2659 case 0x70 ... 0x7f: /* jcc (short) */ 2641 case 0x70 ... 0x7f: /* jcc (short) */
2660 if (test_cc(c->b, ctxt->eflags)) 2642 if (test_cc(c->b, ctxt->eflags))
2661 jmp_rel(c, c->src.val); 2643 jmp_rel(c, c->src.val);
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 6624ad13ee99..658e8e8155cb 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -3150,18 +3150,17 @@ static int kvm_read_guest_virt_system(gva_t addr, void *val, unsigned int bytes,
3150 return kvm_read_guest_virt_helper(addr, val, bytes, vcpu, 0, error); 3150 return kvm_read_guest_virt_helper(addr, val, bytes, vcpu, 0, error);
3151} 3151}
3152 3152
3153static int kvm_write_guest_virt_helper(gva_t addr, void *val, 3153static int kvm_write_guest_virt_system(gva_t addr, void *val,
3154 unsigned int bytes, 3154 unsigned int bytes,
3155 struct kvm_vcpu *vcpu, u32 access, 3155 struct kvm_vcpu *vcpu,
3156 u32 *error) 3156 u32 *error)
3157{ 3157{
3158 void *data = val; 3158 void *data = val;
3159 int r = X86EMUL_CONTINUE; 3159 int r = X86EMUL_CONTINUE;
3160 3160
3161 access |= PFERR_WRITE_MASK;
3162
3163 while (bytes) { 3161 while (bytes) {
3164 gpa_t gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr, access, error); 3162 gpa_t gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr,
3163 PFERR_WRITE_MASK, error);
3165 unsigned offset = addr & (PAGE_SIZE-1); 3164 unsigned offset = addr & (PAGE_SIZE-1);
3166 unsigned towrite = min(bytes, (unsigned)PAGE_SIZE - offset); 3165 unsigned towrite = min(bytes, (unsigned)PAGE_SIZE - offset);
3167 int ret; 3166 int ret;
@@ -3184,20 +3183,6 @@ out:
3184 return r; 3183 return r;
3185} 3184}
3186 3185
3187static int kvm_write_guest_virt(gva_t addr, void *val, unsigned int bytes,
3188 struct kvm_vcpu *vcpu, u32 *error)
3189{
3190 u32 access = (kvm_x86_ops->get_cpl(vcpu) == 3) ? PFERR_USER_MASK : 0;
3191 return kvm_write_guest_virt_helper(addr, val, bytes, vcpu, access, error);
3192}
3193
3194static int kvm_write_guest_virt_system(gva_t addr, void *val,
3195 unsigned int bytes,
3196 struct kvm_vcpu *vcpu, u32 *error)
3197{
3198 return kvm_write_guest_virt_helper(addr, val, bytes, vcpu, 0, error);
3199}
3200
3201static int emulator_read_emulated(unsigned long addr, 3186static int emulator_read_emulated(unsigned long addr,
3202 void *val, 3187 void *val,
3203 unsigned int bytes, 3188 unsigned int bytes,
@@ -3423,23 +3408,20 @@ static int kernel_pio(struct kvm_vcpu *vcpu, void *pd)
3423static int emulator_pio_in_emulated(int size, unsigned short port, void *val, 3408static int emulator_pio_in_emulated(int size, unsigned short port, void *val,
3424 unsigned int count, struct kvm_vcpu *vcpu) 3409 unsigned int count, struct kvm_vcpu *vcpu)
3425{ 3410{
3426 if (vcpu->arch.pio.cur_count) 3411 if (vcpu->arch.pio.count)
3427 goto data_avail; 3412 goto data_avail;
3428 3413
3429 trace_kvm_pio(1, port, size, 1); 3414 trace_kvm_pio(1, port, size, 1);
3430 3415
3431 vcpu->arch.pio.port = port; 3416 vcpu->arch.pio.port = port;
3432 vcpu->arch.pio.in = 1; 3417 vcpu->arch.pio.in = 1;
3433 vcpu->arch.pio.string = 0; 3418 vcpu->arch.pio.count = count;
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; 3419 vcpu->arch.pio.size = size;
3438 3420
3439 if (!kernel_pio(vcpu, vcpu->arch.pio_data)) { 3421 if (!kernel_pio(vcpu, vcpu->arch.pio_data)) {
3440 data_avail: 3422 data_avail:
3441 memcpy(val, vcpu->arch.pio_data, size * count); 3423 memcpy(val, vcpu->arch.pio_data, size * count);
3442 vcpu->arch.pio.cur_count = 0; 3424 vcpu->arch.pio.count = 0;
3443 return 1; 3425 return 1;
3444 } 3426 }
3445 3427
@@ -3461,16 +3443,13 @@ static int emulator_pio_out_emulated(int size, unsigned short port,
3461 3443
3462 vcpu->arch.pio.port = port; 3444 vcpu->arch.pio.port = port;
3463 vcpu->arch.pio.in = 0; 3445 vcpu->arch.pio.in = 0;
3464 vcpu->arch.pio.string = 0; 3446 vcpu->arch.pio.count = count;
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; 3447 vcpu->arch.pio.size = size;
3469 3448
3470 memcpy(vcpu->arch.pio_data, val, size * count); 3449 memcpy(vcpu->arch.pio_data, val, size * count);
3471 3450
3472 if (!kernel_pio(vcpu, vcpu->arch.pio_data)) { 3451 if (!kernel_pio(vcpu, vcpu->arch.pio_data)) {
3473 vcpu->arch.pio.cur_count = 0; 3452 vcpu->arch.pio.count = 0;
3474 return 1; 3453 return 1;
3475 } 3454 }
3476 3455
@@ -3717,7 +3696,6 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
3717 cache_all_regs(vcpu); 3696 cache_all_regs(vcpu);
3718 3697
3719 vcpu->mmio_is_write = 0; 3698 vcpu->mmio_is_write = 0;
3720 vcpu->arch.pio.string = 0;
3721 3699
3722 if (!(emulation_type & EMULTYPE_NO_DECODE)) { 3700 if (!(emulation_type & EMULTYPE_NO_DECODE)) {
3723 int cs_db, cs_l; 3701 int cs_db, cs_l;
@@ -3783,12 +3761,9 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
3783 if (r == 0) 3761 if (r == 0)
3784 kvm_x86_ops->set_interrupt_shadow(vcpu, shadow_mask); 3762 kvm_x86_ops->set_interrupt_shadow(vcpu, shadow_mask);
3785 3763
3786 if (vcpu->arch.pio.string) 3764 if (vcpu->arch.pio.count) {
3787 return EMULATE_DO_MMIO;
3788
3789 if (vcpu->arch.pio.cur_count && !vcpu->arch.pio.string) {
3790 if (!vcpu->arch.pio.in) 3765 if (!vcpu->arch.pio.in)
3791 vcpu->arch.pio.cur_count = 0; 3766 vcpu->arch.pio.count = 0;
3792 return EMULATE_DO_MMIO; 3767 return EMULATE_DO_MMIO;
3793 } 3768 }
3794 3769
@@ -3821,158 +3796,12 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
3821} 3796}
3822EXPORT_SYMBOL_GPL(emulate_instruction); 3797EXPORT_SYMBOL_GPL(emulate_instruction);
3823 3798
3824static int pio_copy_data(struct kvm_vcpu *vcpu)
3825{
3826 void *p = vcpu->arch.pio_data;
3827 gva_t q = vcpu->arch.pio.guest_gva;
3828 unsigned bytes;
3829 int ret;
3830 u32 error_code;
3831
3832 bytes = vcpu->arch.pio.size * vcpu->arch.pio.cur_count;
3833 if (vcpu->arch.pio.in)
3834 ret = kvm_write_guest_virt(q, p, bytes, vcpu, &error_code);
3835 else
3836 ret = kvm_read_guest_virt(q, p, bytes, vcpu, &error_code);
3837
3838 if (ret == X86EMUL_PROPAGATE_FAULT)
3839 kvm_inject_page_fault(vcpu, q, error_code);
3840
3841 return ret;
3842}
3843
3844int complete_pio(struct kvm_vcpu *vcpu)
3845{
3846 struct kvm_pio_request *io = &vcpu->arch.pio;
3847 long delta;
3848 int r;
3849 unsigned long val;
3850
3851 if (io->in) {
3852 r = pio_copy_data(vcpu);
3853 if (r)
3854 goto out;
3855 }
3856
3857 delta = 1;
3858 if (io->rep) {
3859 delta *= io->cur_count;
3860 /*
3861 * The size of the register should really depend on
3862 * current address size.
3863 */
3864 val = kvm_register_read(vcpu, VCPU_REGS_RCX);
3865 val -= delta;
3866 kvm_register_write(vcpu, VCPU_REGS_RCX, val);
3867 }
3868 if (io->down)
3869 delta = -delta;
3870 delta *= io->size;
3871 if (io->in) {
3872 val = kvm_register_read(vcpu, VCPU_REGS_RDI);
3873 val += delta;
3874 kvm_register_write(vcpu, VCPU_REGS_RDI, val);
3875 } else {
3876 val = kvm_register_read(vcpu, VCPU_REGS_RSI);
3877 val += delta;
3878 kvm_register_write(vcpu, VCPU_REGS_RSI, val);
3879 }
3880
3881out:
3882 io->count -= io->cur_count;
3883 io->cur_count = 0;
3884
3885 return 0;
3886}
3887
3888static int pio_string_write(struct kvm_vcpu *vcpu)
3889{
3890 struct kvm_pio_request *io = &vcpu->arch.pio;
3891 void *pd = vcpu->arch.pio_data;
3892 int i, r = 0;
3893
3894 for (i = 0; i < io->cur_count; i++) {
3895 if (kvm_io_bus_write(vcpu->kvm, KVM_PIO_BUS,
3896 io->port, io->size, pd)) {
3897 r = -EOPNOTSUPP;
3898 break;
3899 }
3900 pd += io->size;
3901 }
3902 return r;
3903}
3904
3905int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, int in,
3906 int size, unsigned long count, int down,
3907 gva_t address, int rep, unsigned port)
3908{
3909 unsigned now, in_page;
3910 int ret = 0;
3911
3912 trace_kvm_pio(!in, port, size, count);
3913
3914 vcpu->run->exit_reason = KVM_EXIT_IO;
3915 vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT;
3916 vcpu->run->io.size = vcpu->arch.pio.size = size;
3917 vcpu->run->io.data_offset = KVM_PIO_PAGE_OFFSET * PAGE_SIZE;
3918 vcpu->run->io.count = vcpu->arch.pio.count = vcpu->arch.pio.cur_count = count;
3919 vcpu->run->io.port = vcpu->arch.pio.port = port;
3920 vcpu->arch.pio.in = in;
3921 vcpu->arch.pio.string = 1;
3922 vcpu->arch.pio.down = down;
3923 vcpu->arch.pio.rep = rep;
3924
3925 if (!count) {
3926 kvm_x86_ops->skip_emulated_instruction(vcpu);
3927 return 1;
3928 }
3929
3930 if (!down)
3931 in_page = PAGE_SIZE - offset_in_page(address);
3932 else
3933 in_page = offset_in_page(address) + size;
3934 now = min(count, (unsigned long)in_page / size);
3935 if (!now)
3936 now = 1;
3937 if (down) {
3938 /*
3939 * String I/O in reverse. Yuck. Kill the guest, fix later.
3940 */
3941 pr_unimpl(vcpu, "guest string pio down\n");
3942 kvm_inject_gp(vcpu, 0);
3943 return 1;
3944 }
3945 vcpu->run->io.count = now;
3946 vcpu->arch.pio.cur_count = now;
3947
3948 if (vcpu->arch.pio.cur_count == vcpu->arch.pio.count)
3949 kvm_x86_ops->skip_emulated_instruction(vcpu);
3950
3951 vcpu->arch.pio.guest_gva = address;
3952
3953 if (!vcpu->arch.pio.in) {
3954 /* string PIO write */
3955 ret = pio_copy_data(vcpu);
3956 if (ret == X86EMUL_PROPAGATE_FAULT)
3957 return 1;
3958 if (ret == 0 && !pio_string_write(vcpu)) {
3959 complete_pio(vcpu);
3960 if (vcpu->arch.pio.count == 0)
3961 ret = 1;
3962 }
3963 }
3964 /* no string PIO read support yet */
3965
3966 return ret;
3967}
3968EXPORT_SYMBOL_GPL(kvm_emulate_pio_string);
3969
3970int kvm_fast_pio_out(struct kvm_vcpu *vcpu, int size, unsigned short port) 3799int kvm_fast_pio_out(struct kvm_vcpu *vcpu, int size, unsigned short port)
3971{ 3800{
3972 unsigned long val = kvm_register_read(vcpu, VCPU_REGS_RAX); 3801 unsigned long val = kvm_register_read(vcpu, VCPU_REGS_RAX);
3973 int ret = emulator_pio_out_emulated(size, port, &val, 1, vcpu); 3802 int ret = emulator_pio_out_emulated(size, port, &val, 1, vcpu);
3974 /* do not return to emulator after return from userspace */ 3803 /* do not return to emulator after return from userspace */
3975 vcpu->arch.pio.cur_count = 0; 3804 vcpu->arch.pio.count = 0;
3976 return ret; 3805 return ret;
3977} 3806}
3978EXPORT_SYMBOL_GPL(kvm_fast_pio_out); 3807EXPORT_SYMBOL_GPL(kvm_fast_pio_out);
@@ -4705,15 +4534,14 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
4705 if (!irqchip_in_kernel(vcpu->kvm)) 4534 if (!irqchip_in_kernel(vcpu->kvm))
4706 kvm_set_cr8(vcpu, kvm_run->cr8); 4535 kvm_set_cr8(vcpu, kvm_run->cr8);
4707 4536
4708 if (vcpu->arch.pio.cur_count) { 4537 if (vcpu->arch.pio.count) {
4709 vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu); 4538 vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
4710 if (!vcpu->arch.pio.string) 4539 r = emulate_instruction(vcpu, 0, 0, EMULTYPE_NO_DECODE);
4711 r = emulate_instruction(vcpu, 0, 0, EMULTYPE_NO_DECODE);
4712 else
4713 r = complete_pio(vcpu);
4714 srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx); 4540 srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
4715 if (r == EMULATE_DO_MMIO) 4541 if (r == EMULATE_DO_MMIO) {
4542 r = 0;
4716 goto out; 4543 goto out;
4544 }
4717 } 4545 }
4718 if (vcpu->mmio_needed) { 4546 if (vcpu->mmio_needed) {
4719 memcpy(vcpu->mmio_data, kvm_run->mmio.data, 8); 4547 memcpy(vcpu->mmio_data, kvm_run->mmio.data, 8);