From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:56468) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1XK9yP-0003I3-V7 for qemu-devel@nongnu.org; Wed, 20 Aug 2014 13:47:07 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1XK9yI-0003bp-91 for qemu-devel@nongnu.org; Wed, 20 Aug 2014 13:47:01 -0400 Received: from mail-wi0-x230.google.com ([2a00:1450:400c:c05::230]:37863) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1XK9yH-0003bf-V3 for qemu-devel@nongnu.org; Wed, 20 Aug 2014 13:46:54 -0400 Received: by mail-wi0-f176.google.com with SMTP id bs8so7536275wib.3 for ; Wed, 20 Aug 2014 10:46:52 -0700 (PDT) From: =?UTF-8?q?Marc=20Mar=C3=AD?= Date: Wed, 20 Aug 2014 19:46:44 +0200 Message-Id: <1408556804-5266-1-git-send-email-marc.mari.barcelo@gmail.com> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Subject: [Qemu-devel] [RFC] qapi: New command query-mtree List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: =?UTF-8?q?Marc=20Mar=C3=AD?= , Paolo Bonzini , =?UTF-8?q?Andreas=20F=C3=A4rber?= , 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Ă­ --- 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 #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