All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [RFC] qapi: New command query-mtree
@ 2014-08-20 17:46 Marc Marí
  2014-08-20 19:09 ` Eric Blake
  2014-08-21  9:06 ` Paolo Bonzini
  0 siblings, 2 replies; 8+ messages in thread
From: Marc Marí @ 2014-08-20 17:46 UTC (permalink / raw)
  To: qemu-devel
  Cc: Marc Marí,
	Paolo Bonzini, Andreas Färber, Stefan Hajnoczi,
	Peter Maydell

Add command query-mtree to get the memory tree of the guest.

As we were looking for a flexible solution on accessing the guest memory from
qtests, Stefan came with the idea to implement this new qmp command.

This way, the result can be parsed, and the RAM direction extracted, so only
a generic qtest malloc is necessary and not one per machine, as it is
implemented at the moment (malloc-pc uses fw_cfg).

The actual output is this: http://pastebin.com/nHAH9Jie
Which corresponds to this info mtree: http://pastebin.com/B5vw8DDf

Signed-off-by: Marc Marí <marc.mari.barcelo@gmail.com>
---
 memory.c         |  148 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 qapi-schema.json |   68 +++++++++++++++++++++++++
 qmp-commands.hx  |   19 +++++++
 3 files changed, 235 insertions(+)

diff --git a/memory.c b/memory.c
index 42317a2..6de6fa7 100644
--- a/memory.c
+++ b/memory.c
@@ -20,6 +20,7 @@
 #include "qemu/bitops.h"
 #include "qom/object.h"
 #include "trace.h"
+#include "qmp-commands.h"
 #include <assert.h>
 
 #include "exec/memory-internal.h"
@@ -2100,6 +2101,153 @@ void mtree_info(fprintf_function mon_printf, void *f)
     }
 }
 
