qmp.c 18.8 KB
Newer Older
A
Anthony Liguori 已提交
1 2 3 4 5 6 7 8 9 10 11
/*
 * QEMU Management Protocol
 *
 * Copyright IBM, Corp. 2011
 *
 * Authors:
 *  Anthony Liguori   <aliguori@us.ibm.com>
 *
 * This work is licensed under the terms of the GNU GPL, version 2.  See
 * the COPYING file in the top-level directory.
 *
12 13
 * Contributions after 2012-01-13 are licensed under the terms of the
 * GNU GPL, version 2 or (at your option) any later version.
A
Anthony Liguori 已提交
14 15
 */

P
Peter Maydell 已提交
16
#include "qemu/osdep.h"
17
#include "qemu/cutils.h"
18
#include "monitor/monitor.h"
19
#include "sysemu/sysemu.h"
A
Anthony Liguori 已提交
20
#include "qmp-commands.h"
21
#include "sysemu/char.h"
L
Luiz Capitulino 已提交
22 23
#include "ui/qemu-spice.h"
#include "ui/vnc.h"
24 25
#include "sysemu/kvm.h"
#include "sysemu/arch_init.h"
A
Anthony Liguori 已提交
26
#include "hw/qdev.h"
27
#include "sysemu/blockdev.h"
28
#include "sysemu/block-backend.h"
29
#include "qom/qom-qobject.h"
30
#include "qapi/qmp/qerror.h"
31 32
#include "qapi/qmp/qobject.h"
#include "qapi/qmp-input-visitor.h"
I
Igor Mammedov 已提交
33
#include "hw/boards.h"
34
#include "qom/object_interfaces.h"
35
#include "hw/mem/pc-dimm.h"
36
#include "hw/acpi/acpi_dev_interface.h"
A
Anthony Liguori 已提交
37 38 39 40 41 42 43 44 45 46 47 48

NameInfo *qmp_query_name(Error **errp)
{
    NameInfo *info = g_malloc0(sizeof(*info));

    if (qemu_name) {
        info->has_name = true;
        info->name = g_strdup(qemu_name);
    }

    return info;
}
L
Luiz Capitulino 已提交
49

50
VersionInfo *qmp_query_version(Error **errp)
L
Luiz Capitulino 已提交
51
{
52
    VersionInfo *info = g_new0(VersionInfo, 1);
L
Luiz Capitulino 已提交
53
    const char *version = QEMU_VERSION;
54 55
    const char *tmp;
    int err;
L
Luiz Capitulino 已提交
56

57
    info->qemu = g_new0(VersionTriple, 1);
58 59
    err = qemu_strtoll(version, &tmp, 10, &info->qemu->major);
    assert(err == 0);
L
Luiz Capitulino 已提交
60
    tmp++;
61 62 63

    err = qemu_strtoll(tmp, &tmp, 10, &info->qemu->minor);
    assert(err == 0);
L
Luiz Capitulino 已提交
64
    tmp++;
65 66 67

    err = qemu_strtoll(tmp, &tmp, 10, &info->qemu->micro);
    assert(err == 0);
L
Luiz Capitulino 已提交
68 69 70 71
    info->package = g_strdup(QEMU_PKGVERSION);

    return info;
}
L
Luiz Capitulino 已提交
72 73 74 75 76 77 78 79 80 81 82

KvmInfo *qmp_query_kvm(Error **errp)
{
    KvmInfo *info = g_malloc0(sizeof(*info));

    info->enabled = kvm_enabled();
    info->present = kvm_available();

    return info;
}

L
Luiz Capitulino 已提交
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
UuidInfo *qmp_query_uuid(Error **errp)
{
    UuidInfo *info = g_malloc0(sizeof(*info));
    char uuid[64];

    snprintf(uuid, sizeof(uuid), UUID_FMT, qemu_uuid[0], qemu_uuid[1],
                   qemu_uuid[2], qemu_uuid[3], qemu_uuid[4], qemu_uuid[5],
                   qemu_uuid[6], qemu_uuid[7], qemu_uuid[8], qemu_uuid[9],
                   qemu_uuid[10], qemu_uuid[11], qemu_uuid[12], qemu_uuid[13],
                   qemu_uuid[14], qemu_uuid[15]);

    info->UUID = g_strdup(uuid);
    return info;
}

