qdev-monitor.c 23.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/*
 *  Dynamic device configuration and creation.
 *
 *  Copyright (c) 2009 CodeSourcery
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
 */

20
#include "hw/qdev.h"
21
#include "hw/sysbus.h"
22
#include "monitor/monitor.h"
23
#include "monitor/qdev.h"
L
Luiz Capitulino 已提交
24
#include "qmp-commands.h"
25
#include "sysemu/arch_init.h"
26
#include "qemu/config-file.h"
27
#include "qemu/error-report.h"
28 29 30 31 32 33 34 35 36

/*
 * Aliases were a bad idea from the start.  Let's keep them
 * from spreading further.
 */
typedef struct QDevAlias
{
    const char *typename;
    const char *alias;
A
Alexander Graf 已提交
37
    uint32_t arch_mask;
38 39 40
} QDevAlias;

static const QDevAlias qdev_alias_table[] = {
A
Alexander Graf 已提交
41 42 43 44 45
    { "virtio-blk-pci", "virtio-blk", QEMU_ARCH_ALL & ~QEMU_ARCH_S390X },
    { "virtio-net-pci", "virtio-net", QEMU_ARCH_ALL & ~QEMU_ARCH_S390X },
    { "virtio-serial-pci", "virtio-serial", QEMU_ARCH_ALL & ~QEMU_ARCH_S390X },
    { "virtio-balloon-pci", "virtio-balloon",
            QEMU_ARCH_ALL & ~QEMU_ARCH_S390X },
46 47 48
    { "virtio-blk-ccw", "virtio-blk", QEMU_ARCH_S390X },
    { "virtio-net-ccw", "virtio-net", QEMU_ARCH_S390X },
    { "virtio-serial-ccw", "virtio-serial", QEMU_ARCH_S390X },
49 50
    { "lsi53c895a", "lsi" },
    { "ich9-ahci", "ahci" },
51
    { "kvm-pci-assign", "pci-assign" },
52 53 54 55 56 57 58 59 60
    { }
};

static const char *qdev_class_get_alias(DeviceClass *dc)
{
    const char *typename = object_class_get_name(OBJECT_CLASS(dc));
    int i;

    for (i = 0; qdev_alias_table[i].typename; i++) {
A
Alexander Graf 已提交
61 62 63 64 65
        if (qdev_alias_table[i].arch_mask &&
            !(qdev_alias_table[i].arch_mask & arch_type)) {
            continue;
        }

66 67 68 69 70 71 72 73 74 75 76 77 78
        if (strcmp(qdev_alias_table[i].typename, typename) == 0) {
            return qdev_alias_table[i].alias;
        }
    }

    return NULL;
}

static bool qdev_class_has_alias(DeviceClass *dc)
{
    return (qdev_class_get_alias(dc) != NULL);
}

79
static void qdev_print_devinfo(DeviceClass *dc)
80
{
81
    error_printf("name \"%s\"", object_class_get_name(OBJECT_CLASS(dc)));
82 83
    if (dc->bus_type) {
        error_printf(", bus %s", dc->bus_type);
84 85 86 87 88 89 90
    }
    if (qdev_class_has_alias(dc)) {
        error_printf(", alias \"%s\"", qdev_class_get_alias(dc));
    }
    if (dc->desc) {
        error_printf(", desc \"%s\"", dc->desc);
    }
91
    if (dc->cannot_instantiate_with_device_add_yet) {
92 93 94 95 96
        error_printf(", no-user");
    }
    error_printf("\n");
}

97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
static gint devinfo_cmp(gconstpointer a, gconstpointer b)
{
    return strcasecmp(object_class_get_name((ObjectClass *)a),
                      object_class_get_name((ObjectClass *)b));
}