+static MemRegion *qmp_mtree_mr(const MemoryRegion *mr, hwaddr base,
+                                   MemoryRegionListHead *alias_queue)
+{
+    MemoryRegionList *new_ml, *ml, *next_ml;
+    MemoryRegionListHead submr_print_queue;
+    MemRegionList *cur_item = NULL, *subregion;
+    MemRegion *region = NULL;
+    const MemoryRegion *submr;
+
+    if (!mr || !mr->enabled) {
+        return region;
+    }
+
+    region = g_malloc0(sizeof(*region));
+
+    if (mr->alias) {
+        MemoryRegionList *ml;
+        bool found = false;
+
+        /* check if the alias is already in the queue */
+        QTAILQ_FOREACH(ml, alias_queue, queue) {
+            if (ml->mr == mr->alias) {
+                found = true;
+            }
+        }
+
+        if (!found) {
+            ml = g_new(MemoryRegionList, 1);
+            ml->mr = mr->alias;
+            QTAILQ_INSERT_TAIL(alias_queue, ml, queue);
+        }
+
+        region->base = base+mr->addr;
+        region->size = int128_get64(int128_sub(mr->size, int128_one()));
+        region->prio = mr->priority;
+        region->read = mr->romd_mode;
+        region->write = !mr->readonly && !(mr->rom_device && mr->romd_mode);
+        region->ram = mr->ram;
+        region->name = g_strdup(memory_region_name(mr));
+        region->has_alias = true;
+        region->alias = g_strdup(memory_region_name(mr->alias));
+    } else {
+        region->base = base+mr->addr;
+        region->size = int128_get64(int128_sub(mr->size, int128_one()));
+        region->prio = mr->priority;
+        region->read = mr->romd_mode;
+        region->write = !mr->readonly && !(mr->rom_device && mr->romd_mode);
+        region->ram = mr->ram;
+        region->name = g_strdup(memory_region_name(mr));
+        region->has_alias = false;
+    }
+
+    QTAILQ_INIT(&submr_print_queue);
+
+    QTAILQ_FOREACH(submr, &mr->subregions, subregions_link) {
+        new_ml = g_new(MemoryRegionList, 1);
+        new_ml->mr = submr;
+        QTAILQ_FOREACH(ml, &submr_print_queue, queue) {
+            if (new_ml->mr->addr < ml->mr->addr ||
+                (new_ml->mr->addr == ml->mr->addr &&
+                 new_ml->mr->priority > ml->mr->priority)) {
+                QTAILQ_INSERT_BEFORE(ml, new_ml, queue);
+                new_ml = NULL;
+                break;
+            }
+        }
+        if (new_ml) {
+            QTAILQ_INSERT_TAIL(&submr_print_queue, new_ml, queue);
+        }
+    }
+
+    QTAILQ_FOREACH(ml, &submr_print_queue, queue) {
+        subregion = g_malloc0(sizeof(*subregion));
+        subregion->value = qmp_mtree_mr(ml->mr, base + mr->addr, alias_queue);
+
+        if (subregion->value != NULL) {
+            if (!cur_item) {
+                region->submr = cur_item = subregion;
+            } else {
+                cur_item->next = subregion;
+                cur_item = subregion;
+            }
+        } else {
+            g_free(subregion);
+        }
+    }
+
+    region->has_submr = (region->submr != NULL);
+
+    QTAILQ_FOREACH_SAFE(ml, &submr_print_queue, queue, next_ml) {
+        g_free(ml);
+    }
+
+    return region;
+}
+
+MemTree *qmp_query_mtree(Error **errp)
+{
+    MemoryRegionListHead ml_head;
+    MemoryRegionList *ml, *ml2;
+    AddressSpace *as;
+    AddrSpaceList *head = NULL, *cur_item = NULL, *space;
+    MemTree *mt = g_malloc0(sizeof(*mt));
+
+    QTAILQ_INIT(&ml_head);
+
+    QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
+        space = g_malloc0(sizeof(*space));
+        space->value = g_malloc0(sizeof(*space->value));
+        space->value->name = g_strdup(as->name);
+        space->value->mem = qmp_mtree_mr(as->root, 0, &ml_head);
+
+        if (!cur_item) {
+            head = cur_item = space;
+        } else {
+            cur_item->next = space;
+            cur_item = space;
+        }
+    }
+
+    mt->spaces = head;
+    head = NULL;
+    cur_item = NULL;
+
+    QTAILQ_FOREACH(ml, &ml_head, queue) {
+        space = g_malloc0(sizeof(*space));
+        space->value = g_malloc0(sizeof(*space->value));
+        space->value->name = g_strdup(memory_region_name(ml->mr));
+        space->value->mem = qmp_mtree_mr(ml->mr, 0, &ml_head);
+
+        if (!cur_item) {
+            head = cur_item = space;
+        } else {
+            cur_item->next = space;
+            cur_item = space;
+        }
+    }
+
+    mt->aliases = head;
+
+    QTAILQ_FOREACH_SAFE(ml, &ml_head, queue, ml2) {
+        g_free(ml);
+    }
+
+    return mt;
+}
+
 static const TypeInfo memory_region_info = {
     .parent             = TYPE_OBJECT,
     .name               = TYPE_MEMORY_REGION,
diff --git a/qapi-schema.json b/qapi-schema.json
index 341f417..bc35bd9 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -3481,3 +3481,71 @@
 # Since: 2.1
 ##
 { 'command': 'rtc-reset-reinjection' }
+
+##
+# @MemRegion:
+#
+# Information about a memory region
+#
+# @base: base address
+#
+# @size: size
+#
+# @prio: priority
+#
+# @read: read permitted
+#
+# @write: write permitted
+#
+# @ram: RAM region
+#
+# @name: name of the region
+#
+# @alias: #optional alias of this region
+#
+# @submr: #optional submemory regions of this region
+#
+# Since: 2.x
+##
+{ 'type': 'MemRegion',
+  'data': {'base': 'uint64', 'size': 'uint64', 'prio': 'uint32', 'read': 'bool',
+           'write': 'bool', 'ram': 'bool', 'name': 'str',
+           '*alias': 'str', '*submr': ['MemRegion']} }
+
+##
+# @AddrSpace:
+#
+# An address space of the system
+#
+# @name: name of the address space
+#
+# @mem: a list of memory regions in the address space
+#
+# Since: 2.x
+##
+{ 'type': 'AddrSpace', 'data': {'name': 'str', 'mem': 'MemRegion'} }
+
+##
+# @MemTree:
+#
+# Memory tree of the system
+#
+# @spaces: Address spaces of the system
+#
+# @aliases: Aliased memory regions
+#
+# Since: 2.x
+##
+{ 'type': 'MemTree', 'data': {'spaces': ['AddrSpace'],
+                                'aliases': ['AddrSpace']} }
+
+##
+# @query-mtree:
+#
+# Return the memory distribution of the guest
+#
+# Returns: a list of @AddrSpace
+#
+# Since: 2.x
+##
+{ 'command': 'query-mtree', 'returns': 'MemTree' }
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 4be4765..22f91b0 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -3755,3 +3755,22 @@ Example:
 <- { "return": {} }
 
 EQMP
+    {
+        .name       = "query-mtree",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_query_mtree,
+    },
+SQMP
+query-mtree
+---------
+
+Memory tree.
+
+The returned value is a json-array of the memory distribution of the system.
+Each address space is represented by a json-object, which has a name, and a
+json-array of all memory regions that contain. Each memory region is
+represented by a json-object.
+
+(Missing schema and example)
+
+EQMP
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2014-08-21  9:56 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-08-20 17:46 [Qemu-devel] [RFC] qapi: New command query-mtree Marc Marí
2014-08-20 19:09 ` Eric Blake
2014-08-20 20:08   ` Marc Marí
2014-08-20 20:12   ` Eric Blake
2014-08-21  9:06 ` Paolo Bonzini
2014-08-21  9:18   ` Marc Marí
2014-08-21  9:47     ` Paolo Bonzini
2014-08-21  9:56     ` Paolo Bonzini

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.