Patchwork [RFC,v1,07/22] memory: maintain a list of address spaces

login
register
mail settings
Submitter Avi Kivity
Date Oct. 3, 2012, 4:03 p.m.
Message ID <1349280245-16341-8-git-send-email-avi@redhat.com>
Download mbox | patch
Permalink /patch/188822/
State New
Headers show

Comments

Avi Kivity - Oct. 3, 2012, 4:03 p.m.
Instead of embedding knowledge of the memory and I/O address spaces in the
memory core, maintain a list of all address spaces.  This list will later
be extended dynamically for other but masters.

Signed-off-by: Avi Kivity <avi@redhat.com>
---
 memory.c | 75 +++++++++++++++++++++++++++++++++++++++-------------------------
 memory.h |  2 ++
 2 files changed, 48 insertions(+), 29 deletions(-)
Gleb Natapov - Oct. 4, 2012, 10:17 a.m.
On Wed, Oct 03, 2012 at 06:03:50PM +0200, Avi Kivity wrote:
> Instead of embedding knowledge of the memory and I/O address spaces in the
> memory core, maintain a list of all address spaces.  This list will later
> be extended dynamically for other but masters.
------------------------------------^ bus?

> 
> Signed-off-by: Avi Kivity <avi@redhat.com>
> ---
>  memory.c | 75 +++++++++++++++++++++++++++++++++++++++-------------------------
>  memory.h |  2 ++
>  2 files changed, 48 insertions(+), 29 deletions(-)
> 
> diff --git a/memory.c b/memory.c
> index 431a867..b58b97c 100644
> --- a/memory.c
> +++ b/memory.c
> @@ -28,6 +28,9 @@
>  static QTAILQ_HEAD(memory_listeners, MemoryListener) memory_listeners
>      = QTAILQ_HEAD_INITIALIZER(memory_listeners);
>  
> +static QTAILQ_HEAD(, AddressSpace) address_spaces
> +    = QTAILQ_HEAD_INITIALIZER(address_spaces);
> +
>  typedef struct AddrRange AddrRange;
>  
>  /*
> @@ -449,14 +452,15 @@ static void memory_region_iorange_destructor(IORange *iorange)
>  
>  static AddressSpace *memory_region_to_address_space(MemoryRegion *mr)
>  {
> +    AddressSpace *as;
> +
>      while (mr->parent) {
>          mr = mr->parent;
>      }
> -    if (mr == address_space_memory.root) {
> -        return &address_space_memory;
> -    }
> -    if (mr == address_space_io.root) {
> -        return &address_space_io;
> +    QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
> +        if (mr == as->root) {
> +            return as;
> +        }
>      }
>      abort();
>  }
> @@ -729,16 +733,15 @@ void memory_region_transaction_begin(void)
>  
>  void memory_region_transaction_commit(void)
>  {
> +    AddressSpace *as;
> +
>      assert(memory_region_transaction_depth);
>      --memory_region_transaction_depth;
>      if (!memory_region_transaction_depth) {
>          MEMORY_LISTENER_CALL_GLOBAL(begin, Forward);
>  
> -        if (address_space_memory.root) {
> -            address_space_update_topology(&address_space_memory);
> -        }
> -        if (address_space_io.root) {
> -            address_space_update_topology(&address_space_io);
> +        QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
> +            address_space_update_topology(as);
>          }
>  
>          MEMORY_LISTENER_CALL_GLOBAL(commit, Forward);
> @@ -1072,12 +1075,14 @@ void memory_region_set_dirty(MemoryRegion *mr, target_phys_addr_t addr,
>  
>  void memory_region_sync_dirty_bitmap(MemoryRegion *mr)
>  {
> +    AddressSpace *as;
>      FlatRange *fr;
>  
> -    FOR_EACH_FLAT_RANGE(fr, address_space_memory.current_map) {
> -        if (fr->mr == mr) {
> -            MEMORY_LISTENER_UPDATE_REGION(fr, &address_space_memory,
> -                                          Forward, log_sync);
> +    QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
> +        FOR_EACH_FLAT_RANGE(fr, as->current_map) {
> +            if (fr->mr == mr) {
> +                MEMORY_LISTENER_UPDATE_REGION(fr, as, Forward, log_sync);
> +            }
>          }
>      }
>  }
> @@ -1120,13 +1125,13 @@ void *memory_region_get_ram_ptr(MemoryRegion *mr)
>      return qemu_get_ram_ptr(mr->ram_addr & TARGET_PAGE_MASK);
>  }
>  
> -static void memory_region_update_coalesced_range(MemoryRegion *mr)
> +static void memory_region_update_coalesced_range_as(MemoryRegion *mr, AddressSpace *as)
>  {
>      FlatRange *fr;
>      CoalescedMemoryRange *cmr;
>      AddrRange tmp;
>  
> -    FOR_EACH_FLAT_RANGE(fr, address_space_memory.current_map) {
> +    FOR_EACH_FLAT_RANGE(fr, as->current_map) {
>          if (fr->mr == mr) {
>              qemu_unregister_coalesced_mmio(int128_get64(fr->addr.start),
>                                             int128_get64(fr->addr.size));
> @@ -1145,6 +1150,15 @@ static void memory_region_update_coalesced_range(MemoryRegion *mr)
>      }
>  }
>  
> +static void memory_region_update_coalesced_range(MemoryRegion *mr)
> +{
> +    AddressSpace *as;
> +
> +    QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
> +        memory_region_update_coalesced_range_as(mr, as);
> +    }
> +}
> +
>  void memory_region_set_coalescing(MemoryRegion *mr)
>  {
>      memory_region_clear_coalescing(mr);
> @@ -1450,10 +1464,6 @@ static void listener_add_address_space(MemoryListener *listener,
>  {
>      FlatRange *fr;
>  
> -    if (!as->root) {
> -        return;
> -    }
> -
>      if (listener->address_space_filter
>          && listener->address_space_filter != as->root) {
>          return;
> @@ -1478,6 +1488,7 @@ static void listener_add_address_space(MemoryListener *listener,
>  void memory_listener_register(MemoryListener *listener, MemoryRegion *filter)
>  {
>      MemoryListener *other = NULL;
> +    AddressSpace *as;
>  
>      listener->address_space_filter = filter;
>      if (QTAILQ_EMPTY(&memory_listeners)
> @@ -1492,8 +1503,10 @@ void memory_listener_register(MemoryListener *listener, MemoryRegion *filter)
>          }
>          QTAILQ_INSERT_BEFORE(other, listener, link);
>      }
> -    listener_add_address_space(listener, &address_space_memory);
> -    listener_add_address_space(listener, &address_space_io);
> +
> +    QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
> +        listener_add_address_space(listener, as);
> +    }
>  }
>  
>  void memory_listener_unregister(MemoryListener *listener)
> @@ -1507,17 +1520,21 @@ void address_space_init(AddressSpace *as, MemoryRegion *root)
>      as->root = root;
>      as->current_map = g_new(FlatView, 1);
>      flatview_init(as->current_map);
> +    QTAILQ_INSERT_TAIL(&address_spaces, as, address_spaces_link);
> +    as->name = NULL;
>      memory_region_transaction_commit();
>  }
>  
>  void set_system_memory_map(MemoryRegion *mr)
>  {
>      address_space_init(&address_space_memory, mr);
> +    address_space_memory.name = "memory";
>  }
>  
>  void set_system_io_map(MemoryRegion *mr)
>  {
>      address_space_init(&address_space_io, mr);
> +    address_space_io.name = "I/O";
>  }
>  
>  uint64_t io_mem_read(MemoryRegion *mr, target_phys_addr_t addr, unsigned size)
> @@ -1637,16 +1654,16 @@ void mtree_info(fprintf_function mon_printf, void *f)
>  {
>      MemoryRegionListHead ml_head;
>      MemoryRegionList *ml, *ml2;
> +    AddressSpace *as;
>  
>      QTAILQ_INIT(&ml_head);
>  
> -    mon_printf(f, "memory\n");
> -    mtree_print_mr(mon_printf, f, address_space_memory.root, 0, 0, &ml_head);
> -
> -    if (address_space_io.root &&
> -        !QTAILQ_EMPTY(&address_space_io.root->subregions)) {
> -        mon_printf(f, "I/O\n");
> -        mtree_print_mr(mon_printf, f, address_space_io.root, 0, 0, &ml_head);
> +    QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
> +        if (!as->name) {
> +            continue;
> +        }
> +        mon_printf(f, "%s\n", as->name);
> +        mtree_print_mr(mon_printf, f, as->root, 0, 0, &ml_head);
>      }
>  
>      mon_printf(f, "aliases\n");
> diff --git a/memory.h b/memory.h
> index a1d75e7..46bc5e1 100644
> --- a/memory.h
> +++ b/memory.h
> @@ -164,10 +164,12 @@ typedef struct AddressSpace AddressSpace;
>   */
>  struct AddressSpace {
>      /* All fields are private. */
> +    const char *name;
>      MemoryRegion *root;
>      struct FlatView *current_map;
>      int ioeventfd_nb;
>      struct MemoryRegionIoeventfd *ioeventfds;
> +    QTAILQ_ENTRY(AddressSpace) address_spaces_link;
>  };
>  
>  typedef struct MemoryRegionSection MemoryRegionSection;
> -- 
> 1.7.12
> 