static void qdev_print_devinfos(bool show_no_user)
{
    static const char *cat_name[DEVICE_CATEGORY_MAX + 1] = {
        [DEVICE_CATEGORY_BRIDGE]  = "Controller/Bridge/Hub",
        [DEVICE_CATEGORY_USB]     = "USB",
        [DEVICE_CATEGORY_STORAGE] = "Storage",
        [DEVICE_CATEGORY_NETWORK] = "Network",
        [DEVICE_CATEGORY_INPUT]   = "Input",
        [DEVICE_CATEGORY_DISPLAY] = "Display",
        [DEVICE_CATEGORY_SOUND]   = "Sound",
        [DEVICE_CATEGORY_MISC]    = "Misc",
        [DEVICE_CATEGORY_MAX]     = "Uncategorized",
    };
    GSList *list, *elt;
    int i;
    bool cat_printed;

    list = g_slist_sort(object_class_get_list(TYPE_DEVICE, false),
                        devinfo_cmp);

    for (i = 0; i <= DEVICE_CATEGORY_MAX; i++) {
        cat_printed = false;
        for (elt = list; elt; elt = elt->next) {
            DeviceClass *dc = OBJECT_CLASS_CHECK(DeviceClass, elt->data,
                                                 TYPE_DEVICE);
            if ((i < DEVICE_CATEGORY_MAX
                 ? !test_bit(i, dc->categories)
                 : !bitmap_empty(dc->categories, DEVICE_CATEGORY_MAX))
131 132
                || (!show_no_user
                    && dc->cannot_instantiate_with_device_add_yet)) {
133 134 135 136 137 138 139 140 141 142 143 144 145 146
                continue;
            }
            if (!cat_printed) {
                error_printf("%s%s devices:\n", i ? "\n" : "",
                             cat_name[i]);
                cat_printed = true;
            }
            qdev_print_devinfo(dc);
        }
    }

    g_slist_free(list);
}

147 148
static int set_property(void *opaque, const char *name, const char *value,
                        Error **errp)
149
{
P
Paolo Bonzini 已提交
150
    Object *obj = opaque;
151
    Error *err = NULL;
152 153 154 155 156 157

    if (strcmp(name, "driver") == 0)
        return 0;
    if (strcmp(name, "bus") == 0)
        return 0;

P
Paolo Bonzini 已提交
158
    object_property_parse(obj, value, name, &err);
159
    if (err != NULL) {
160
        error_propagate(errp, err);
161 162 163 164 165 166 167 168 169 170
        return -1;
    }
    return 0;
}

static const char *find_typename_by_alias(const char *alias)
{
    int i;

    for (i = 0; qdev_alias_table[i].alias; i++) {
A
Alexander Graf 已提交
171 172 173 174 175
        if (qdev_alias_table[i].arch_mask &&
            !(qdev_alias_table[i].arch_mask & arch_type)) {
            continue;
        }

176 177 178 179 180 181 182 183
        if (strcmp(qdev_alias_table[i].alias, alias) == 0) {
            return qdev_alias_table[i].typename;
        }
    }

    return NULL;
}

184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
static DeviceClass *qdev_get_device_class(const char **driver, Error **errp)
{
    ObjectClass *oc;
    DeviceClass *dc;

    oc = object_class_by_name(*driver);
    if (!oc) {
        const char *typename = find_typename_by_alias(*driver);

        if (typename) {
            *driver = typename;
            oc = object_class_by_name(*driver);
        }
    }

    if (!object_class_dynamic_cast(oc, TYPE_DEVICE)) {
        error_setg(errp, "'%s' is not a valid device model name", *driver);
        return NULL;
    }

    if (object_class_is_abstract(oc)) {
205 206
        error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "driver",
                   "non-abstract device type");
207 208 209 210 211 212
        return NULL;
    }

    dc = DEVICE_CLASS(oc);
    if (dc->cannot_instantiate_with_device_add_yet ||
        (qdev_hotplug && !dc->hotpluggable)) {
213 214
        error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "driver",
                   "pluggable device type");
215 216 217 218 219 220 221
        return NULL;
    }

    return dc;
}


