Skip to content

Commit 68c3b4d

Browse files
mstsirkinmatosatti
authored andcommitted
KVM: VMX: speed up wildcard MMIO EVENTFD
With KVM, MMIO is much slower than PIO, due to the need to do page walk and emulation. But with EPT, it does not have to be: we know the address from the VMCS so if the address is unique, we can look up the eventfd directly, bypassing emulation. Unfortunately, this only works if userspace does not need to match on access length and data. The implementation adds a separate FAST_MMIO bus internally. This serves two purposes: - minimize overhead for old userspace that does not use eventfd with lengtth = 0 - minimize disruption in other code (since we don't know the length, devices on the MMIO bus only get a valid address in write, this way we don't need to touch all devices to teach them to handle an invalid length) At the moment, this optimization only has effect for EPT on x86. It will be possible to speed up MMIO for NPT and MMU using the same idea in the future. With this patch applied, on VMX MMIO EVENTFD is essentially as fast as PIO. I was unable to detect any measureable slowdown to non-eventfd MMIO. Making MMIO faster is important for the upcoming virtio 1.0 which includes an MMIO signalling capability. The idea was suggested by Peter Anvin. Lots of thanks to Gleb for pre-review and suggestions. Signed-off-by: Michael S. Tsirkin <[email protected]> Signed-off-by: Marcelo Tosatti <[email protected]>
1 parent f848a5a commit 68c3b4d

File tree

5 files changed

+23
-0
lines changed

5 files changed

+23
-0
lines changed

arch/x86/kvm/vmx.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5528,6 +5528,10 @@ static int handle_ept_misconfig(struct kvm_vcpu *vcpu)
55285528
gpa_t gpa;
55295529

55305530
gpa = vmcs_read64(GUEST_PHYSICAL_ADDRESS);
5531+
if (!kvm_io_bus_write(vcpu->kvm, KVM_FAST_MMIO_BUS, gpa, 0, NULL)) {
5532+
skip_emulated_instruction(vcpu);
5533+
return 1;
5534+
}
55315535

55325536
ret = handle_mmio_page_fault_common(vcpu, gpa, true);
55335537
if (likely(ret == RET_MMIO_PF_EMULATE))

include/linux/kvm_host.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ enum kvm_bus {
163163
KVM_MMIO_BUS,
164164
KVM_PIO_BUS,
165165
KVM_VIRTIO_CCW_NOTIFY_BUS,
166+
KVM_FAST_MMIO_BUS,
166167
KVM_NR_BUSES
167168
};
168169

include/uapi/linux/kvm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,7 @@ enum {
515515
kvm_ioeventfd_flag_nr_pio,
516516
kvm_ioeventfd_flag_nr_deassign,
517517
kvm_ioeventfd_flag_nr_virtio_ccw_notify,
518+
kvm_ioeventfd_flag_nr_fast_mmio,
518519
kvm_ioeventfd_flag_nr_max,
519520
};
520521

virt/kvm/eventfd.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -770,13 +770,25 @@ kvm_assign_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args)
770770
if (ret < 0)
771771
goto unlock_fail;
772772

773+
/* When length is ignored, MMIO is also put on a separate bus, for
774+
* faster lookups.
775+
*/
776+
if (!args->len && !(args->flags & KVM_IOEVENTFD_FLAG_PIO)) {
777+
ret = kvm_io_bus_register_dev(kvm, KVM_FAST_MMIO_BUS,
778+
p->addr, 0, &p->dev);
779+
if (ret < 0)
780+
goto register_fail;
781+
}
782+
773783
kvm->buses[bus_idx]->ioeventfd_count++;
774784
list_add_tail(&p->list, &kvm->ioeventfds);
775785

776786
mutex_unlock(&kvm->slots_lock);
777787

778788
return 0;
779789

790+
register_fail:
791+
kvm_io_bus_unregister_dev(kvm, bus_idx, &p->dev);
780792
unlock_fail:
781793
mutex_unlock(&kvm->slots_lock);
782794

@@ -816,6 +828,10 @@ kvm_deassign_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args)
816828
continue;
817829

818830
kvm_io_bus_unregister_dev(kvm, bus_idx, &p->dev);
831+
if (!p->length) {
832+
kvm_io_bus_unregister_dev(kvm, KVM_FAST_MMIO_BUS,
833+
&p->dev);
834+
}
819835
kvm->buses[bus_idx]->ioeventfd_count--;
820836
ioeventfd_release(p);
821837
ret = 0;

virt/kvm/kvm_main.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2922,6 +2922,7 @@ static int __kvm_io_bus_read(struct kvm_io_bus *bus, struct kvm_io_range *range,
29222922

29232923
return -EOPNOTSUPP;
29242924
}
2925+
EXPORT_SYMBOL_GPL(kvm_io_bus_write);
29252926

29262927
/* kvm_io_bus_read - called under kvm->slots_lock */
29272928
int kvm_io_bus_read(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,

0 commit comments

Comments
 (0)