aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm/x86.c
diff options
context:
space:
mode:
authorGleb Natapov <gleb@redhat.com>2012-09-03 08:24:26 -0400
committerAvi Kivity <avi@redhat.com>2012-09-06 11:06:37 -0400
commit716d51abff06f48425cef15d78ca6f36093f6dbf (patch)
tree15449b877468b066a7f2b43fcdb9c459c748cbee /arch/x86/kvm/x86.c
parent3b4dc3a031110753b9ba36432dbd21f989fcee56 (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.c93
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
4547static int complete_emulated_mmio(struct kvm_vcpu *vcpu);
4548static int complete_emulated_pio(struct kvm_vcpu *vcpu);
4549
4547int x86_emulate_instruction(struct kvm_vcpu *vcpu, 4550int 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
5485static 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
5496static 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 */
5495static int complete_mmio(struct kvm_vcpu *vcpu) 5519static 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;
5527done: 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
5536int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) 5550int 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