222 223
int qdev_device_help(QemuOpts *opts)
{
224
    Error *local_err = NULL;
225
    const char *driver;
226 227
    DevicePropertyInfoList *prop_list;
    DevicePropertyInfoList *prop;
228 229

    driver = qemu_opt_get(opts, "driver");
230
    if (driver && is_help_option(driver)) {
231
        qdev_print_devinfos(false);
232 233 234
        return 1;
    }

235
    if (!driver || !qemu_opt_has_help_opt(opts)) {
236 237 238
        return 0;
    }

239 240 241
    qdev_get_device_class(&driver, &local_err);
    if (local_err) {
        goto error;
242 243
    }

244
    prop_list = qmp_device_list_properties(driver, &local_err);
245
    if (local_err) {
246
        goto error;
247
    }
248 249

    for (prop = prop_list; prop; prop = prop->next) {
250
        error_printf("%s.%s=%s", driver,
251 252
                     prop->value->name,
                     prop->value->type);
253 254 255 256 257
        if (prop->value->has_description) {
            error_printf(" (%s)\n", prop->value->description);
        } else {
            error_printf("\n");
        }
258 259 260
    }

    qapi_free_DevicePropertyInfoList(prop_list);
261
    return 1;
262 263 264 265 266

error:
    error_printf("%s\n", error_get_pretty(local_err));
    error_free(local_err);
    return 1;
267 268
}

269
static Object *qdev_get_peripheral(void)
270
{
271
    static Object *dev;
272 273

    if (dev == NULL) {
274
        dev = container_get(qdev_get_machine(), "/peripheral");
275 276
    }

277
    return dev;
278 279
}

280
static Object *qdev_get_peripheral_anon(void)
281
{
282
    static Object *dev;
283 284

    if (dev == NULL) {
285
        dev = container_get(qdev_get_machine(), "/peripheral-anon");
286 287
    }

288
    return dev;
289 290
}

291
#if 0 /* conversion from qerror_report() to error_set() broke their use */
292 293 294 295 296
static void qbus_list_bus(DeviceState *dev)
{
    BusState *child;
    const char *sep = " ";

297
    error_printf("child buses at \"%s\":",
298 299 300 301 302 303 304 305 306 307
                 dev->id ? dev->id : object_get_typename(OBJECT(dev)));
    QLIST_FOREACH(child, &dev->child_bus, sibling) {
        error_printf("%s\"%s\"", sep, child->name);
        sep = ", ";
    }
    error_printf("\n");
}

static void qbus_list_dev(BusState *bus)
{
A
Anthony Liguori 已提交
308
    BusChild *kid;
309 310 311
    const char *sep = " ";

    error_printf("devices at \"%s\":", bus->name);
A
Anthony Liguori 已提交
312 313
    QTAILQ_FOREACH(kid, &bus->children, sibling) {
        DeviceState *dev = kid->child;
314 315 316 317 318 319 320
        error_printf("%s\"%s\"", sep, object_get_typename(OBJECT(dev)));
        if (dev->id)
            error_printf("/\"%s\"", dev->id);
        sep = ", ";
    }
    error_printf("\n");
}
321
#endif
322 323 324 325 326 327 328 329 330 331 332 333 334 335 336

static BusState *qbus_find_bus(DeviceState *dev, char *elem)
{
    BusState *child;

    QLIST_FOREACH(child, &dev->child_bus, sibling) {
        if (strcmp(child->name, elem) == 0) {
            return child;
        }
    }
    return NULL;
}

static DeviceState *qbus_find_dev(BusState *bus, char *elem)
{
A
Anthony Liguori 已提交
337
    BusChild *kid;
338 339 340 341 342 343 344

    /*
     * try to match in order:
     *   (1) instance id, if present
     *   (2) driver name
     *   (3) driver alias, if present
     */
A
Anthony Liguori 已提交
345 346
    QTAILQ_FOREACH(kid, &bus->children, sibling) {
        DeviceState *dev = kid->child;
347 348 349 350
        if (dev->id  &&  strcmp(dev->id, elem) == 0) {
            return dev;
        }
    }
A
Anthony Liguori 已提交
351 352
    QTAILQ_FOREACH(kid, &bus->children, sibling) {
        DeviceState *dev = kid->child;
353 354 355 356
        if (strcmp(object_get_typename(OBJECT(dev)), elem) == 0) {
            return dev;
        }
    }
A
Anthony Liguori 已提交
357 358
    QTAILQ_FOREACH(kid, &bus->children, sibling) {
        DeviceState *dev = kid->child;
359 360 361 362 363 364 365 366 367 368
        DeviceClass *dc = DEVICE_GET_CLASS(dev);

        if (qdev_class_has_alias(dc) &&
            strcmp(qdev_class_get_alias(dc), elem) == 0) {
            return dev;
        }
    }
    return NULL;
}

