Skip to content

Commit 716d51a

Browse files
Gleb Natapovavikivity
authored andcommitted
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 <[email protected]> Signed-off-by: Avi Kivity <[email protected]>
1 parent 3b4dc3a commit 716d51a

File tree

2 files changed

+57
-37
lines changed

2 files changed

+57
-37
lines changed

arch/x86/include/asm/kvm_host.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,7 @@ struct kvm_vcpu_arch {
414414
struct x86_emulate_ctxt emulate_ctxt;
415415
bool emulate_regs_need_sync_to_vcpu;
416416
bool emulate_regs_need_sync_from_vcpu;
417+
int (*complete_userspace_io)(struct kvm_vcpu *vcpu);
417418

418419
gpa_t time;
419420
struct pvclock_vcpu_time_info hv_clock;

arch/x86/kvm/x86.c

Lines changed: 56 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -4544,6 +4544,9 @@ static bool retry_instruction(struct x86_emulate_ctxt *ctxt,
45444544
return true;
45454545
}
45464546

4547+
static int complete_emulated_mmio(struct kvm_vcpu *vcpu);
4548+
static int complete_emulated_pio(struct kvm_vcpu *vcpu);
4549+
45474550
int x86_emulate_instruction(struct kvm_vcpu *vcpu,
45484551
unsigned long cr2,
45494552
int emulation_type,
@@ -4614,13 +4617,16 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu,
46144617
} else if (vcpu->arch.pio.count) {
46154618
if (!vcpu->arch.pio.in)
46164619
vcpu->arch.pio.count = 0;
4617-
else
4620+
else {
46184621
writeback = false;
4622+
vcpu->arch.complete_userspace_io = complete_emulated_pio;
4623+
}
46194624
r = EMULATE_DO_MMIO;
46204625
} else if (vcpu->mmio_needed) {
46214626
if (!vcpu->mmio_is_write)
46224627
writeback = false;
46234628
r = EMULATE_DO_MMIO;
4629+
vcpu->arch.complete_userspace_io = complete_emulated_mmio;
46244630
} else if (r == EMULATION_RESTART)
46254631
goto restart;
46264632
else
@@ -5476,6 +5482,24 @@ static int __vcpu_run(struct kvm_vcpu *vcpu)
54765482
return r;
54775483
}
54785484

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+
54795503
/*
54805504
* Implements the following, as a state machine:
54815505
*
@@ -5492,47 +5516,37 @@ static int __vcpu_run(struct kvm_vcpu *vcpu)
54925516
* copy data
54935517
* exit
54945518
*/
5495-
static int complete_mmio(struct kvm_vcpu *vcpu)
5519+
static int complete_emulated_mmio(struct kvm_vcpu *vcpu)
54965520
{
54975521
struct kvm_run *run = vcpu->run;
54985522
struct kvm_mmio_fragment *frag;
5499-
int r;
55005523

5501-
if (!(vcpu->arch.pio.count || vcpu->mmio_needed))
5502-
return 1;
5524+
BUG_ON(!vcpu->mmio_needed);
55035525

5504-
if (vcpu->mmio_needed) {
5505-
/* Complete previous fragment */
5506-
frag = &vcpu->mmio_fragments[vcpu->mmio_cur_fragment++];
5507-
if (!vcpu->mmio_is_write)
5508-
memcpy(frag->data, run->mmio.data, frag->len);
5509-
if (vcpu->mmio_cur_fragment == vcpu->mmio_nr_fragments) {
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;
5526+
/* Complete previous fragment */
5527+
frag = &vcpu->mmio_fragments[vcpu->mmio_cur_fragment++];
5528+
if (!vcpu->mmio_is_write)
5529+
memcpy(frag->data, run->mmio.data, frag->len);
5530+
if (vcpu->mmio_cur_fragment == vcpu->mmio_nr_fragments) {
5531+
vcpu->mmio_needed = 0;
55205532
if (vcpu->mmio_is_write)
5521-
memcpy(run->mmio.data, frag->data, frag->len);
5522-
run->mmio.len = frag->len;
5523-
run->mmio.is_write = vcpu->mmio_is_write;
5524-
return 0;
5525-
5526-
}
5527-
done:
5528-
vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
5529-
r = emulate_instruction(vcpu, EMULTYPE_NO_DECODE);
5530-
srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
5531-
if (r != EMULATE_DONE)
5532-
return 0;
5533-
return 1;
5533+
return 1;
5534+
vcpu->mmio_read_completed = 1;
5535+
return complete_emulated_io(vcpu);
5536+
}
5537+
/* Initiate next fragment */
5538+
++frag;
5539+
run->exit_reason = KVM_EXIT_MMIO;
5540+
run->mmio.phys_addr = frag->gpa;
5541+
if (vcpu->mmio_is_write)
5542+
memcpy(run->mmio.data, frag->data, frag->len);
5543+
run->mmio.len = frag->len;
5544+
run->mmio.is_write = vcpu->mmio_is_write;
5545+
vcpu->arch.complete_userspace_io = complete_emulated_mmio;
5546+
return 0;
55345547
}
55355548

5549+
55365550
int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
55375551
{
55385552
int r;
@@ -5559,9 +5573,14 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
55595573
}
55605574
}
55615575

5562-
r = complete_mmio(vcpu);
5563-
if (r <= 0)
5564-
goto out;
5576+
if (unlikely(vcpu->arch.complete_userspace_io)) {
5577+
int (*cui)(struct kvm_vcpu *) = vcpu->arch.complete_userspace_io;
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);
55655584

55665585
r = __vcpu_run(vcpu);
55675586

0 commit comments

Comments
 (0)