packing update
[qemu] / kvm-all.c
index 39f826b..28c9c07 100644 (file)
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -24,6 +24,9 @@
 #include "sysemu.h"
 #include "kvm.h"
 
+/* KVM uses PAGE_SIZE in it's definition of COALESCED_MMIO_MAX */
+#define PAGE_SIZE TARGET_PAGE_SIZE
+
 //#define DEBUG_KVM
 
 #ifdef DEBUG_KVM
@@ -52,6 +55,7 @@ struct KVMState
     KVMSlot slots[32];
     int fd;
     int vmfd;
+    int coalesced_mmio;
 };
 
 static KVMState *kvm_state;
@@ -137,6 +141,21 @@ err:
     return ret;
 }
 
+int kvm_sync_vcpus(void)
+{
+    CPUState *env;
+
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        int ret;
+
+        ret = kvm_arch_put_registers(env);
+        if (ret)
+            return ret;
+    }
+
+    return 0;
+}
+
 /*
  * dirty pages logging control
  */
@@ -201,11 +220,6 @@ void kvm_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, target_phys_a
     alloc_size = mem->memory_size >> TARGET_PAGE_BITS / sizeof(d.dirty_bitmap);
     d.dirty_bitmap = qemu_mallocz(alloc_size);
 
-    if (d.dirty_bitmap == NULL) {
-        dprintf("Could not allocate dirty bitmap\n");
-        return;
-    }
-
     d.slot = mem->slot;
     dprintf("slot %d, phys_addr %llx, uaddr: %llx\n",
             d.slot, mem->start_addr, mem->phys_offset);
@@ -228,6 +242,44 @@ out:
     qemu_free(d.dirty_bitmap);
 }
 
+int kvm_coalesce_mmio_region(target_phys_addr_t start, ram_addr_t size)
+{
+    int ret = -ENOSYS;
+#ifdef KVM_CAP_COALESCED_MMIO
+    KVMState *s = kvm_state;
+
+    if (s->coalesced_mmio) {
+        struct kvm_coalesced_mmio_zone zone;
+
+        zone.addr = start;
+        zone.size = size;
+
+        ret = kvm_vm_ioctl(s, KVM_REGISTER_COALESCED_MMIO, &zone);
+    }
+#endif
+
+    return ret;
+}
+
+int kvm_uncoalesce_mmio_region(target_phys_addr_t start, ram_addr_t size)
+{
+    int ret = -ENOSYS;
+#ifdef KVM_CAP_COALESCED_MMIO
+    KVMState *s = kvm_state;
+
+    if (s->coalesced_mmio) {
+        struct kvm_coalesced_mmio_zone zone;
+
+        zone.addr = start;
+        zone.size = size;
+
+        ret = kvm_vm_ioctl(s, KVM_UNREGISTER_COALESCED_MMIO, &zone);
+    }
+#endif
+
+    return ret;
+}
+
 int kvm_init(int smp_cpus)
 {
     KVMState *s;
@@ -238,8 +290,6 @@ int kvm_init(int smp_cpus)
         return -EINVAL;
 
     s = qemu_mallocz(sizeof(KVMState));
-    if (s == NULL)
-        return -ENOMEM;
 
     for (i = 0; i < ARRAY_SIZE(s->slots); i++)
         s->slots[i].slot = i;
@@ -283,6 +333,28 @@ int kvm_init(int smp_cpus)
         goto err;
     }
 
+    /* There was a nasty bug in < kvm-80 that prevents memory slots from being
+     * destroyed properly.  Since we rely on this capability, refuse to work
+     * with any kernel without this capability. */
+    ret = kvm_ioctl(s, KVM_CHECK_EXTENSION,
+                    KVM_CAP_DESTROY_MEMORY_REGION_WORKS);
+    if (ret <= 0) {
+        if (ret == 0)
+            ret = -EINVAL;
+
+        fprintf(stderr,
+                "KVM kernel module broken (DESTROY_MEMORY_REGION)\n"
+                "Please upgrade to at least kvm-81.\n");
+        goto err;
+    }
+
+    s->coalesced_mmio = 0;
+#ifdef KVM_CAP_COALESCED_MMIO
+    ret = kvm_ioctl(s, KVM_CHECK_EXTENSION, KVM_CAP_COALESCED_MMIO);
+    if (ret > 0)
+        s->coalesced_mmio = ret;
+#endif
+
     ret = kvm_arch_init(s, smp_cpus);
     if (ret < 0)
         goto err;
@@ -342,6 +414,27 @@ static int kvm_handle_io(CPUState *env, uint16_t port, void *data,
     return 1;
 }
 
+static void kvm_run_coalesced_mmio(CPUState *env, struct kvm_run *run)
+{
+#ifdef KVM_CAP_COALESCED_MMIO
+    KVMState *s = kvm_state;
+    if (s->coalesced_mmio) {
+        struct kvm_coalesced_mmio_ring *ring;
+
+        ring = (void *)run + (s->coalesced_mmio * TARGET_PAGE_SIZE);
+        while (ring->first != ring->last) {
+            struct kvm_coalesced_mmio *ent;
+
+            ent = &ring->coalesced_mmio[ring->first];
+
+            cpu_physical_memory_write(ent->phys_addr, ent->data, ent->len);
+            /* FIXME smp_wmb() */
+            ring->first = (ring->first + 1) % KVM_COALESCED_MMIO_MAX;
+        }
+    }
+#endif
+}
+
 int kvm_cpu_exec(CPUState *env)
 {
     struct kvm_run *run = env->kvm_run;
@@ -352,7 +445,7 @@ int kvm_cpu_exec(CPUState *env)
     do {
         kvm_arch_pre_run(env, run);
 
-        if ((env->interrupt_request & CPU_INTERRUPT_EXIT)) {
+        if (env->exit_request) {
             dprintf("interrupt exit requested\n");
             ret = 0;
             break;
@@ -372,6 +465,8 @@ int kvm_cpu_exec(CPUState *env)
             abort();
         }
 
+        kvm_run_coalesced_mmio(env, run);
+
         ret = 0; /* exit loop */
         switch (run->exit_reason) {
         case KVM_EXIT_IO:
@@ -417,8 +512,8 @@ int kvm_cpu_exec(CPUState *env)
         }
     } while (ret > 0);
 
-    if ((env->interrupt_request & CPU_INTERRUPT_EXIT)) {
-        env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
+    if (env->exit_request) {
+        env->exit_request = 0;
         env->exception_index = EXCP_INTERRUPT;
     }
 
@@ -549,3 +644,15 @@ int kvm_vcpu_ioctl(CPUState *env, int type, ...)
 
     return ret;
 }
+
+int kvm_has_sync_mmu(void)
+{
+#ifdef KVM_CAP_SYNC_MMU
+    KVMState *s = kvm_state;
+
+    if (kvm_ioctl(s, KVM_CHECK_EXTENSION, KVM_CAP_SYNC_MMU) > 0)
+        return 1;
+#endif
+
+    return 0;
+}