2e83913
This adds notifiers for phys memory changes: a set of callbacks that
2e83913
vhost can register and update kernel accordingly.  Down the road, kvm
2e83913
code can be switched to use these as well, instead of calling kvm code
2e83913
directly from exec.c as is done now.
2e83913
2e83913
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2e83913
---
2e83913
 cpu-common.h |   19 ++++++++++
2e83913
 exec.c       |  114 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
2e83913
 2 files changed, 130 insertions(+), 3 deletions(-)
2e83913
2e83913
diff --git a/cpu-common.h b/cpu-common.h
2e83913
index 5e59564..326513d 100644
2e83913
--- a/cpu-common.h
2e83913
+++ b/cpu-common.h
2e83913
@@ -8,6 +8,7 @@
2e83913
 #endif
2e83913
 
2e83913
 #include "bswap.h"
2e83913
+#include "qemu-queue.h"
2e83913
 
2e83913
 /* address in the RAM (different from a physical address) */
2e83913
 typedef unsigned long ram_addr_t;
2e83913
@@ -62,6 +63,24 @@ void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len,
2e83913
 void *cpu_register_map_client(void *opaque, void (*callback)(void *opaque));
2e83913
 void cpu_unregister_map_client(void *cookie);
2e83913
 
2e83913
+struct CPUPhysMemoryClient;
2e83913
+typedef struct CPUPhysMemoryClient CPUPhysMemoryClient;
2e83913
+struct CPUPhysMemoryClient {
2e83913
+    void (*set_memory)(struct CPUPhysMemoryClient *client,
2e83913
+                       target_phys_addr_t start_addr,
2e83913
+                       ram_addr_t size,
2e83913
+                       ram_addr_t phys_offset);
2e83913
+    int (*sync_dirty_bitmap)(struct CPUPhysMemoryClient *client,
2e83913
+                             target_phys_addr_t start_addr,
2e83913
+                             target_phys_addr_t end_addr);
2e83913
+    int (*migration_log)(struct CPUPhysMemoryClient *client,
2e83913
+                         int enable);
2e83913
+    QLIST_ENTRY(CPUPhysMemoryClient) list;
2e83913
+};
2e83913
+
2e83913
+void cpu_register_phys_memory_client(CPUPhysMemoryClient *);
2e83913
+void cpu_unregister_phys_memory_client(CPUPhysMemoryClient *);
2e83913
+
2e83913
 uint32_t ldub_phys(target_phys_addr_t addr);
2e83913
 uint32_t lduw_phys(target_phys_addr_t addr);
2e83913
 uint32_t ldl_phys(target_phys_addr_t addr);
2e83913
diff --git a/exec.c b/exec.c
2e83913
index 8f873ab..cbba15e 100644
2e83913
--- a/exec.c
2e83913
+++ b/exec.c
2e83913
@@ -1640,6 +1640,101 @@ const CPULogItem cpu_log_items[] = {
2e83913
     { 0, NULL, NULL },
2e83913
 };
2e83913
 