--
			Gleb.
Avi Kivity - Oct. 4, 2012, 10:19 a.m.
On 10/04/2012 12:17 PM, Gleb Natapov wrote:
> On Wed, Oct 03, 2012 at 06:03:50PM +0200, Avi Kivity wrote:
>> Instead of embedding knowledge of the memory and I/O address spaces in the
>> memory core, maintain a list of all address spaces.  This list will later
>> be extended dynamically for other but masters.
> ------------------------------------^ bus?

Fixed.
Anthony Liguori - Oct. 4, 2012, 2:03 p.m.
Avi Kivity <avi@redhat.com> writes:

> Instead of embedding knowledge of the memory and I/O address spaces in the
> memory core, maintain a list of all address spaces.  This list will later
> be extended dynamically for other but masters.
>
> Signed-off-by: Avi Kivity <avi@redhat.com>

Reviewed-by: Anthony Liguori <aliguori@us.ibm.com>

Regards,

Anthony Liguori

> ---
>  memory.c | 75 +++++++++++++++++++++++++++++++++++++++-------------------------
>  memory.h |  2 ++
>  2 files changed, 48 insertions(+), 29 deletions(-)
>
> diff --git a/memory.c b/memory.c
> index 431a867..b58b97c 100644
> --- a/memory.c
> +++ b/memory.c
> @@ -28,6 +28,9 @@
>  static QTAILQ_HEAD(memory_listeners, MemoryListener) memory_listeners
>      = QTAILQ_HEAD_INITIALIZER(memory_listeners);
>  
> +static QTAILQ_HEAD(, AddressSpace) address_spaces
> +    = QTAILQ_HEAD_INITIALIZER(address_spaces);
> +
>  typedef struct AddrRange AddrRange;
>  
>  /*
> @@ -449,14 +452,15 @@ static void memory_region_iorange_destructor(IORange *iorange)
>  
>  static AddressSpace *memory_region_to_address_space(MemoryRegion *mr)
>  {
> +    AddressSpace *as;
> +
>      while (mr->parent) {
>          mr = mr->parent;
>      }
> -    if (mr == address_space_memory.root) {
> -        return &address_space_memory;
> -    }
> -    if (mr == address_space_io.root) {
> -        return &address_space_io;
> +    QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
> +        if (mr == as->root) {
> +            return as;
> +        }
>      }
>      abort();
>  }
> @@ -729,16 +733,15 @@ void memory_region_transaction_begin(void)
>  
>  void memory_region_transaction_commit(void)
>  {
> +    AddressSpace *as;
> +
>      assert(memory_region_transaction_depth);
>      --memory_region_transaction_depth;
>      if (!memory_region_transaction_depth) {
>          MEMORY_LISTENER_CALL_GLOBAL(begin, Forward);
>  
> -        if (address_space_memory.root) {
> -            address_space_update_topology(&address_space_memory);
> -        }
> -        if (address_space_io.root) {
> -            address_space_update_topology(&address_space_io);
> +        QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
> +            address_space_update_topology(as);
>          }
>  
>          MEMORY_LISTENER_CALL_GLOBAL(commit, Forward);
> @@ -1072,12 +1075,14 @@ void memory_region_set_dirty(MemoryRegion *mr, target_phys_addr_t addr,
>  
>  void memory_region_sync_dirty_bitmap(MemoryRegion *mr)
>  {
> +    AddressSpace *as;
>      FlatRange *fr;
>  
> -    FOR_EACH_FLAT_RANGE(fr, address_space_memory.current_map) {
> -        if (fr->mr == mr) {
> -            MEMORY_LISTENER_UPDATE_REGION(fr, &address_space_memory,
> -                                          Forward, log_sync);
> +    QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
> +        FOR_EACH_FLAT_RANGE(fr, as->current_map) {
> +            if (fr->mr == mr) {
> +                MEMORY_LISTENER_UPDATE_REGION(fr, as, Forward, log_sync);
> +            }
>          }
>      }
>  }
> @@ -1120,13 +1125,13 @@ void *memory_region_get_ram_ptr(MemoryRegion *mr)
>      return qemu_get_ram_ptr(mr->ram_addr & TARGET_PAGE_MASK);
>  }
>  
> -static void memory_region_update_coalesced_range(MemoryRegion *mr)
> +static void memory_region_update_coalesced_range_as(MemoryRegion *mr, AddressSpace *as)
>  {
>      FlatRange *fr;
>      CoalescedMemoryRange *cmr;
>      AddrRange tmp;
>  
> -    FOR_EACH_FLAT_RANGE(fr, address_space_memory.current_map) {
> +    FOR_EACH_FLAT_RANGE(fr, as->current_map) {
>          if (fr->mr == mr) {
>              qemu_unregister_coalesced_mmio(int128_get64(fr->addr.start),
>                                             int128_get64(fr->addr.size));
> @@ -1145,6 +1150,15 @@ static void memory_region_update_coalesced_range(MemoryRegion *mr)
>      }
>  }
>  
> +static void memory_region_update_coalesced_range(MemoryRegion *mr)
> +{
> +    AddressSpace *as;
> +
> +    QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
> +        memory_region_update_coalesced_range_as(mr, as);
> +    }
> +}
> +
>  void memory_region_set_coalescing(MemoryRegion *mr)
>  {
>      memory_region_clear_coalescing(mr);
> @@ -1450,10 +1464,6 @@ static void listener_add_address_space(MemoryListener *listener,
>  {
>      FlatRange *fr;
>  
> -    if (!as->root) {
> -        return;
> -    }
> -
>      if (listener->address_space_filter
>          && listener->address_space_filter != as->root) {
>          return;
> @@ -1478,6 +1488,7 @@ static void listener_add_address_space(MemoryListener *listener,
>  void memory_listener_register(MemoryListener *listener, MemoryRegion *filter)
>  {
>      MemoryListener *other = NULL;
> +    AddressSpace *as;
>  
>      listener->address_space_filter = filter;
>      if (QTAILQ_EMPTY(&memory_listeners)
> @@ -1492,8 +1503,10 @@ void memory_listener_register(MemoryListener *listener, MemoryRegion *filter)
>          }
>          QTAILQ_INSERT_BEFORE(other, listener, link);
>      }
> -    listener_add_address_space(listener, &address_space_memory);
> -    listener_add_address_space(listener, &address_space_io);
> +
> +    QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
> +        listener_add_address_space(listener, as);
> +    }
>  }
>  
>  void memory_listener_unregister(MemoryListener *listener)
> @@ -1507,17 +1520,21 @@ void address_space_init(AddressSpace *as, MemoryRegion *root)
>      as->root = root;
>      as->current_map = g_new(FlatView, 1);
>      flatview_init(as->current_map);
> +    QTAILQ_INSERT_TAIL(&address_spaces, as, address_spaces_link);
> +    as->name = NULL;
>      memory_region_transaction_commit();
>  }
>  
>  void set_system_memory_map(MemoryRegion *mr)
>  {
>      address_space_init(&address_space_memory, mr);
> +    address_space_memory.name = "memory";
>  }
>  
>  void set_system_io_map(MemoryRegion *mr)
>  {
>      address_space_init(&address_space_io, mr);
> +    address_space_io.name = "I/O";
>  }
>  
>  uint64_t io_mem_read(MemoryRegion *mr, target_phys_addr_t addr, unsigned size)
> @@ -1637,16 +1654,16 @@ void mtree_info(fprintf_function mon_printf, void *f)
>  {
>      MemoryRegionListHead ml_head;
>      MemoryRegionList *ml, *ml2;
> +    AddressSpace *as;
>  
>      QTAILQ_INIT(&ml_head);
>  
> -    mon_printf(f, "memory\n");
> -    mtree_print_mr(mon_printf, f, address_space_memory.root, 0, 0, &ml_head);
> -
> -    if (address_space_io.root &&
> -        !QTAILQ_EMPTY(&address_space_io.root->subregions)) {
> -        mon_printf(f, "I/O\n");
> -        mtree_print_mr(mon_printf, f, address_space_io.root, 0, 0, &ml_head);
> +    QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
> +        if (!as->name) {
> +            continue;
> +        }
> +        mon_printf(f, "%s\n", as->name);
> +        mtree_print_mr(mon_printf, f, as->root, 0, 0, &ml_head);
>      }
>  
>      mon_printf(f, "aliases\n");
> diff --git a/memory.h b/memory.h
> index a1d75e7..46bc5e1 100644
> --- a/memory.h
> +++ b/memory.h
> @@ -164,10 +164,12 @@ typedef struct AddressSpace AddressSpace;
>   */
>  struct AddressSpace {
>      /* All fields are private. */
> +    const char *name;
>      MemoryRegion *root;
>      struct FlatView *current_map;
>      int ioeventfd_nb;
>      struct MemoryRegionIoeventfd *ioeventfds;
> +    QTAILQ_ENTRY(AddressSpace) address_spaces_link;
>  };
>  
>  typedef struct MemoryRegionSection MemoryRegionSection;
> -- 
> 1.7.12