98
void qmp_quit(Error **errp)
L
Luiz Capitulino 已提交
99 100 101 102 103
{
    no_shutdown = 0;
    qemu_system_shutdown_request();
}

L
Luiz Capitulino 已提交
104 105
void qmp_stop(Error **errp)
{
106 107 108 109 110 111 112
    /* if there is a dump in background, we should wait until the dump
     * finished */
    if (dump_in_progress()) {
        error_setg(errp, "There is a dump in process, please wait.");
        return;
    }

113 114 115 116 117
    if (runstate_check(RUN_STATE_INMIGRATE)) {
        autostart = 0;
    } else {
        vm_stop(RUN_STATE_PAUSED);
    }
L
Luiz Capitulino 已提交
118 119
}

L
Luiz Capitulino 已提交
120 121 122 123
void qmp_system_reset(Error **errp)
{
    qemu_system_reset_request();
}
L
Luiz Capitulino 已提交
124 125 126 127 128

void qmp_system_powerdown(Error **erp)
{
    qemu_system_powerdown_request();
}
L
Luiz Capitulino 已提交
129 130 131 132 133

void qmp_cpu(int64_t index, Error **errp)
{
    /* Just do nothing */
}
L
Luiz Capitulino 已提交
134

I
Igor Mammedov 已提交
135 136
void qmp_cpu_add(int64_t id, Error **errp)
{
137 138 139
    MachineClass *mc;

    mc = MACHINE_GET_CLASS(current_machine);
140 141
    if (mc->hot_add_cpu) {
        mc->hot_add_cpu(id, errp);
I
Igor Mammedov 已提交
142 143 144 145 146
    } else {
        error_setg(errp, "Not supported");
    }
}

L
Luiz Capitulino 已提交
147 148 149 150 151
#ifndef CONFIG_VNC
/* If VNC support is enabled, the "true" query-vnc command is
   defined in the VNC subsystem */
VncInfo *qmp_query_vnc(Error **errp)
{
152
    error_setg(errp, QERR_FEATURE_DISABLED, "vnc");
L
Luiz Capitulino 已提交
153 154
    return NULL;
};
155 156 157

VncInfo2List *qmp_query_vnc_servers(Error **errp)
{
158
    error_setg(errp, QERR_FEATURE_DISABLED, "vnc");
159 160
    return NULL;
};
L
Luiz Capitulino 已提交
161
#endif
L
Luiz Capitulino 已提交
162 163

#ifndef CONFIG_SPICE
164 165 166 167 168
/*
 * qmp-commands.hx ensures that QMP command query-spice exists only
 * #ifdef CONFIG_SPICE.  Necessary for an accurate query-commands
 * result.  However, the QAPI schema is blissfully unaware of that,
 * and the QAPI code generator happily generates a dead
169 170 171
 * qmp_marshal_query_spice() that calls qmp_query_spice().  Provide it
 * one, or else linking fails.  FIXME Educate the QAPI schema on
 * CONFIG_SPICE.
172
 */
L
Luiz Capitulino 已提交
173 174
SpiceInfo *qmp_query_spice(Error **errp)
{
175
    abort();
L
Luiz Capitulino 已提交
176 177
};
#endif
L
Luiz Capitulino 已提交
178 179 180