2e83913
+#ifndef CONFIG_USER_ONLY
2e83913
+static QLIST_HEAD(memory_client_list, CPUPhysMemoryClient) memory_client_list
2e83913
+    = QLIST_HEAD_INITIALIZER(memory_client_list);
2e83913
+
2e83913
+static void cpu_notify_set_memory(target_phys_addr_t start_addr,
2e83913
+				  ram_addr_t size,
2e83913
+				  ram_addr_t phys_offset)
2e83913
+{
2e83913
+    CPUPhysMemoryClient *client;
2e83913
+    QLIST_FOREACH(client, &memory_client_list, list) {
2e83913
+        client->set_memory(client, start_addr, size, phys_offset);
2e83913
+    }
2e83913
+}
2e83913
+
2e83913
+static int cpu_notify_sync_dirty_bitmap(target_phys_addr_t start,
2e83913
+					target_phys_addr_t end)
2e83913
+{
2e83913
+    CPUPhysMemoryClient *client;
2e83913
+    QLIST_FOREACH(client, &memory_client_list, list) {
2e83913
+        int r = client->sync_dirty_bitmap(client, start, end);
2e83913
+        if (r < 0)
2e83913
+            return r;
2e83913
+    }
2e83913
+    return 0;
2e83913
+}
2e83913
+
2e83913
+static int cpu_notify_migration_log(int enable)
2e83913
+{
2e83913
+    CPUPhysMemoryClient *client;
2e83913
+    QLIST_FOREACH(client, &memory_client_list, list) {
2e83913
+        int r = client->migration_log(client, enable);
2e83913
+        if (r < 0)
2e83913
+            return r;
2e83913
+    }
2e83913
+    return 0;
2e83913
+}
2e83913
+
2e83913
+static void phys_page_for_each_in_l1_map(PhysPageDesc **phys_map,
2e83913
+                                         CPUPhysMemoryClient *client)
2e83913
+{
2e83913
+    PhysPageDesc *pd;
2e83913
+    int l1, l2;
2e83913
+
2e83913
+    for (l1 = 0; l1 < L1_SIZE; ++l1) {
2e83913
+        pd = phys_map[l1];
2e83913
+        if (!pd) {
2e83913
+            continue;
2e83913
+        }
2e83913
+        for (l2 = 0; l2 < L2_SIZE; ++l2) {
2e83913
+            if (pd[l2].phys_offset == IO_MEM_UNASSIGNED) {
2e83913
+                continue;
2e83913
+            }
2e83913
+            client->set_memory(client, pd[l2].region_offset,
2e83913
+                               TARGET_PAGE_SIZE, pd[l2].phys_offset);
2e83913
+        }
2e83913
+    }
2e83913
+}
2e83913
+
2e83913
+static void phys_page_for_each(CPUPhysMemoryClient *client)
2e83913
+{
2e83913
+#if TARGET_PHYS_ADDR_SPACE_BITS > 32
2e83913
+
2e83913
+#if TARGET_PHYS_ADDR_SPACE_BITS > (32 + L1_BITS)
2e83913
+#error unsupported TARGET_PHYS_ADDR_SPACE_BITS
2e83913
+#endif
2e83913
+    void **phys_map = (void **)l1_phys_map;
2e83913
+    int l1;
2e83913
+    if (!l1_phys_map) {
2e83913
+        return;
2e83913
+    }
2e83913
+    for (l1 = 0; l1 < L1_SIZE; ++l1) {
2e83913
+        if (phys_map[l1]) {
2e83913
+            phys_page_for_each_in_l1_map(phys_map[l1], client);
2e83913
+        }
2e83913
+    }
2e83913
+#else
2e83913
+    if (!l1_phys_map) {
2e83913
+        return;
2e83913
+    }
2e83913
+    phys_page_for_each_in_l1_map(l1_phys_map, client);
2e83913
+#endif
2e83913
+}
2e83913
+
2e83913
+void cpu_register_phys_memory_client(CPUPhysMemoryClient *client)
2e83913
+{
2e83913
+    QLIST_INSERT_HEAD(&memory_client_list, client, list);
2e83913
+    phys_page_for_each(client);
2e83913
+}
2e83913
+
2e83913
+void cpu_unregister_phys_memory_client(CPUPhysMemoryClient *client)
2e83913
+{
2e83913
+    QLIST_REMOVE(client, list);
2e83913
+}
2e83913
+#endif
2e83913
+
2e83913
 static int cmp1(const char *s1, int n, const char *s2)
2e83913
 {
2e83913
     if (strlen(s2) != n)
2e83913
@@ -1899,10 +1994,16 @@ void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
2e83913
 
2e83913
 int cpu_physical_memory_set_dirty_tracking(int enable)
2e83913
 {
2e83913
+    int ret = 0;
2e83913
+    in_migration = enable;
2e83913
     if (kvm_enabled()) {
2e83913
-        return kvm_set_migration_log(enable);
2e83913
+        ret = kvm_set_migration_log(enable);
2e83913
     }
2e83913
-    return 0;
2e83913
+    if (ret < 0) {
2e83913
+        return ret;
2e83913
+    }
2e83913
+    ret = cpu_notify_migration_log(!!enable);
2e83913
+    return ret;
2e83913
 }
2e83913
 
2e83913
 int cpu_physical_memory_get_dirty_tracking(void)
2e83913
@@ -1915,8 +2016,13 @@ int cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr,
2e83913
 {
2e83913
     int ret = 0;
2e83913
 
2e83913
-    if (kvm_enabled())
2e83913
+    if (kvm_enabled()) {
2e83913
         ret = kvm_physical_sync_dirty_bitmap(start_addr, end_addr);
2e83913
+    }
2e83913
+    if (ret < 0) {
2e83913
+        return ret;
2e83913
+    }
2e83913
+    ret = cpu_notify_sync_dirty_bitmap(start_addr, end_addr);
2e83913
     return ret;
2e83913
 }
2e83913
 
2e83913
@@ -2331,6 +2437,8 @@ void cpu_register_physical_memory_offset(target_phys_addr_t start_addr,
2e83913
     if (kvm_enabled())
2e83913
         kvm_set_phys_mem(start_addr, size, phys_offset);
2e83913
 
2e83913
+    cpu_notify_set_memory(start_addr, size, phys_offset);
2e83913
+
2e83913
     if (phys_offset == IO_MEM_UNASSIGNED) {
2e83913
         region_offset = start_addr;
2e83913
     }
2e83913
-- 
2e83913
1.6.6.144.g5c3af