This patch introduces in libkvm the common part of coalesced MMIO interface.
It checks the coalesced MMIO availability with ioctl(KVM_CHECK_EXTENSION).
If KVM_CAP_COALESCED_MMIO is available, it processes the MMIO ring buffer
at the return of ioctl(KVM_RUN).
It defines kvm_register_coalesced_mmio() to register a coalesced MMIO zone, and
kvm_unregister_coalesced_mmio() to unregister it.
Signed-off-by: Laurent Vivier <[EMAIL PROTECTED]>
---
libkvm/kvm-common.h | 2 +
libkvm/libkvm.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++
libkvm/libkvm.h | 4 +++
3 files changed, 81 insertions(+), 0 deletions(-)
diff --git a/libkvm/kvm-common.h b/libkvm/kvm-common.h
index a3549e2..9780fb8 100644
--- a/libkvm/kvm-common.h
+++ b/libkvm/kvm-common.h
@@ -49,6 +49,8 @@ struct kvm_context {
int no_pit_creation;
/// in-kernel pit status
int pit_in_kernel;
+ /// in-kernel coalesced mmio
+ int coalesced_mmio;
};
void init_slots(void);
diff --git a/libkvm/libkvm.c b/libkvm/libkvm.c
index d1e95a4..1e7bbed 100644
--- a/libkvm/libkvm.c
+++ b/libkvm/libkvm.c
@@ -879,6 +879,22 @@ again:
post_kvm_run(kvm, vcpu);
+#if defined(KVM_CAP_COALESCED_MMIO)
+ if (kvm->coalesced_mmio) {
+ struct kvm_coalesced_mmio_ring *ring = (void *)run +
+ kvm->coalesced_mmio * PAGE_SIZE;
+ while (ring->first != ring->last) {
+ kvm->callbacks->mmio_write(kvm->opaque,
+ ring->coalesced_mmio[ring->first].phys_addr,
+ &ring->coalesced_mmio[ring->first].data[0],
+ ring->coalesced_mmio[ring->first].len);
+ smp_wmb();
+ ring->first = (ring->first + 1) %
+ KVM_COALESCED_MMIO_MAX;
+ }
+ }
+#endif
+
if (r == -1) {
r = handle_io_window(kvm);
goto more;
@@ -983,3 +999,62 @@ int kvm_pit_in_kernel(kvm_context_t kvm)
{
return kvm->pit_in_kernel;
}
+
+int kvm_init_coalesced_mmio(kvm_context_t kvm)
+{
+ int r = 0;
+ kvm->coalesced_mmio = 0;
+#ifdef KVM_CAP_COALESCED_MMIO
+ r = ioctl(kvm->fd, KVM_CHECK_EXTENSION, KVM_CAP_COALESCED_MMIO);
+ if (r > 0) {
+ kvm->coalesced_mmio = r;
+ return 0;
+ }
+#endif
+ return r;
+}
+
+int kvm_register_coalesced_mmio(kvm_context_t kvm, uint64_t addr, uint32_t
size)
+{
+#ifdef KVM_CAP_COALESCED_MMIO
+ struct kvm_coalesced_mmio_zone zone;
+ int r;
+
+ if (kvm->coalesced_mmio) {
+
+ zone.addr = addr;
+ zone.size = size;
+
+ r = ioctl(kvm->vm_fd, KVM_REGISTER_COALESCED_MMIO, &zone);
+ if (r == -1) {
+ perror("kvm_register_coalesced_mmio_zone");
+ return -errno;
+ }
+ return 0;
+ }
+#endif
+ return -ENOSYS;
+}
+
+int kvm_unregister_coalesced_mmio(kvm_context_t kvm, uint64_t addr, uint32_t
size)
+{
+#ifdef KVM_CAP_COALESCED_MMIO
+ struct kvm_coalesced_mmio_zone zone;
+ int r;
+
+ if (kvm->coalesced_mmio) {
+
+ zone.addr = addr;
+ zone.size = size;
+
+ r = ioctl(kvm->vm_fd, KVM_UNREGISTER_COALESCED_MMIO, &zone);
+ if (r == -1) {
+ perror("kvm_unregister_coalesced_mmio_zone");
+ return -errno;
+ }
+ return 0;
+ }
+#endif
+ return -ENOSYS;
+}
+
diff --git a/libkvm/libkvm.h b/libkvm/libkvm.h
index 63183b8..a33e9db 100644
--- a/libkvm/libkvm.h
+++ b/libkvm/libkvm.h
@@ -457,6 +457,10 @@ int kvm_get_dirty_pages_range(kvm_context_t kvm, unsigned
long phys_addr,
unsigned long end_addr, void *buf, void*opaque,
int (*cb)(unsigned long start, unsigned long len,
void*bitmap, void *opaque));
+int kvm_register_coalesced_mmio(kvm_context_t kvm,
+ uint64_t addr, uint32_t size);
+int kvm_unregister_coalesced_mmio(kvm_context_t kvm,
+ uint64_t addr, uint32_t size);
/*!
* \brief Create a memory alias
--
1.5.2.4
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at http://vger.kernel.org/majordomo-info.html