void qmp_cont(Error **errp)
{
181
    Error *local_err = NULL;
182
    BlockBackend *blk;
183
    BlockDriverState *bs;
K
Kevin Wolf 已提交
184
    BdrvNextIterator it;
L
Luiz Capitulino 已提交
185

186 187 188 189 190 191 192
    /* if there is a dump in background, we should wait until the dump
     * finished */
    if (dump_in_progress()) {
        error_setg(errp, "There is a dump in process, please wait.");
        return;
    }

193
    if (runstate_needs_reset()) {
194
        error_setg(errp, "Resetting the Virtual Machine is required");
L
Luiz Capitulino 已提交
195
        return;
196 197
    } else if (runstate_check(RUN_STATE_SUSPENDED)) {
        return;
L
Luiz Capitulino 已提交
198 199
    }

200 201
    for (blk = blk_next(NULL); blk; blk = blk_next(blk)) {
        blk_iostatus_reset(blk);
202
    }
K
Kevin Wolf 已提交
203

K
Kevin Wolf 已提交
204
    for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
205 206 207
        bdrv_add_key(bs, NULL, &local_err);
        if (local_err) {
            error_propagate(errp, local_err);
208 209
            return;
        }
L
Luiz Capitulino 已提交
210 211
    }

212 213 214 215 216 217 218 219 220 221 222 223
    /* Continuing after completed migration. Images have been inactivated to
     * allow the destination to take control. Need to get control back now. */
    if (runstate_check(RUN_STATE_FINISH_MIGRATE) ||
        runstate_check(RUN_STATE_POSTMIGRATE))
    {
        bdrv_invalidate_cache_all(&local_err);
        if (local_err) {
            error_propagate(errp, local_err);
            return;
        }
    }

224 225 226 227 228
    if (runstate_check(RUN_STATE_INMIGRATE)) {
        autostart = 1;
    } else {
        vm_start();
    }
L
Luiz Capitulino 已提交
229
}
A
Anthony Liguori 已提交
230

231 232 233 234 235
void qmp_system_wakeup(Error **errp)
{
    qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
}

236
ObjectPropertyInfoList *qmp_qom_list(const char *path, Error **errp)
A
Anthony Liguori 已提交
237
{
238
    Object *obj;
A
Anthony Liguori 已提交
239
    bool ambiguous = false;
240 241
    ObjectPropertyInfoList *props = NULL;
    ObjectProperty *prop;
242
    ObjectPropertyIterator iter;
A
Anthony Liguori 已提交
243

244 245
    obj = object_resolve_path(path, &ambiguous);
    if (obj == NULL) {
246 247 248
        if (ambiguous) {
            error_setg(errp, "Path '%s' is ambiguous", path);
        } else {
249 250
            error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
                      "Device '%s' not found", path);
251
        }
A
Anthony Liguori 已提交
252 253 254
        return NULL;
    }

255 256
    object_property_iter_init(&iter, obj);
    while ((prop = object_property_iter_next(&iter))) {
257
        ObjectPropertyInfoList *entry = g_malloc0(sizeof(*entry));
A
Anthony Liguori 已提交
258

259
        entry->value = g_malloc0(sizeof(ObjectPropertyInfo));
A
Anthony Liguori 已提交
260 261 262 263 264 265 266 267 268
        entry->next = props;
        props = entry;

        entry->value->name = g_strdup(prop->name);
        entry->value->type = g_strdup(prop->type);
    }

    return props;
}
269

270 271
void qmp_qom_set(const char *path, const char *property, QObject *value,
                 Error **errp)
272
{
273
    Object *obj;
274

275 276
    obj = object_resolve_path(path, NULL);
    if (!obj) {
277
        error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
278
                  "Device '%s' not found", path);
279
        return;
280 281
    }

282
    object_property_set_qobject(obj, value, property, errp);
283 284
}

285
QObject *qmp_qom_get(const char *path, const char *property, Error **errp)
286
{
287
    Object *obj;
288

289 290
    obj = object_resolve_path(path, NULL);
    if (!obj) {
291
        error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
292
                  "Device '%s' not found", path);
293
        return NULL;
294 295
    }

296
    return object_property_get_qobject(obj, property, errp);
297
}
L
Luiz Capitulino 已提交
298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313