369 370 371 372 373 374 375 376 377 378 379 380 381 382
static inline bool qbus_is_full(BusState *bus)
{
    BusClass *bus_class = BUS_GET_CLASS(bus);
    return bus_class->max_dev && bus->max_index >= bus_class->max_dev;
}

/*
 * Search the tree rooted at @bus for a bus.
 * If @name, search for a bus with that name.  Note that bus names
 * need not be unique.  Yes, that's screwed up.
 * Else search for a bus that is a subtype of @bus_typename.
 * If more than one exists, prefer one that can take another device.
 * Return the bus if found, else %NULL.
 */
383
static BusState *qbus_find_recursive(BusState *bus, const char *name,
384
                                     const char *bus_typename)
385
{
A
Anthony Liguori 已提交
386
    BusChild *kid;
387 388 389 390 391 392 393 394
    BusState *pick, *child, *ret;
    bool match;

    assert(name || bus_typename);
    if (name) {
        match = !strcmp(bus->name, name);
    } else {
        match = !!object_dynamic_cast(OBJECT(bus), bus_typename);
395
    }
396 397 398

    if (match && !qbus_is_full(bus)) {
        return bus;             /* root matches and isn't full */
399 400
    }

401 402
    pick = match ? bus : NULL;

A
Anthony Liguori 已提交
403 404
    QTAILQ_FOREACH(kid, &bus->children, sibling) {
        DeviceState *dev = kid->child;
405
        QLIST_FOREACH(child, &dev->child_bus, sibling) {
406
            ret = qbus_find_recursive(child, name, bus_typename);
407 408 409 410 411
            if (ret && !qbus_is_full(ret)) {
                return ret;     /* a descendant matches and isn't full */
            }
            if (ret && !pick) {
                pick = ret;
412 413 414
            }
        }
    }
415 416 417

    /* root or a descendant matches, but is full */
    return pick;
418 419
}

420
static BusState *qbus_find(const char *path, Error **errp)
421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437
{
    DeviceState *dev;
    BusState *bus;
    char elem[128];
    int pos, len;

    /* find start element */
    if (path[0] == '/') {
        bus = sysbus_get_default();
        pos = 0;
    } else {
        if (sscanf(path, "%127[^/]%n", elem, &len) != 1) {
            assert(!path[0]);
            elem[0] = len = 0;
        }
        bus = qbus_find_recursive(sysbus_get_default(), elem, NULL);
        if (!bus) {
438
            error_setg(errp, "Bus '%s' not found", elem);
439 440 441 442 443 444 445 446 447 448 449
            return NULL;
        }
        pos = len;
    }

    for (;;) {
        assert(path[pos] == '/' || !path[pos]);
        while (path[pos] == '/') {
            pos++;
        }
        if (path[pos] == '\0') {
450
            break;
451 452 453 454
        }

        /* find device */
        if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {
455
            g_assert_not_reached();
456 457 458 459 460
            elem[0] = len = 0;
        }
        pos += len;
        dev = qbus_find_dev(bus, elem);
        if (!dev) {
461 462
            error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
                      "Device '%s' not found", elem);
463
#if 0 /* conversion from qerror_report() to error_set() broke this: */
464 465 466
            if (!monitor_cur_is_qmp()) {
                qbus_list_dev(bus);
            }
467
#endif
468 469 470 471 472 473 474 475 476 477
            return NULL;
        }

        assert(path[pos] == '/' || !path[pos]);
        while (path[pos] == '/') {
            pos++;
        }
        if (path[pos] == '\0') {
            /* last specified element is a device.  If it has exactly
             * one child bus accept it nevertheless */
478 479 480 481 482
            if (dev->num_child_bus == 1) {
                bus = QLIST_FIRST(&dev->child_bus);
                break;
            }
            if (dev->num_child_bus) {
483 484 485
                error_setg(errp, "Device '%s' has multiple child buses",
                           elem);
#if 0 /* conversion from qerror_report() to error_set() broke this: */
486 487 488
                if (!monitor_cur_is_qmp()) {
                    qbus_list_bus(dev);
                }
489
#endif
490
            } else {
491
                error_setg(errp, "Device '%s' has no child bus", elem);
492
            }
493
            return NULL;
494 495 496 497
        }

        /* find bus */
        if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {
498
            g_assert_not_reached();
499 500 501 502 503
            elem[0] = len = 0;
        }
        pos += len;
        bus = qbus_find_bus(dev, elem);
        if (!bus) {
504 505
            error_setg(errp, "Bus '%s' not found", elem);
#if 0 /* conversion from qerror_report() to error_set() broke this: */
506 507 508
            if (!monitor_cur_is_qmp()) {
                qbus_list_bus(dev);
            }
509
#endif
510 511 512
            return NULL;
        }
    }
