X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=qmp.c;h=0b4f131936052ed6062ba4b2b9434da0c2cce959;hb=5e0b7d8869a567d8f535f63510adf8f53ca438d3;hp=d0d98e777b1a41f0bdd310d394f77c2a5aaeb9a7;hpb=bc1c72171ceb9a817138603fe381d64e7f8a9364;p=mirror_qemu.git diff --git a/qmp.c b/qmp.c index d0d98e777b..0b4f131936 100644 --- a/qmp.c +++ b/qmp.c @@ -28,6 +28,8 @@ #include "qapi/qmp-input-visitor.h" #include "hw/boards.h" #include "qom/object_interfaces.h" +#include "hw/mem/pc-dimm.h" +#include "hw/acpi/acpi_dev_interface.h" NameInfo *qmp_query_name(Error **errp) { @@ -41,7 +43,7 @@ NameInfo *qmp_query_name(Error **errp) return info; } -VersionInfo *qmp_query_version(Error **err) +VersionInfo *qmp_query_version(Error **errp) { VersionInfo *info = g_malloc0(sizeof(*info)); const char *version = QEMU_VERSION; @@ -82,7 +84,7 @@ UuidInfo *qmp_query_uuid(Error **errp) return info; } -void qmp_quit(Error **err) +void qmp_quit(Error **errp) { no_shutdown = 0; qemu_system_shutdown_request(); @@ -114,8 +116,11 @@ void qmp_cpu(int64_t index, Error **errp) void qmp_cpu_add(int64_t id, Error **errp) { - if (current_machine->hot_add_cpu) { - current_machine->hot_add_cpu(id, errp); + MachineClass *mc; + + mc = MACHINE_GET_CLASS(current_machine); + if (mc->hot_add_cpu) { + mc->hot_add_cpu(id, errp); } else { error_setg(errp, "Not supported"); } @@ -143,37 +148,27 @@ SpiceInfo *qmp_query_spice(Error **errp) }; #endif -static void iostatus_bdrv_it(void *opaque, BlockDriverState *bs) -{ - bdrv_iostatus_reset(bs); -} - -static void encrypted_bdrv_it(void *opaque, BlockDriverState *bs) -{ - Error **err = opaque; - - if (!error_is_set(err) && bdrv_key_required(bs)) { - error_set(err, QERR_DEVICE_ENCRYPTED, bdrv_get_device_name(bs), - bdrv_get_encrypted_filename(bs)); - } -} - void qmp_cont(Error **errp) { - Error *local_err = NULL; + BlockDriverState *bs; if (runstate_needs_reset()) { - error_set(errp, QERR_RESET_REQUIRED); + error_setg(errp, "Resetting the Virtual Machine is required"); return; } else if (runstate_check(RUN_STATE_SUSPENDED)) { return; } - bdrv_iterate(iostatus_bdrv_it, NULL); - bdrv_iterate(encrypted_bdrv_it, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; + for (bs = bdrv_next(NULL); bs; bs = bdrv_next(bs)) { + bdrv_iostatus_reset(bs); + } + for (bs = bdrv_next(NULL); bs; bs = bdrv_next(bs)) { + if (bdrv_key_required(bs)) { + error_set(errp, QERR_DEVICE_ENCRYPTED, + bdrv_get_device_name(bs), + bdrv_get_encrypted_filename(bs)); + return; + } } if (runstate_check(RUN_STATE_INMIGRATE)) { @@ -197,7 +192,11 @@ ObjectPropertyInfoList *qmp_qom_list(const char *path, Error **errp) obj = object_resolve_path(path, &ambiguous); if (obj == NULL) { - error_set(errp, QERR_DEVICE_NOT_FOUND, path); + if (ambiguous) { + error_setg(errp, "Path '%s' is ambiguous", path); + } else { + error_set(errp, QERR_DEVICE_NOT_FOUND, path); + } return NULL; } @@ -398,12 +397,12 @@ static void qmp_change_vnc(const char *target, bool has_arg, const char *arg, #endif /* !CONFIG_VNC */ void qmp_change(const char *device, const char *target, - bool has_arg, const char *arg, Error **err) + bool has_arg, const char *arg, Error **errp) { if (strcmp(device, "vnc") == 0) { - qmp_change_vnc(target, has_arg, arg, err); + qmp_change_vnc(target, has_arg, arg, errp); } else { - qmp_change_blockdev(device, target, arg, err); + qmp_change_blockdev(device, target, arg, errp); } } @@ -434,11 +433,63 @@ ObjectTypeInfoList *qmp_qom_list_types(bool has_implements, return ret; } +/* Return a DevicePropertyInfo for a qdev property. + * + * If a qdev property with the given name does not exist, use the given default + * type. If the qdev property info should not be shown, return NULL. + * + * The caller must free the return value. + */ +static DevicePropertyInfo *make_device_property_info(ObjectClass *klass, + const char *name, + const char *default_type, + const char *description) +{ + DevicePropertyInfo *info; + Property *prop; + + do { + for (prop = DEVICE_CLASS(klass)->props; prop && prop->name; prop++) { + if (strcmp(name, prop->name) != 0) { + continue; + } + + /* + * TODO Properties without a parser are just for dirty hacks. + * qdev_prop_ptr is the only such PropertyInfo. It's marked + * for removal. This conditional should be removed along with + * it. + */ + if (!prop->info->set) { + return NULL; /* no way to set it, don't show */ + } + + info = g_malloc0(sizeof(*info)); + info->name = g_strdup(prop->name); + info->type = g_strdup(prop->info->name); + info->has_description = !!prop->info->description; + info->description = g_strdup(prop->info->description); + return info; + } + klass = object_class_get_parent(klass); + } while (klass != object_class_by_name(TYPE_DEVICE)); + + /* Not a qdev property, use the default type */ + info = g_malloc0(sizeof(*info)); + info->name = g_strdup(name); + info->type = g_strdup(default_type); + info->has_description = !!description; + info->description = g_strdup(description); + + return info; +} + DevicePropertyInfoList *qmp_device_list_properties(const char *typename, Error **errp) { ObjectClass *klass; - Property *prop; + Object *obj; + ObjectProperty *prop; DevicePropertyInfoList *prop_list = NULL; klass = object_class_by_name(typename); @@ -454,32 +505,41 @@ DevicePropertyInfoList *qmp_device_list_properties(const char *typename, return NULL; } - do { - for (prop = DEVICE_CLASS(klass)->props; prop && prop->name; prop++) { - DevicePropertyInfoList *entry; - DevicePropertyInfo *info; + obj = object_new(typename); - /* - * TODO Properties without a parser are just for dirty hacks. - * qdev_prop_ptr is the only such PropertyInfo. It's marked - * for removal. This conditional should be removed along with - * it. - */ - if (!prop->info->set) { - continue; /* no way to set it, don't show */ - } + QTAILQ_FOREACH(prop, &obj->properties, node) { + DevicePropertyInfo *info; + DevicePropertyInfoList *entry; + + /* Skip Object and DeviceState properties */ + if (strcmp(prop->name, "type") == 0 || + strcmp(prop->name, "realized") == 0 || + strcmp(prop->name, "hotpluggable") == 0 || + strcmp(prop->name, "hotplugged") == 0 || + strcmp(prop->name, "parent_bus") == 0) { + continue; + } - info = g_malloc0(sizeof(*info)); - info->name = g_strdup(prop->name); - info->type = g_strdup(prop->info->legacy_name ?: prop->info->name); + /* Skip legacy properties since they are just string versions of + * properties that we already list. + */ + if (strstart(prop->name, "legacy-", NULL)) { + continue; + } - entry = g_malloc0(sizeof(*entry)); - entry->value = info; - entry->next = prop_list; - prop_list = entry; + info = make_device_property_info(klass, prop->name, prop->type, + prop->description); + if (!info) { + continue; } - klass = object_class_get_parent(klass); - } while (klass != object_class_by_name(TYPE_DEVICE)); + + entry = g_malloc0(sizeof(*entry)); + entry->value = info; + entry->next = prop_list; + prop_list = entry; + } + + object_unref(obj); return prop_list; } @@ -537,11 +597,24 @@ void object_add(const char *type, const char *id, const QDict *qdict, Visitor *v, Error **errp) { Object *obj; + ObjectClass *klass; const QDictEntry *e; Error *local_err = NULL; - if (!object_class_by_name(type)) { - error_setg(errp, "invalid class name"); + klass = object_class_by_name(type); + if (!klass) { + error_setg(errp, "invalid object type: %s", type); + return; + } + + if (!object_class_dynamic_cast(klass, TYPE_USER_CREATABLE)) { + error_setg(errp, "object type '%s' isn't supported by object-add", + type); + return; + } + + if (object_class_is_abstract(klass)) { + error_setg(errp, "object type '%s' is abstract", type); return; } @@ -555,19 +628,18 @@ void object_add(const char *type, const char *id, const QDict *qdict, } } - if (!object_dynamic_cast(obj, TYPE_USER_CREATABLE)) { - error_setg(&local_err, "object '%s' isn't supported by object-add", - id); + object_property_add_child(container_get(object_get_root(), "/objects"), + id, obj, &local_err); + if (local_err) { goto out; } user_creatable_complete(obj, &local_err); if (local_err) { + object_property_del(container_get(object_get_root(), "/objects"), + id, &error_abort); goto out; } - - object_property_add_child(container_get(object_get_root(), "/objects"), - id, obj, &local_err); out: if (local_err) { error_propagate(errp, local_err); @@ -619,3 +691,32 @@ void qmp_object_del(const char *id, Error **errp) } object_unparent(obj); } + +MemoryDeviceInfoList *qmp_query_memory_devices(Error **errp) +{ + MemoryDeviceInfoList *head = NULL; + MemoryDeviceInfoList **prev = &head; + + qmp_pc_dimm_device_list(qdev_get_machine(), &prev); + + return head; +} + +ACPIOSTInfoList *qmp_query_acpi_ospm_status(Error **errp) +{ + bool ambig; + ACPIOSTInfoList *head = NULL; + ACPIOSTInfoList **prev = &head; + Object *obj = object_resolve_path_type("", TYPE_ACPI_DEVICE_IF, &ambig); + + if (obj) { + AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(obj); + AcpiDeviceIf *adev = ACPI_DEVICE_IF(obj); + + adevc->ospm_status(adev, &prev); + } else { + error_setg(errp, "command is not supported, missing ACPI device"); + } + + return head; +}