void qmp_set_password(const char *protocol, const char *password,
                      bool has_connected, const char *connected, Error **errp)
{
    int disconnect_if_connected = 0;
    int fail_if_connected = 0;
    int rc;

    if (has_connected) {
        if (strcmp(connected, "fail") == 0) {
            fail_if_connected = 1;
        } else if (strcmp(connected, "disconnect") == 0) {
            disconnect_if_connected = 1;
        } else if (strcmp(connected, "keep") == 0) {
            /* nothing */
        } else {
314
            error_setg(errp, QERR_INVALID_PARAMETER, "connected");
L
Luiz Capitulino 已提交
315 316 317 318 319
            return;
        }
    }

    if (strcmp(protocol, "spice") == 0) {
320
        if (!qemu_using_spice(errp)) {
L
Luiz Capitulino 已提交
321 322 323 324 325
            return;
        }
        rc = qemu_spice_set_passwd(password, fail_if_connected,
                                   disconnect_if_connected);
        if (rc != 0) {
326
            error_setg(errp, QERR_SET_PASSWD_FAILED);
L
Luiz Capitulino 已提交
327 328 329 330 331 332 333
        }
        return;
    }

    if (strcmp(protocol, "vnc") == 0) {
        if (fail_if_connected || disconnect_if_connected) {
            /* vnc supports "connected=keep" only */
334
            error_setg(errp, QERR_INVALID_PARAMETER, "connected");
L
Luiz Capitulino 已提交
335 336 337 338 339 340
            return;
        }
        /* Note that setting an empty password will not disable login through
         * this interface. */
        rc = vnc_display_password(NULL, password);
        if (rc < 0) {
341
            error_setg(errp, QERR_SET_PASSWD_FAILED);
L
Luiz Capitulino 已提交
342 343 344 345
        }
        return;
    }

346
    error_setg(errp, QERR_INVALID_PARAMETER, "protocol");
L
Luiz Capitulino 已提交
347
}
L
Luiz Capitulino 已提交
348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365

void qmp_expire_password(const char *protocol, const char *whenstr,
                         Error **errp)
{
    time_t when;
    int rc;

    if (strcmp(whenstr, "now") == 0) {
        when = 0;
    } else if (strcmp(whenstr, "never") == 0) {
        when = TIME_MAX;
    } else if (whenstr[0] == '+') {
        when = time(NULL) + strtoull(whenstr+1, NULL, 10);
    } else {
        when = strtoull(whenstr, NULL, 10);
    }

    if (strcmp(protocol, "spice") == 0) {
366
        if (!qemu_using_spice(errp)) {
L
Luiz Capitulino 已提交
367 368 369 370
            return;
        }
        rc = qemu_spice_set_pw_expire(when);
        if (rc != 0) {
371
            error_setg(errp, QERR_SET_PASSWD_FAILED);
L
Luiz Capitulino 已提交
372 373 374 375 376 377 378
        }
        return;
    }

    if (strcmp(protocol, "vnc") == 0) {
        rc = vnc_display_pw_expire(NULL, when);
        if (rc != 0) {
379
            error_setg(errp, QERR_SET_PASSWD_FAILED);
L
Luiz Capitulino 已提交
380 381 382 383
        }
        return;
    }

384
    error_setg(errp, QERR_INVALID_PARAMETER, "protocol");
L
Luiz Capitulino 已提交
385
}
386

L
Luiz Capitulino 已提交
387
#ifdef CONFIG_VNC
388 389 390
void qmp_change_vnc_password(const char *password, Error **errp)
{
    if (vnc_display_password(NULL, password) < 0) {
391
        error_setg(errp, QERR_SET_PASSWD_FAILED);
392 393
    }
}
L
Luiz Capitulino 已提交
394

395
static void qmp_change_vnc_listen(const char *target, Error **errp)
L
Luiz Capitulino 已提交
396
{
397 398 399 400 401 402 403 404 405 406 407 408
    QemuOptsList *olist = qemu_find_opts("vnc");
    QemuOpts *opts;

    if (strstr(target, "id=")) {
        error_setg(errp, "id not supported");
        return;
    }

    opts = qemu_opts_find(olist, "default");
    if (opts) {
        qemu_opts_del(opts);
    }
409
    opts = vnc_parse(target, errp);
410 411 412 413
    if (!opts) {
        return;
    }

414
    vnc_display_open("default", errp);
L
Luiz Capitulino 已提交
415 416 417 418 419 420 421
}