513 514

    if (qbus_is_full(bus)) {
515
        error_setg(errp, "Bus '%s' is full", path);
516 517 518
        return NULL;
    }
    return bus;
519 520
}

521
DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
522
{
523
    DeviceClass *dc;
524
    const char *driver, *path, *id;
525
    DeviceState *dev;
526
    BusState *bus = NULL;
527
    Error *err = NULL;
528 529 530

    driver = qemu_opt_get(opts, "driver");
    if (!driver) {
531
        error_setg(errp, QERR_MISSING_PARAMETER, "driver");
532 533 534 535
        return NULL;
    }

    /* find driver */
536 537
    dc = qdev_get_device_class(&driver, errp);
    if (!dc) {
538 539
        return NULL;
    }
540 541 542 543

    /* find bus */
    path = qemu_opt_get(opts, "bus");
    if (path != NULL) {
544
        bus = qbus_find(path, errp);
545 546 547
        if (!bus) {
            return NULL;
        }
548
        if (!object_dynamic_cast(OBJECT(bus), dc->bus_type)) {
549 550
            error_setg(errp, "Device '%s' can't go on %s bus",
                       driver, object_get_typename(OBJECT(bus)));
551 552
            return NULL;
        }
553 554
    } else if (dc->bus_type != NULL) {
        bus = qbus_find_recursive(sysbus_get_default(), NULL, dc->bus_type);
555
        if (!bus || qbus_is_full(bus)) {
556 557
            error_setg(errp, "No '%s' bus found for device '%s'",
                       dc->bus_type, driver);
558 559 560
            return NULL;
        }
    }
561
    if (qdev_hotplug && bus && !qbus_is_hotpluggable(bus)) {
562
        error_setg(errp, QERR_BUS_NO_HOTPLUG, bus->name);
563 564 565
        return NULL;
    }

566
    /* create device */
567
    dev = DEVICE(object_new(driver));
568 569

    if (bus) {
570
        qdev_set_parent_bus(dev, bus);
571
    }
572 573 574

    id = qemu_opts_id(opts);
    if (id) {
575
        dev->id = id;
576
    }
577

578 579 580
    if (dev->id) {
        object_property_add_child(qdev_get_peripheral(), dev->id,
                                  OBJECT(dev), NULL);
581 582 583
    } else {
        static int anon_count;
        gchar *name = g_strdup_printf("device[%d]", anon_count++);
584
        object_property_add_child(qdev_get_peripheral_anon(), name,
585
                                  OBJECT(dev), NULL);
586
        g_free(name);
587
    }
588

589
    /* set properties */
590
    if (qemu_opt_foreach(opts, set_property, dev, &err)) {
591
        error_propagate(errp, err);
592 593 594 595 596
        object_unparent(OBJECT(dev));
        object_unref(OBJECT(dev));
        return NULL;
    }

597
    dev->opts = opts;
598 599
    object_property_set_bool(OBJECT(dev), true, "realized", &err);
    if (err != NULL) {
600
        error_propagate(errp, err);
601
        dev->opts = NULL;
602
        object_unparent(OBJECT(dev));
603
        object_unref(OBJECT(dev));
604 605
        return NULL;
    }
606
    return dev;
607 608 609 610 611 612 613
}


