kvm: Conditionally apply workaround for KVM slot handling bug
[qemu] / kvm-all.c
index 36659a9..f64a8e9 100644 (file)
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -57,6 +57,7 @@ struct KVMState
     int fd;
     int vmfd;
     int coalesced_mmio;
+    int broken_set_mem_region;
 #ifdef KVM_CAP_SET_GUEST_DEBUG
     struct kvm_sw_breakpoint_head kvm_sw_breakpoints;
 #endif
@@ -320,14 +321,28 @@ int kvm_uncoalesce_mmio_region(target_phys_addr_t start, ram_addr_t size)
     return ret;
 }
 
+int kvm_check_extension(KVMState *s, unsigned int extension)
+{
+    int ret;
+
+    ret = kvm_ioctl(s, KVM_CHECK_EXTENSION, extension);
+    if (ret < 0) {
+        ret = 0;
+    }
+
+    return ret;
+}
+
 int kvm_init(int smp_cpus)
 {
     KVMState *s;
     int ret;
     int i;
 
-    if (smp_cpus > 1)
+    if (smp_cpus > 1) {
+        fprintf(stderr, "No SMP KVM support, use '-smp 1'\n");
         return -EINVAL;
+    }
 
     s = qemu_mallocz(sizeof(KVMState));
 
@@ -368,10 +383,8 @@ int kvm_init(int smp_cpus)
      * just use a user allocated buffer so we can use regular pages
      * unmodified.  Make sure we have a sufficiently modern version of KVM.
      */
-    ret = kvm_ioctl(s, KVM_CHECK_EXTENSION, KVM_CAP_USER_MEMORY);
-    if (ret <= 0) {
-        if (ret == 0)
-            ret = -EINVAL;
+    if (!kvm_check_extension(s, KVM_CAP_USER_MEMORY)) {
+        ret = -EINVAL;
         fprintf(stderr, "kvm does not support KVM_CAP_USER_MEMORY\n");
         goto err;
     }
@@ -379,11 +392,8 @@ int kvm_init(int smp_cpus)
     /* 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;
+    if (!kvm_check_extension(s, KVM_CAP_DESTROY_MEMORY_REGION_WORKS)) {
+        ret = -EINVAL;
 
         fprintf(stderr,
                 "KVM kernel module broken (DESTROY_MEMORY_REGION)\n"
@@ -391,11 +401,18 @@ int kvm_init(int smp_cpus)
         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;
+    s->coalesced_mmio = kvm_check_extension(s, KVM_CAP_COALESCED_MMIO);
+#else
+    s->coalesced_mmio = 0;
+#endif
+
+    s->broken_set_mem_region = 1;
+#ifdef KVM_CAP_JOIN_MEMORY_REGIONS_WORKS
+    ret = kvm_ioctl(s, KVM_CHECK_EXTENSION, KVM_CAP_JOIN_MEMORY_REGIONS_WORKS);
+    if (ret > 0) {
+        s->broken_set_mem_region = 0;
+    }
 #endif
 
     ret = kvm_arch_init(s, smp_cpus);
@@ -631,7 +648,8 @@ void kvm_set_phys_mem(target_phys_addr_t start_addr,
          * address as the first existing one. If not or if some overlapping
          * slot comes around later, we will fail (not seen in practice so far)
          * - and actually require a recent KVM version. */
-        if (old.start_addr == start_addr && old.memory_size < size &&
+        if (s->broken_set_mem_region &&
+            old.start_addr == start_addr && old.memory_size < size &&
             flags < IO_MEM_UNASSIGNED) {
             mem = kvm_alloc_slot(s);
             mem->memory_size = old.memory_size;
@@ -766,11 +784,10 @@ 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 kvm_check_extension(s, KVM_CAP_SYNC_MMU);
+#else
     return 0;
+#endif
 }
 
 void kvm_setup_guest_memory(void *start, size_t size)