diff options
author | Gleb Natapov <gleb@redhat.com> | 2012-09-03 08:24:26 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2012-09-06 11:06:37 -0400 |
commit | 716d51abff06f48425cef15d78ca6f36093f6dbf (patch) | |
tree | 15449b877468b066a7f2b43fcdb9c459c748cbee /arch/x86/kvm/x86.c | |
parent | 3b4dc3a031110753b9ba36432dbd21f989fcee56 (diff) |
KVM: Provide userspace IO exit completion callback
Current code assumes that IO exit was due to instruction emulation
and handles execution back to emulator directly. This patch adds new
userspace IO exit completion callback that can be set by any other code
that caused IO exit to userspace.
Signed-off-by: Gleb Natapov <gleb@redhat.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch/x86/kvm/x86.c')
-rw-r--r-- | arch/x86/kvm/x86.c | 93 |
1 files changed, 56 insertions, 37 deletions
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 | ||