#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
static void qbus_print(Monitor *mon, BusState *bus, int indent);

static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
614
                             int indent)
615 616 617
{
    if (!props)
        return;
618 619 620 621 622 623 624
    for (; props->name; props++) {
        Error *err = NULL;
        char *value;
        char *legacy_name = g_strdup_printf("legacy-%s", props->name);
        if (object_property_get_type(OBJECT(dev), legacy_name, NULL)) {
            value = object_property_get_str(OBJECT(dev), legacy_name, &err);
        } else {
625
            value = object_property_print(OBJECT(dev), props->name, true, &err);
626 627 628 629 630 631
        }
        g_free(legacy_name);

        if (err) {
            error_free(err);
            continue;
632
        }
633
        qdev_printf("%s = %s\n", props->name,
634 635
                    value && *value ? value : "<null>");
        g_free(value);
636 637 638
    }
}

639 640 641 642 643 644 645 646 647
static void bus_print_dev(BusState *bus, Monitor *mon, DeviceState *dev, int indent)
{
    BusClass *bc = BUS_GET_CLASS(bus);

    if (bc->print_dev) {
        bc->print_dev(mon, dev, indent);
    }
}

648 649
static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
{
650
    ObjectClass *class;
651
    BusState *child;
P
Peter Crosthwaite 已提交
652 653
    NamedGPIOList *ngl;

654 655 656
    qdev_printf("dev: %s, id \"%s\"\n", object_get_typename(OBJECT(dev)),
                dev->id ? dev->id : "");
    indent += 2;
P
Peter Crosthwaite 已提交
657 658 659 660 661 662 663 664 665
    QLIST_FOREACH(ngl, &dev->gpios, node) {
        if (ngl->num_in) {
            qdev_printf("gpio-in \"%s\" %d\n", ngl->name ? ngl->name : "",
                        ngl->num_in);
        }
        if (ngl->num_out) {
            qdev_printf("gpio-out \"%s\" %d\n", ngl->name ? ngl->name : "",
                        ngl->num_out);
        }
666
    }
667 668 669 670 671
    class = object_get_class(OBJECT(dev));
    do {
        qdev_print_props(mon, dev, DEVICE_CLASS(class)->props, indent);
        class = object_class_get_parent(class);
    } while (class != object_class_by_name(TYPE_DEVICE));
G
Gerd Hoffmann 已提交
672
    bus_print_dev(dev->parent_bus, mon, dev, indent);
673 674 675 676 677 678 679
    QLIST_FOREACH(child, &dev->child_bus, sibling) {
        qbus_print(mon, child, indent);
    }
}

static void qbus_print(Monitor *mon, BusState *bus, int indent)
{
A
Anthony Liguori 已提交
680
    BusChild *kid;
681 682 683

    qdev_printf("bus: %s\n", bus->name);
    indent += 2;
684
    qdev_printf("type %s\n", object_get_typename(OBJECT(bus)));
A
Anthony Liguori 已提交
685 686
    QTAILQ_FOREACH(kid, &bus->children, sibling) {
        DeviceState *dev = kid->child;
687 688 689 690 691
        qdev_print(mon, dev, indent);
    }
}
#undef qdev_printf

692
void hmp_info_qtree(Monitor *mon, const QDict *qdict)
693 694 695 696 697
{
    if (sysbus_get_default())
        qbus_print(mon, sysbus_get_default(), 0);
}

698
void hmp_info_qdm(Monitor *mon, const QDict *qdict)
699
{
700
    qdev_print_devinfos(true);
701 702
}

703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759
typedef struct QOMCompositionState {
    Monitor *mon;
    int indent;
} QOMCompositionState;

static void print_qom_composition(Monitor *mon, Object *obj, int indent);

static int print_qom_composition_child(Object *obj, void *opaque)
{
    QOMCompositionState *s = opaque;

    print_qom_composition(s->mon, obj, s->indent);

    return 0;
}