static void qmp_change_vnc(const char *target, bool has_arg, const char *arg,
                           Error **errp)
{
    if (strcmp(target, "passwd") == 0 || strcmp(target, "password") == 0) {
        if (!has_arg) {
422
            error_setg(errp, QERR_MISSING_PARAMETER, "password");
L
Luiz Capitulino 已提交
423 424 425 426 427 428 429 430 431 432
        } else {
            qmp_change_vnc_password(arg, errp);
        }
    } else {
        qmp_change_vnc_listen(target, errp);
    }
}
#else
void qmp_change_vnc_password(const char *password, Error **errp)
{
433
    error_setg(errp, QERR_FEATURE_DISABLED, "vnc");
L
Luiz Capitulino 已提交
434 435 436 437
}
static void qmp_change_vnc(const char *target, bool has_arg, const char *arg,
                           Error **errp)
{
438
    error_setg(errp, QERR_FEATURE_DISABLED, "vnc");
L
Luiz Capitulino 已提交
439 440 441 442
}
#endif /* !CONFIG_VNC */

void qmp_change(const char *device, const char *target,
443
                bool has_arg, const char *arg, Error **errp)
L
Luiz Capitulino 已提交
444 445
{
    if (strcmp(device, "vnc") == 0) {
446
        qmp_change_vnc(target, has_arg, arg, errp);
L
Luiz Capitulino 已提交
447
    } else {
448 449
        qmp_blockdev_change_medium(device, target, has_arg, arg, false, 0,
                                   errp);
L
Luiz Capitulino 已提交
450 451
    }
}
452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478

static void qom_list_types_tramp(ObjectClass *klass, void *data)
{
    ObjectTypeInfoList *e, **pret = data;
    ObjectTypeInfo *info;

    info = g_malloc0(sizeof(*info));
    info->name = g_strdup(object_class_get_name(klass));

    e = g_malloc0(sizeof(*e));
    e->value = info;
    e->next = *pret;
    *pret = e;
}

ObjectTypeInfoList *qmp_qom_list_types(bool has_implements,
                                       const char *implements,
                                       bool has_abstract,
                                       bool abstract,
                                       Error **errp)
{
    ObjectTypeInfoList *ret = NULL;

    object_class_foreach(qom_list_types_tramp, implements, abstract, &ret);

    return ret;
}
479

480 481 482 483 484 485 486 487 488
/* 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,
489 490
                                                     const char *default_type,
                                                     const char *description)
491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512
{
    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);
513 514 515
            info->type = g_strdup(prop->info->name);
            info->has_description = !!prop->info->description;
            info->description = g_strdup(prop->info->description);
516 517 518 519 520 521 522 523 524
            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);
525 526 527
    info->has_description = !!description;
    info->description = g_strdup(description);

528 529 530
    return info;
}

531 532 533 534
DevicePropertyInfoList *qmp_device_list_properties(const char *typename,
                                                   Error **errp)
{
    ObjectClass *klass;
535 536
    Object *obj;
    ObjectProperty *prop;
537
    ObjectPropertyIterator iter;
538 539 540 541
    DevicePropertyInfoList *prop_list = NULL;

    klass = object_class_by_name(typename);
    if (klass == NULL) {
542 543
        error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
                  "Device '%s' not found", typename);
544 545 546 547 548
        return NULL;
    }

    klass = object_class_dynamic_cast(klass, TYPE_DEVICE);
    if (klass == NULL) {
549
        error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "name", TYPE_DEVICE);
550 551 552
        return NULL;
    }

553 554 555 556 557 558
    if (object_class_is_abstract(klass)) {
        error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "name",
                   "non-abstract device type");
        return NULL;
    }

559 560 561 562 563
    if (DEVICE_CLASS(klass)->cannot_destroy_with_object_finalize_yet) {
        error_setg(errp, "Can't list properties of device '%s'", typename);
        return NULL;
    }

564
    obj = object_new(typename);
565

566 567
    object_property_iter_init(&iter, obj);
    while ((prop = object_property_iter_next(&iter))) {
568 569 570 571 572 573 574
        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 ||
575
            strcmp(prop->name, "hotplugged") == 0 ||
576 577 578
            strcmp(prop->name, "parent_bus") == 0) {
            continue;
        }
579

580 581 582 583 584 585
        /* Skip legacy properties since they are just string versions of
         * properties that we already list.
         */
        if (strstart(prop->name, "legacy-", NULL)) {
            continue;
        }
