]> git.proxmox.com Git - mirror_qemu.git/blobdiff - memory.c
numa: introduce memory_region_allocate_system_memory
[mirror_qemu.git] / memory.c
index a490cbd6670a9b57a9e7aab3e6c9676a76c0dd69..3e8cd5680bbdd2eccaf9357d5ae0fd10451f58a5 100644 (file)
--- a/memory.c
+++ b/memory.c
 #include <assert.h>
 
 #include "exec/memory-internal.h"
+#include "exec/ram_addr.h"
 
 //#define DEBUG_UNASSIGNED
 
 static unsigned memory_region_transaction_depth;
 static bool memory_region_update_pending;
+static bool ioeventfd_update_pending;
 static bool global_dirty_log = false;
 
 /* flat_view_mutex is taken around reading as->current_map; the critical
@@ -483,15 +485,15 @@ static AddressSpace *memory_region_to_address_space(MemoryRegion *mr)
 {
     AddressSpace *as;
 
-    while (mr->parent) {
-        mr = mr->parent;
+    while (mr->container) {
+        mr = mr->container;
     }
     QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
         if (mr == as->root) {
             return as;
         }
     }
-    abort();
+    return NULL;
 }
 
 /* Render a memory region into the global view.  Ranges in @view obscure
@@ -785,22 +787,34 @@ void memory_region_transaction_begin(void)
     ++memory_region_transaction_depth;
 }
 
+static void memory_region_clear_pending(void)
+{
+    memory_region_update_pending = false;
+    ioeventfd_update_pending = false;
+}
+
 void memory_region_transaction_commit(void)
 {
     AddressSpace *as;
 
     assert(memory_region_transaction_depth);
     --memory_region_transaction_depth;
-    if (!memory_region_transaction_depth && memory_region_update_pending) {
-        memory_region_update_pending = false;
-        MEMORY_LISTENER_CALL_GLOBAL(begin, Forward);
+    if (!memory_region_transaction_depth) {
+        if (memory_region_update_pending) {
+            MEMORY_LISTENER_CALL_GLOBAL(begin, Forward);
 
-        QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
-            address_space_update_topology(as);
-        }
+            QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
+                address_space_update_topology(as);
+            }
 
-        MEMORY_LISTENER_CALL_GLOBAL(commit, Forward);
-    }
+            MEMORY_LISTENER_CALL_GLOBAL(commit, Forward);
+        } else if (ioeventfd_update_pending) {
+            QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
+                address_space_update_ioeventfds(as);
+            }
+        }
+        memory_region_clear_pending();
+   }
 }
 
 static void memory_region_destructor_none(MemoryRegion *mr)
@@ -836,7 +850,7 @@ void memory_region_init(MemoryRegion *mr,
     mr->opaque = NULL;
     mr->owner = owner;
     mr->iommu_ops = NULL;
-    mr->parent = NULL;
+    mr->container = NULL;
     mr->size = int128_make64(size);
     if (size == UINT64_MAX) {
         mr->size = int128_2_64();
@@ -1191,9 +1205,7 @@ bool memory_region_test_and_clear_dirty(MemoryRegion *mr, hwaddr addr,
     assert(mr->terminates);
     ret = cpu_physical_memory_get_dirty(mr->ram_addr + addr, size, client);
     if (ret) {
-        cpu_physical_memory_reset_dirty(mr->ram_addr + addr,
-                                        mr->ram_addr + addr + size,
-                                        client);
+        cpu_physical_memory_reset_dirty(mr->ram_addr + addr, size, client);
     }
     return ret;
 }
@@ -1239,9 +1251,7 @@ void memory_region_reset_dirty(MemoryRegion *mr, hwaddr addr,
                                hwaddr size, unsigned client)
 {
     assert(mr->terminates);
-    cpu_physical_memory_reset_dirty(mr->ram_addr + addr,
-                                    mr->ram_addr + addr + size,
-                                    client);
+    cpu_physical_memory_reset_dirty(mr->ram_addr + addr, size, client);
 }
 
 void *memory_region_get_ram_ptr(MemoryRegion *mr)
@@ -1322,6 +1332,7 @@ void memory_region_add_coalescing(MemoryRegion *mr,
 void memory_region_clear_coalescing(MemoryRegion *mr)
 {
     CoalescedMemoryRange *cmr;
+    bool updated = false;
 
     qemu_flush_coalesced_mmio_buffer();
     mr->flush_coalesced_mmio = false;
@@ -1330,8 +1341,12 @@ void memory_region_clear_coalescing(MemoryRegion *mr)
         cmr = QTAILQ_FIRST(&mr->coalesced);
         QTAILQ_REMOVE(&mr->coalesced, cmr, link);
         g_free(cmr);
+        updated = true;
+    }
+
+    if (updated) {
+        memory_region_update_coalesced_range(mr);
     }
-    memory_region_update_coalesced_range(mr);
 }
 
 void memory_region_set_flush_coalesced(MemoryRegion *mr)
@@ -1376,7 +1391,7 @@ void memory_region_add_eventfd(MemoryRegion *mr,
     memmove(&mr->ioeventfds[i+1], &mr->ioeventfds[i],
             sizeof(*mr->ioeventfds) * (mr->ioeventfd_nb-1 - i));
     mr->ioeventfds[i] = mrfd;
-    memory_region_update_pending |= mr->enabled;
+    ioeventfd_update_pending |= mr->enabled;
     memory_region_transaction_commit();
 }
 
@@ -1409,22 +1424,19 @@ void memory_region_del_eventfd(MemoryRegion *mr,
     --mr->ioeventfd_nb;
     mr->ioeventfds = g_realloc(mr->ioeventfds,
                                   sizeof(*mr->ioeventfds)*mr->ioeventfd_nb + 1);
-    memory_region_update_pending |= mr->enabled;
+    ioeventfd_update_pending |= mr->enabled;
     memory_region_transaction_commit();
 }
 
-static void memory_region_add_subregion_common(MemoryRegion *mr,
-                                               hwaddr offset,
-                                               MemoryRegion *subregion)
+static void memory_region_update_container_subregions(MemoryRegion *subregion)
 {
+    hwaddr offset = subregion->addr;
+    MemoryRegion *mr = subregion->container;
     MemoryRegion *other;
 
     memory_region_transaction_begin();
 
-    assert(!subregion->parent);
     memory_region_ref(subregion);
-    subregion->parent = mr;
-    subregion->addr = offset;
     QTAILQ_FOREACH(other, &mr->subregions, subregions_link) {
         if (subregion->may_overlap || other->may_overlap) {
             continue;
@@ -1458,6 +1470,15 @@ done:
     memory_region_transaction_commit();
 }
 
+static void memory_region_add_subregion_common(MemoryRegion *mr,
+                                               hwaddr offset,
+                                               MemoryRegion *subregion)
+{
+    assert(!subregion->container);
+    subregion->container = mr;
+    subregion->addr = offset;
+    memory_region_update_container_subregions(subregion);
+}
 
 void memory_region_add_subregion(MemoryRegion *mr,
                                  hwaddr offset,
@@ -1482,8 +1503,8 @@ void memory_region_del_subregion(MemoryRegion *mr,
                                  MemoryRegion *subregion)
 {
     memory_region_transaction_begin();
-    assert(subregion->parent == mr);
-    subregion->parent = NULL;
+    assert(subregion->container == mr);
+    subregion->container = NULL;
     QTAILQ_REMOVE(&mr->subregions, subregion, subregions_link);
     memory_region_unref(subregion);
     memory_region_update_pending |= mr->enabled && subregion->enabled;
@@ -1501,27 +1522,27 @@ void memory_region_set_enabled(MemoryRegion *mr, bool enabled)
     memory_region_transaction_commit();
 }
 
-void memory_region_set_address(MemoryRegion *mr, hwaddr addr)
+static void memory_region_readd_subregion(MemoryRegion *mr)
 {
-    MemoryRegion *parent = mr->parent;
-    int priority = mr->priority;
-    bool may_overlap = mr->may_overlap;
+    MemoryRegion *container = mr->container;
 
-    if (addr == mr->addr || !parent) {
-        mr->addr = addr;
-        return;
+    if (container) {
+        memory_region_transaction_begin();
+        memory_region_ref(mr);
+        memory_region_del_subregion(container, mr);
+        mr->container = container;
+        memory_region_update_container_subregions(mr);
+        memory_region_unref(mr);
+        memory_region_transaction_commit();
     }
+}
 
-    memory_region_transaction_begin();
-    memory_region_ref(mr);
-    memory_region_del_subregion(parent, mr);
-    if (may_overlap) {
-        memory_region_add_subregion_overlap(parent, addr, mr, priority);
-    } else {
-        memory_region_add_subregion(parent, addr, mr);
+void memory_region_set_address(MemoryRegion *mr, hwaddr addr)
+{
+    if (addr != mr->addr) {
+        mr->addr = addr;
+        memory_region_readd_subregion(mr);
     }
-    memory_region_unref(mr);
-    memory_region_transaction_commit();
 }
 
 void memory_region_set_alias_offset(MemoryRegion *mr, hwaddr offset)
@@ -1562,16 +1583,21 @@ static FlatRange *flatview_lookup(FlatView *view, AddrRange addr)
                    sizeof(FlatRange), cmp_flatrange_addr);
 }
 
-bool memory_region_present(MemoryRegion *parent, hwaddr addr)
+bool memory_region_present(MemoryRegion *container, hwaddr addr)
 {
-    MemoryRegion *mr = memory_region_find(parent, addr, 1).mr;
-    if (!mr) {
+    MemoryRegion *mr = memory_region_find(container, addr, 1).mr;
+    if (!mr || (mr == container)) {
         return false;
     }
     memory_region_unref(mr);
     return true;
 }
 
+bool memory_region_is_mapped(MemoryRegion *mr)
+{
+    return mr->container ? true : false;
+}
+
 MemoryRegionSection memory_region_find(MemoryRegion *mr,
                                        hwaddr addr, uint64_t size)
 {
@@ -1583,12 +1609,15 @@ MemoryRegionSection memory_region_find(MemoryRegion *mr,
     FlatRange *fr;
 
     addr += mr->addr;
-    for (root = mr; root->parent; ) {
-        root = root->parent;
+    for (root = mr; root->container; ) {
+        root = root->container;
         addr += root->addr;
     }
 
     as = memory_region_to_address_space(root);
+    if (!as) {
+        return ret;
+    }
     range = addrrange_make(int128_make64(addr), int128_make64(size));
 
     view = address_space_get_flatview(as);
@@ -1725,12 +1754,19 @@ void address_space_init(AddressSpace *as, MemoryRegion *root, const char *name)
 
 void address_space_destroy(AddressSpace *as)
 {
+    MemoryListener *listener;
+
     /* Flush out anything from MemoryListeners listening in on this */
     memory_region_transaction_begin();
     as->root = NULL;
     memory_region_transaction_commit();
     QTAILQ_REMOVE(&address_spaces, as, address_spaces_link);
     address_space_destroy_dispatch(as);
+
+    QTAILQ_FOREACH(listener, &memory_listeners, link) {
+        assert(listener->address_space_filter != as);
+    }
+
     flatview_unref(as->current_map);
     g_free(as->name);
     g_free(as->ioeventfds);