static void print_qom_composition(Monitor *mon, Object *obj, int indent)
{
    QOMCompositionState s = {
        .mon = mon,
        .indent = indent + 2,
    };
    char *name;

    if (obj == object_get_root()) {
        name = g_strdup("");
    } else {
        name = object_get_canonical_path_component(obj);
    }
    monitor_printf(mon, "%*s/%s (%s)\n", indent, "", name,
                   object_get_typename(obj));
    g_free(name);
    object_child_foreach(obj, print_qom_composition_child, &s);
}

void hmp_info_qom_tree(Monitor *mon, const QDict *dict)
{
    const char *path = qdict_get_try_str(dict, "path");
    Object *obj;
    bool ambiguous = false;

    if (path) {
        obj = object_resolve_path(path, &ambiguous);
        if (!obj) {
            monitor_printf(mon, "Path '%s' could not be resolved.\n", path);
            return;
        }
        if (ambiguous) {
            monitor_printf(mon, "Warning: Path '%s' is ambiguous.\n", path);
            return;
        }
    } else {
        obj = qdev_get_machine();
    }
    print_qom_composition(mon, obj, 0);
}

760
void qmp_device_add(QDict *qdict, QObject **ret_data, Error **errp)
761
{
762
    Error *local_err = NULL;
763
    QemuOpts *opts;
764
    DeviceState *dev;
765

766
    opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict, &local_err);
767
    if (local_err) {
768 769
        error_propagate(errp, local_err);
        return;
770 771 772
    }
    if (!monitor_cur_is_qmp() && qdev_device_help(opts)) {
        qemu_opts_del(opts);
773
        return;
774
    }
775
    dev = qdev_device_add(opts, &local_err);
776
    if (!dev) {
777
        error_propagate(errp, local_err);
778
        qemu_opts_del(opts);
779
        return;
780
    }
781
    object_unref(OBJECT(dev));
782 783
}

L
Luiz Capitulino 已提交
784
void qmp_device_del(const char *id, Error **errp)
785
{
786 787 788
    Object *obj;
    char *root_path = object_get_canonical_path(qdev_get_peripheral());
    char *path = g_strdup_printf("%s/%s", root_path, id);
789

790 791 792 793 794
    g_free(root_path);
    obj = object_resolve_path_type(path, TYPE_DEVICE, NULL);
    g_free(path);

    if (!obj) {
795 796
        error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
                  "Device '%s' not found", id);
L
Luiz Capitulino 已提交
797
        return;
798 799
    }

800
    qdev_unplug(DEVICE(obj), errp);
801 802 803 804 805 806 807
}

void qdev_machine_init(void)
{
    qdev_get_peripheral_anon();
    qdev_get_peripheral();
}
808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846

QemuOptsList qemu_device_opts = {
    .name = "device",
    .implied_opt_name = "driver",
    .head = QTAILQ_HEAD_INITIALIZER(qemu_device_opts.head),
    .desc = {
        /*
         * no elements => accept any
         * sanity checking will happen later
         * when setting device properties
         */
        { /* end of list */ }
    },
};

QemuOptsList qemu_global_opts = {
    .name = "global",
    .head = QTAILQ_HEAD_INITIALIZER(qemu_global_opts.head),
    .desc = {
        {
            .name = "driver",
            .type = QEMU_OPT_STRING,
        },{
            .name = "property",
            .type = QEMU_OPT_STRING,
        },{
            .name = "value",
            .type = QEMU_OPT_STRING,
        },
        { /* end of list */ }
    },
};

int qemu_global_option(const char *str)
{
    char driver[64], property[64];
    QemuOpts *opts;
    int rc, offset;

847 848 849 850 851 852 853 854 855
    rc = sscanf(str, "%63[^.=].%63[^=]%n", driver, property, &offset);
    if (rc == 2 && str[offset] == '=') {
        opts = qemu_opts_create(&qemu_global_opts, NULL, 0, &error_abort);
        qemu_opt_set(opts, "driver", driver, &error_abort);
        qemu_opt_set(opts, "property", property, &error_abort);
        qemu_opt_set(opts, "value", str + offset + 1, &error_abort);
        return 0;
    }

856
    opts = qemu_opts_parse_noisily(&qemu_global_opts, str, false);
857
    if (!opts) {
858 859 860 861 862
        return -1;
    }

    return 0;
}