586

587 588
        info = make_device_property_info(klass, prop->name, prop->type,
                                         prop->description);
589 590
        if (!info) {
            continue;
591
        }
592 593 594 595 596 597 598 599

        entry = g_malloc0(sizeof(*entry));
        entry->value = info;
        entry->next = prop_list;
        prop_list = entry;
    }

    object_unref(obj);
600 601 602

    return prop_list;
}
603

604 605 606 607 608
CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
{
    return arch_query_cpu_definitions(errp);
}

L
Luiz Capitulino 已提交
609 610 611 612 613 614 615 616 617 618 619 620 621
void qmp_add_client(const char *protocol, const char *fdname,
                    bool has_skipauth, bool skipauth, bool has_tls, bool tls,
                    Error **errp)
{
    CharDriverState *s;
    int fd;

    fd = monitor_get_fd(cur_mon, fdname, errp);
    if (fd < 0) {
        return;
    }

    if (strcmp(protocol, "spice") == 0) {
622
        if (!qemu_using_spice(errp)) {
L
Luiz Capitulino 已提交
623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650
            close(fd);
            return;
        }
        skipauth = has_skipauth ? skipauth : false;
        tls = has_tls ? tls : false;
        if (qemu_spice_display_add_client(fd, skipauth, tls) < 0) {
            error_setg(errp, "spice failed to add client");
            close(fd);
        }
        return;
#ifdef CONFIG_VNC
    } else if (strcmp(protocol, "vnc") == 0) {
        skipauth = has_skipauth ? skipauth : false;
        vnc_display_add_client(NULL, fd, skipauth);
        return;
#endif
    } else if ((s = qemu_chr_find(protocol)) != NULL) {
        if (qemu_chr_add_client(s, fd) < 0) {
            error_setg(errp, "failed to add client");
            close(fd);
            return;
        }
        return;
    }

    error_setg(errp, "protocol '%s' is invalid", protocol);
    close(fd);
}
651

652

653 654
void qmp_object_add(const char *type, const char *id,
                    bool has_props, QObject *props, Error **errp)
655 656 657
{
    const QDict *pdict = NULL;
    QmpInputVisitor *qiv;
658
    Object *obj;
659 660 661 662

    if (props) {
        pdict = qobject_to_qdict(props);
        if (!pdict) {
663 664
            error_setg(errp, QERR_INVALID_PARAMETER_TYPE, "props", "dict");
            return;
665 666 667
        }
    }

668
    qiv = qmp_input_visitor_new(props, true);
669 670
    obj = user_creatable_add_type(type, id, pdict,
                                  qmp_input_get_visitor(qiv), errp);
671
    qmp_input_visitor_cleanup(qiv);
672 673 674
    if (obj) {
        object_unref(obj);
    }
675 676
}

677 678
void qmp_object_del(const char *id, Error **errp)
{
679
    user_creatable_del(id, errp);
680
}
681 682 683 684 685 686 687 688 689 690

MemoryDeviceInfoList *qmp_query_memory_devices(Error **errp)
{
    MemoryDeviceInfoList *head = NULL;
    MemoryDeviceInfoList **prev = &head;

    qmp_pc_dimm_device_list(qdev_get_machine(), &prev);

    return head;
}
691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709

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;
}