diff options
| -rw-r--r-- | arch/x86/include/asm/kvm_host.h | 1 | ||||
| -rw-r--r-- | arch/x86/kvm/x86.c | 93 |
2 files changed, 57 insertions, 37 deletions
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index fc0e752e7564..64adb6117e19 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h | |||
| @@ -414,6 +414,7 @@ struct kvm_vcpu_arch { | |||
| 414 | struct x86_emulate_ctxt emulate_ctxt; | 414 | struct x86_emulate_ctxt emulate_ctxt; |
| 415 | bool emulate_regs_need_sync_to_vcpu; | 415 | bool emulate_regs_need_sync_to_vcpu; |
| 416 | bool emulate_regs_need_sync_from_vcpu; | 416 | bool emulate_regs_need_sync_from_vcpu; |
| 417 | int (*complete_userspace_io)(struct kvm_vcpu *vcpu); | ||
| 417 | 418 | ||
| 418 | gpa_t time; | 419 | gpa_t time; |
| 419 | struct pvclock_vcpu_time_info hv_clock; | 420 | struct pvclock_vcpu_time_info hv_clock; |
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 6f6812ec8419..f91e2c9d7cb1 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
| @@ -4544,6 +4544,9 @@ static bool retry_instruction(struct x86_emulate_ctxt *ctxt, | |||
| 4544 | return true; | 4544 | return true; |
| 4545 | } | 4545 | } |
| 4546 | 4546 | ||
| 4547 | static int complete_emulated_mmio(struct kvm_vcpu *vcpu); | ||
| 4548 | static int complete_emulated_pio(struct kvm_vcpu *vcpu); | ||
| 4549 | |||
| 4547 | int x86_emulate_instruction(struct kvm_vcpu *vcpu, | 4550 | int x86_emulate_instruction(struct kvm_vcpu *vcpu, |
| 4548 | unsigned long cr2, | 4551 | unsigned long cr2, |
| 4549 | int emulation_type, | 4552 | int emulation_type, |
| @@ -4614,13 +4617,16 @@ restart: | |||
| 4614 | } else if (vcpu->arch.pio.count) { | 4617 | } else if (vcpu->arch.pio.count) { |
| 4615 | if (!vcpu->arch.pio.in) | 4618 | if (!vcpu->arch.pio.in) |
| 4616 | vcpu->arch.pio.count = 0; | 4619 | vcpu->arch.pio.count = 0; |
| 4617 | else | 4620 | else { |
| 4618 | writeback = false; | 4621 | writeback = false; |
| 4622 | vcpu->arch.complete_userspace_io = complete_emulated_pio; | ||
| 4623 | } | ||
| 4619 | r = EMULATE_DO_MMIO; | 4624 | r = EMULATE_DO_MMIO; |
| 4620 | } else if (vcpu->mmio_needed) { | 4625 | } else if (vcpu->mmio_needed) { |
| 4621 | if (!vcpu->mmio_is_write) | 4626 | if (!vcpu->mmio_is_write) |
| 4622 | writeback = false; | 4627 | writeback = false; |
| 4623 | r = EMULATE_DO_MMIO; | 4628 | r = EMULATE_DO_MMIO; |
| 4629 | vcpu->arch.complete_userspace_io = complete_emulated_mmio; | ||
| 4624 | } else if (r == EMULATION_RESTART) | 4630 | } else if (r == EMULATION_RESTART) |
| 4625 | goto restart; | 4631 | goto restart; |
| 4626 | else | 4632 | else |
| @@ -5476,6 +5482,24 @@ static int __vcpu_run(struct kvm_vcpu *vcpu) | |||
| 5476 | return r; | 5482 | return r; |
| 5477 | } | 5483 | } |
| 5478 | 5484 | ||
| 5485 | static inline int complete_emulated_io(struct kvm_vcpu *vcpu) | ||
| 5486 | { | ||
| 5487 | int r; | ||
| 5488 | vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu); | ||
| 5489 | r = emulate_instruction(vcpu, EMULTYPE_NO_DECODE); | ||
| 5490 | srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx); | ||
| 5491 | if (r != EMULATE_DONE) | ||
| 5492 | return 0; | ||
| 5493 | return 1; | ||
| 5494 | } | ||
| 5495 | |||
| 5496 | static int complete_emulated_pio(struct kvm_vcpu *vcpu) | ||
| 5497 | { | ||
| 5498 | BUG_ON(!vcpu->arch.pio.count); | ||
| 5499 | |||
| 5500 | return complete_emulated_io(vcpu); | ||
| 5501 | } | ||
| 5502 | |||
| 5479 | /* | 5503 | /* |
| 5480 | * Implements the following, as a state machine: | 5504 | * Implements the following, as a state machine: |
| 5481 | * | 5505 | * |
| @@ -5492,47 +5516,37 @@ static int __vcpu_run(struct kvm_vcpu *vcpu) | |||
| 5492 | * copy data | 5516 | * copy data |
| 5493 | * exit | 5517 | * exit |
| 5494 | */ | 5518 | */ |
| 5495 | static int complete_mmio(struct kvm_vcpu *vcpu) | 5519 | static int complete_emulated_mmio(struct kvm_vcpu *vcpu) |
| 5496 | { | 5520 | { |
| 5497 | struct kvm_run *run = vcpu->run; | 5521 | struct kvm_run *run = vcpu->run; |
| 5498 | struct kvm_mmio_fragment *frag; | 5522 | struct kvm_mmio_fragment *frag; |
| 5499 | int r; | ||
| 5500 | 5523 | ||
| 5501 | if (!(vcpu->arch.pio.count || vcpu->mmio_needed)) | 5524 | BUG_ON(!vcpu->mmio_needed); |
| 5502 | return 1; | ||
| 5503 | 5525 | ||
| 5504 | if (vcpu->mmio_needed) { | 5526 | /* Complete previous fragment */ |
| 5505 | /* Complete previous fragment */ | 5527 | frag = &vcpu->mmio_fragments[vcpu->mmio_cur_fragment++]; |
| 5506 | frag = &vcpu->mmio_fragments[vcpu->mmio_cur_fragment++]; | 5528 | if (!vcpu->mmio_is_write) |
| 5507 | if (!vcpu->mmio_is_write) | 5529 | memcpy(frag->data, run->mmio.data, frag->len); |
| 5508 | memcpy(frag->data, run->mmio.data, frag->len); | 5530 | if (vcpu->mmio_cur_fragment == vcpu->mmio_nr_fragments) { |
| 5509 | if (vcpu->mmio_cur_fragment == vcpu->mmio_nr_fragments) { | 5531 | vcpu->mmio_needed = 0; |
| 5510 | vcpu->mmio_needed = 0; | ||
| 5511 | if (vcpu->mmio_is_write) | ||
| 5512 | return 1; | ||
| 5513 | vcpu->mmio_read_completed = 1; | ||
| 5514 | goto done; | ||
| 5515 | } | ||
| 5516 | /* Initiate next fragment */ | ||
| 5517 | ++frag; | ||
| 5518 | run->exit_reason = KVM_EXIT_MMIO; | ||
| 5519 | run->mmio.phys_addr = frag->gpa; | ||
| 5520 | if (vcpu->mmio_is_write) | 5532 | if (vcpu->mmio_is_write) |
| 5521 | memcpy(run->mmio.data, frag->data, frag->len); | 5533 | return 1; |
| 5522 | run->mmio.len = frag->len; | 5534 | vcpu->mmio_read_completed = 1; |
| 5523 | run->mmio.is_write = vcpu->mmio_is_write; | 5535 | return complete_emulated_io(vcpu); |
| 5524 | return 0; | 5536 | } |
| 5525 | 5537 | /* Initiate next fragment */ | |
| 5526 | } | 5538 | ++frag; |
| 5527 | done: | 5539 | run->exit_reason = KVM_EXIT_MMIO; |
| 5528 | vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu); | 5540 | run->mmio.phys_addr = frag->gpa; |
| 5529 | r = emulate_instruction(vcpu, EMULTYPE_NO_DECODE); | 5541 | if (vcpu->mmio_is_write) |
| 5530 | srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx); | 5542 | memcpy(run->mmio.data, frag->data, frag->len); |
| 5531 | if (r != EMULATE_DONE) | 5543 | run->mmio.len = frag->len; |
| 5532 | return 0; | 5544 | run->mmio.is_write = vcpu->mmio_is_write; |
| 5533 | return 1; | 5545 | vcpu->arch.complete_userspace_io = complete_emulated_mmio; |
| 5546 | return 0; | ||
| 5534 | } | 5547 | } |
| 5535 | 5548 | ||
| 5549 | |||
| 5536 | int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | 5550 | int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) |
| 5537 | { | 5551 | { |
| 5538 | int r; | 5552 | int r; |
| @@ -5559,9 +5573,14 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
| 5559 | } | 5573 | } |
| 5560 | } | 5574 | } |
| 5561 | 5575 | ||
| 5562 | r = complete_mmio(vcpu); | 5576 | if (unlikely(vcpu->arch.complete_userspace_io)) { |
| 5563 | if (r <= 0) | 5577 | int (*cui)(struct kvm_vcpu *) = vcpu->arch.complete_userspace_io; |
| 5564 | goto out; | 5578 | vcpu->arch.complete_userspace_io = NULL; |
| 5579 | r = cui(vcpu); | ||
| 5580 | if (r <= 0) | ||
| 5581 | goto out; | ||
| 5582 | } else | ||
| 5583 | WARN_ON(vcpu->arch.pio.count || vcpu->mmio_needed); | ||
| 5565 | 5584 | ||
| 5566 | r = __vcpu_run(vcpu); | 5585 | r = __vcpu_run(vcpu); |
| 5567 | 5586 | ||
