qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [RFC] qapi: New command query-mtree


From: Paolo Bonzini
Subject: Re: [Qemu-devel] [RFC] qapi: New command query-mtree
Date: Thu, 21 Aug 2014 11:06:51 +0200
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:24.0) Gecko/20100101 Thunderbird/24.7.0

Il 20/08/2014 19:46, Marc Marí ha scritto:
> 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

I don't like this idea very much.  libqos should be using the real
memory map information from the machine.  In the case of x86, that means
fw_cfg; in the case of ARM, that would mean using the device tree.
Getting the information from an out-of-band channel (such as QMP) is
basically cheating. :)

If you had a memory map abstraction in libqos, malloc could be generic.
 Perhaps you can start doing that for PC?

Paolo

> Signed-off-by: Marc Marí <address@hidden>
> ---
>  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
> 




reply via email to

[Prev in Thread] Current Thread [Next in Thread]