Patch

diff --git a/memory.c b/memory.c
index 431a867..b58b97c 100644
--- a/memory.c
+++ b/memory.c
@@ -28,6 +28,9 @@ 
 static QTAILQ_HEAD(memory_listeners, MemoryListener) memory_listeners
     = QTAILQ_HEAD_INITIALIZER(memory_listeners);
 
+static QTAILQ_HEAD(, AddressSpace) address_spaces
+    = QTAILQ_HEAD_INITIALIZER(address_spaces);
+
 typedef struct AddrRange AddrRange;
 
 /*
@@ -449,14 +452,15 @@  static void memory_region_iorange_destructor(IORange *iorange)
 
 static AddressSpace *memory_region_to_address_space(MemoryRegion *mr)
 {
+    AddressSpace *as;
+
     while (mr->parent) {
         mr = mr->parent;
     }
-    if (mr == address_space_memory.root) {
-        return &address_space_memory;
-    }
-    if (mr == address_space_io.root) {
-        return &address_space_io;
+    QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
+        if (mr == as->root) {
+            return as;
+        }
     }
     abort();
 }
@@ -729,16 +733,15 @@  void memory_region_transaction_begin(void)
 
 void memory_region_transaction_commit(void)
 {
+    AddressSpace *as;
+
     assert(memory_region_transaction_depth);
     --memory_region_transaction_depth;
     if (!memory_region_transaction_depth) {
         MEMORY_LISTENER_CALL_GLOBAL(begin, Forward);
 
-        if (address_space_memory.root) {
-            address_space_update_topology(&address_space_memory);
-        }
-        if (address_space_io.root) {
-            address_space_update_topology(&address_space_io);
+        QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
+            address_space_update_topology(as);
         }
 
         MEMORY_LISTENER_CALL_GLOBAL(commit, Forward);
@@ -1072,12 +1075,14 @@  void memory_region_set_dirty(MemoryRegion *mr, target_phys_addr_t addr,
 
 void memory_region_sync_dirty_bitmap(MemoryRegion *mr)
 {
+    AddressSpace *as;
     FlatRange *fr;
 
-    FOR_EACH_FLAT_RANGE(fr, address_space_memory.current_map) {
-        if (fr->mr == mr) {
-            MEMORY_LISTENER_UPDATE_REGION(fr, &address_space_memory,
-                                          Forward, log_sync);
+    QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
+        FOR_EACH_FLAT_RANGE(fr, as->current_map) {
+            if (fr->mr == mr) {
+                MEMORY_LISTENER_UPDATE_REGION(fr, as, Forward, log_sync);
+            }
         }
     }
 }
@@ -1120,13 +1125,13 @@  void *memory_region_get_ram_ptr(MemoryRegion *mr)
     return qemu_get_ram_ptr(mr->ram_addr & TARGET_PAGE_MASK);
 }
 
-static void memory_region_update_coalesced_range(MemoryRegion *mr)
+static void memory_region_update_coalesced_range_as(MemoryRegion *mr, AddressSpace *as)
 {
     FlatRange *fr;
     CoalescedMemoryRange *cmr;
     AddrRange tmp;
 
-    FOR_EACH_FLAT_RANGE(fr, address_space_memory.current_map) {
+    FOR_EACH_FLAT_RANGE(fr, as->current_map) {
         if (fr->mr == mr) {
             qemu_unregister_coalesced_mmio(int128_get64(fr->addr.start),
                                            int128_get64(fr->addr.size));
@@ -1145,6 +1150,15 @@  static void memory_region_update_coalesced_range(MemoryRegion *mr)
     }
 }
 
+static void memory_region_update_coalesced_range(MemoryRegion *mr)
+{
+    AddressSpace *as;
+
+    QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
+        memory_region_update_coalesced_range_as(mr, as);
+    }
+}
+
 void memory_region_set_coalescing(MemoryRegion *mr)
 {
     memory_region_clear_coalescing(mr);
@@ -1450,10 +1464,6 @@  static void listener_add_address_space(MemoryListener *listener,
 {
     FlatRange *fr;
 
-    if (!as->root) {
-        return;
-    }
-
     if (listener->address_space_filter
         && listener->address_space_filter != as->root) {
         return;
@@ -1478,6 +1488,7 @@  static void listener_add_address_space(MemoryListener *listener,
 void memory_listener_register(MemoryListener *listener, MemoryRegion *filter)
 {
     MemoryListener *other = NULL;
+    AddressSpace *as;
 
     listener->address_space_filter = filter;
     if (QTAILQ_EMPTY(&memory_listeners)
@@ -1492,8 +1503,10 @@  void memory_listener_register(MemoryListener *listener, MemoryRegion *filter)
         }
         QTAILQ_INSERT_BEFORE(other, listener, link);
     }
-    listener_add_address_space(listener, &address_space_memory);
-    listener_add_address_space(listener, &address_space_io);
+
+    QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
+        listener_add_address_space(listener, as);
+    }
 }
 
 void memory_listener_unregister(MemoryListener *listener)
@@ -1507,17 +1520,21 @@  void address_space_init(AddressSpace *as, MemoryRegion *root)
     as->root = root;
     as->current_map = g_new(FlatView, 1);
     flatview_init(as->current_map);
+    QTAILQ_INSERT_TAIL(&address_spaces, as, address_spaces_link);
+    as->name = NULL;
     memory_region_transaction_commit();
 }
 
 void set_system_memory_map(MemoryRegion *mr)
 {
     address_space_init(&address_space_memory, mr);
+    address_space_memory.name = "memory";
 }
 
 void set_system_io_map(MemoryRegion *mr)
 {
     address_space_init(&address_space_io, mr);
+    address_space_io.name = "I/O";
 }
 
 uint64_t io_mem_read(MemoryRegion *mr, target_phys_addr_t addr, unsigned size)
@@ -1637,16 +1654,16 @@  void mtree_info(fprintf_function mon_printf, void *f)
 {
     MemoryRegionListHead ml_head;
     MemoryRegionList *ml, *ml2;
+    AddressSpace *as;
 
     QTAILQ_INIT(&ml_head);
 
-    mon_printf(f, "memory\n");
-    mtree_print_mr(mon_printf, f, address_space_memory.root, 0, 0, &ml_head);
-
-    if (address_space_io.root &&
-        !QTAILQ_EMPTY(&address_space_io.root->subregions)) {
-        mon_printf(f, "I/O\n");
-        mtree_print_mr(mon_printf, f, address_space_io.root, 0, 0, &ml_head);
+    QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
+        if (!as->name) {
+            continue;
+        }
+        mon_printf(f, "%s\n", as->name);
+        mtree_print_mr(mon_printf, f, as->root, 0, 0, &ml_head);
     }
 
     mon_printf(f, "aliases\n");
diff --git a/memory.h b/memory.h
index a1d75e7..46bc5e1 100644
--- a/memory.h
+++ b/memory.h
@@ -164,10 +164,12 @@  typedef struct AddressSpace AddressSpace;
  */
 struct AddressSpace {
     /* All fields are private. */
+    const char *name;
     MemoryRegion *root;
     struct FlatView *current_map;
     int ioeventfd_nb;
     struct MemoryRegionIoeventfd *ioeventfds;
+    QTAILQ_ENTRY(AddressSpace) address_spaces_link;
 };
 
 typedef struct MemoryRegionSection MemoryRegionSection;