From patchwork Mon Jan 30 21:08:53 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anthony Liguori X-Patchwork-Id: 138647 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [140.186.70.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 1627B1007D4 for ; Tue, 31 Jan 2012 08:35:19 +1100 (EST) Received: from localhost ([::1]:48351 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Rrysf-0001hO-3h for incoming@patchwork.ozlabs.org; Mon, 30 Jan 2012 16:35:17 -0500 Received: from eggs.gnu.org ([140.186.70.92]:41759) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RryTo-0002F3-NK for qemu-devel@nongnu.org; Mon, 30 Jan 2012 16:09:39 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1RryTk-00055W-KL for qemu-devel@nongnu.org; Mon, 30 Jan 2012 16:09:36 -0500 Received: from cpe-70-123-132-139.austin.res.rr.com ([70.123.132.139]:34353 helo=localhost6.localdomain6) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RryTk-00055O-2N for qemu-devel@nongnu.org; Mon, 30 Jan 2012 16:09:32 -0500 Received: from localhost6.localdomain6 (localhost.localdomain [127.0.0.1]) by localhost6.localdomain6 (8.14.4/8.14.4/Debian-2ubuntu1) with ESMTP id q0UL9TYr006068; Mon, 30 Jan 2012 15:09:29 -0600 Received: (from anthony@localhost) by localhost6.localdomain6 (8.14.4/8.14.4/Submit) id q0UL9Shr006066; Mon, 30 Jan 2012 15:09:28 -0600 From: Anthony Liguori To: qemu-devel@nongnu.org Date: Mon, 30 Jan 2012 15:08:53 -0600 Message-Id: <1327957741-5842-15-git-send-email-aliguori@us.ibm.com> X-Mailer: git-send-email 1.7.4.1 In-Reply-To: <1327957741-5842-1-git-send-email-aliguori@us.ibm.com> References: <1327957741-5842-1-git-send-email-aliguori@us.ibm.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 70.123.132.139 Cc: Paolo Bonzini , Andreas Faerber , Anthony Liguori , Peter Maydell Subject: [Qemu-devel] [PATCH 15/23] qdev: split out UI portions into a new function X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org qdev-monitor.c deals with the -device, device_add, and info qdm/qtree interfaces. Signed-off-by: Anthony Liguori --- Makefile.objs | 2 +- hw/qdev-monitor.c | 587 +++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/qdev.c | 574 +--------------------------------------------------- hw/qdev.h | 2 + 4 files changed, 591 insertions(+), 574 deletions(-) create mode 100644 hw/qdev-monitor.c diff --git a/Makefile.objs b/Makefile.objs index b942625..1a26349 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -113,7 +113,7 @@ common-obj-y += bt-hci-csr.o common-obj-y += buffered_file.o migration.o migration-tcp.o common-obj-y += qemu-char.o #aio.o common-obj-y += msmouse.o ps2.o -common-obj-y += qdev.o qdev-properties.o +common-obj-y += qdev.o qdev-properties.o qdev-monitor.o common-obj-y += block-migration.o iohandler.o common-obj-y += pflib.o common-obj-y += bitmap.o bitops.o diff --git a/hw/qdev-monitor.c b/hw/qdev-monitor.c new file mode 100644 index 0000000..3894574 --- /dev/null +++ b/hw/qdev-monitor.c @@ -0,0 +1,587 @@ +/* + * 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 . + */ + +#include "qdev.h" +#include "monitor.h" + +/* + * Aliases were a bad idea from the start. Let's keep them + * from spreading further. + */ +static const char *qdev_class_get_alias(DeviceClass *dc) +{ + const char *typename = object_class_get_name(OBJECT_CLASS(dc)); + + if (strcmp(typename, "virtio-blk-pci") == 0) { + return "virtio-blk"; + } else if (strcmp(typename, "virtio-net-pci") == 0) { + return "virtio-net"; + } else if (strcmp(typename, "virtio-serial-pci") == 0) { + return "virtio-serial"; + } else if (strcmp(typename, "virtio-balloon-pci") == 0) { + return "virtio-balloon"; + } else if (strcmp(typename, "virtio-blk-s390") == 0) { + return "virtio-blk"; + } else if (strcmp(typename, "virtio-net-s390") == 0) { + return "virtio-net"; + } else if (strcmp(typename, "virtio-serial-s390") == 0) { + return "virtio-serial"; + } else if (strcmp(typename, "lsi53c895a") == 0) { + return "lsi"; + } else if (strcmp(typename, "ich9-ahci") == 0) { + return "ahci"; + } + + return NULL; +} + +static bool qdev_class_has_alias(DeviceClass *dc) +{ + return (qdev_class_get_alias(dc) != NULL); +} + +static void qdev_print_devinfo(ObjectClass *klass, void *opaque) +{ + DeviceClass *dc; + bool *show_no_user = opaque; + + dc = (DeviceClass *)object_class_dynamic_cast(klass, TYPE_DEVICE); + + if (!dc || (show_no_user && !*show_no_user && dc->no_user)) { + return; + } + + error_printf("name \"%s\"", object_class_get_name(klass)); + if (dc->bus_info) { + error_printf(", bus %s", dc->bus_info->name); + } + if (qdev_class_has_alias(dc)) { + error_printf(", alias \"%s\"", qdev_class_get_alias(dc)); + } + if (dc->desc) { + error_printf(", desc \"%s\"", dc->desc); + } + if (dc->no_user) { + error_printf(", no-user"); + } + error_printf("\n"); +} + +static int set_property(const char *name, const char *value, void *opaque) +{ + DeviceState *dev = opaque; + + if (strcmp(name, "driver") == 0) + return 0; + if (strcmp(name, "bus") == 0) + return 0; + + if (qdev_prop_parse(dev, name, value) == -1) { + return -1; + } + return 0; +} + +static const char *find_typename_by_alias(const char *alias) +{ + /* I don't think s390 aliasing could have ever worked... */ + + if (strcmp(alias, "virtio-blk") == 0) { + return "virtio-blk-pci"; + } else if (strcmp(alias, "virtio-net") == 0) { + return "virtio-net-pci"; + } else if (strcmp(alias, "virtio-serial") == 0) { + return "virtio-serial-pci"; + } else if (strcmp(alias, "virtio-balloon") == 0) { + return "virtio-balloon-pci"; + } else if (strcmp(alias, "lsi") == 0) { + return "lsi53c895a"; + } else if (strcmp(alias, "ahci") == 0) { + return "ich9-ahci"; + } + + return NULL; +} + +int qdev_device_help(QemuOpts *opts) +{ + const char *driver; + Property *prop; + ObjectClass *klass; + DeviceClass *info; + + driver = qemu_opt_get(opts, "driver"); + if (driver && !strcmp(driver, "?")) { + bool show_no_user = false; + object_class_foreach(qdev_print_devinfo, TYPE_DEVICE, false, &show_no_user); + return 1; + } + + if (!driver || !qemu_opt_get(opts, "?")) { + return 0; + } + + klass = object_class_by_name(driver); + if (!klass) { + const char *typename = find_typename_by_alias(driver); + + if (typename) { + driver = typename; + klass = object_class_by_name(driver); + } + } + + if (!klass) { + return 0; + } + info = DEVICE_CLASS(klass); + + for (prop = info->props; prop && prop->name; prop++) { + /* + * 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->parse) { + continue; /* no way to set it, don't show */ + } + error_printf("%s.%s=%s\n", driver, prop->name, + prop->info->legacy_name ?: prop->info->name); + } + for (prop = info->bus_info->props; prop && prop->name; prop++) { + if (!prop->info->parse) { + continue; /* no way to set it, don't show */ + } + error_printf("%s.%s=%s\n", driver, prop->name, + prop->info->legacy_name ?: prop->info->name); + } + return 1; +} + +static DeviceState *qdev_get_peripheral(void) +{ + static DeviceState *dev; + + if (dev == NULL) { + dev = qdev_create(NULL, "container"); + qdev_property_add_child(qdev_get_root(), "peripheral", dev, NULL); + qdev_init_nofail(dev); + } + + return dev; +} + +static DeviceState *qdev_get_peripheral_anon(void) +{ + static DeviceState *dev; + + if (dev == NULL) { + dev = qdev_create(NULL, "container"); + qdev_property_add_child(qdev_get_root(), "peripheral-anon", dev, NULL); + qdev_init_nofail(dev); + } + + return dev; +} + +static void qbus_list_bus(DeviceState *dev) +{ + BusState *child; + const char *sep = " "; + + error_printf("child busses at \"%s\":", + 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) +{ + DeviceState *dev; + const char *sep = " "; + + error_printf("devices at \"%s\":", bus->name); + QTAILQ_FOREACH(dev, &bus->children, sibling) { + error_printf("%s\"%s\"", sep, object_get_typename(OBJECT(dev))); + if (dev->id) + error_printf("/\"%s\"", dev->id); + sep = ", "; + } + error_printf("\n"); +} + +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) +{ + DeviceState *dev; + + /* + * try to match in order: + * (1) instance id, if present + * (2) driver name + * (3) driver alias, if present + */ + QTAILQ_FOREACH(dev, &bus->children, sibling) { + if (dev->id && strcmp(dev->id, elem) == 0) { + return dev; + } + } + QTAILQ_FOREACH(dev, &bus->children, sibling) { + if (strcmp(object_get_typename(OBJECT(dev)), elem) == 0) { + return dev; + } + } + QTAILQ_FOREACH(dev, &bus->children, sibling) { + DeviceClass *dc = DEVICE_GET_CLASS(dev); + + if (qdev_class_has_alias(dc) && + strcmp(qdev_class_get_alias(dc), elem) == 0) { + return dev; + } + } + return NULL; +} + +static BusState *qbus_find_recursive(BusState *bus, const char *name, + const BusInfo *info) +{ + DeviceState *dev; + BusState *child, *ret; + int match = 1; + + if (name && (strcmp(bus->name, name) != 0)) { + match = 0; + } + if (info && (bus->info != info)) { + match = 0; + } + if (match) { + return bus; + } + + QTAILQ_FOREACH(dev, &bus->children, sibling) { + QLIST_FOREACH(child, &dev->child_bus, sibling) { + ret = qbus_find_recursive(child, name, info); + if (ret) { + return ret; + } + } + } + return NULL; +} + +static BusState *qbus_find(const char *path) +{ + 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) { + qerror_report(QERR_BUS_NOT_FOUND, elem); + return NULL; + } + pos = len; + } + + for (;;) { + assert(path[pos] == '/' || !path[pos]); + while (path[pos] == '/') { + pos++; + } + if (path[pos] == '\0') { + return bus; + } + + /* find device */ + if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) { + assert(0); + elem[0] = len = 0; + } + pos += len; + dev = qbus_find_dev(bus, elem); + if (!dev) { + qerror_report(QERR_DEVICE_NOT_FOUND, elem); + if (!monitor_cur_is_qmp()) { + qbus_list_dev(bus); + } + 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 */ + switch (dev->num_child_bus) { + case 0: + qerror_report(QERR_DEVICE_NO_BUS, elem); + return NULL; + case 1: + return QLIST_FIRST(&dev->child_bus); + default: + qerror_report(QERR_DEVICE_MULTIPLE_BUSSES, elem); + if (!monitor_cur_is_qmp()) { + qbus_list_bus(dev); + } + return NULL; + } + } + + /* find bus */ + if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) { + assert(0); + elem[0] = len = 0; + } + pos += len; + bus = qbus_find_bus(dev, elem); + if (!bus) { + qerror_report(QERR_BUS_NOT_FOUND, elem); + if (!monitor_cur_is_qmp()) { + qbus_list_bus(dev); + } + return NULL; + } + } +} + +DeviceState *qdev_device_add(QemuOpts *opts) +{ + ObjectClass *obj; + DeviceClass *k; + const char *driver, *path, *id; + DeviceState *qdev; + BusState *bus; + + driver = qemu_opt_get(opts, "driver"); + if (!driver) { + qerror_report(QERR_MISSING_PARAMETER, "driver"); + return NULL; + } + + /* find driver */ + obj = object_class_by_name(driver); + if (!obj) { + const char *typename = find_typename_by_alias(driver); + + if (typename) { + driver = typename; + obj = object_class_by_name(driver); + } + } + + if (!obj) { + qerror_report(QERR_INVALID_PARAMETER_VALUE, "driver", "device type"); + return NULL; + } + + k = DEVICE_CLASS(obj); + + /* find bus */ + path = qemu_opt_get(opts, "bus"); + if (path != NULL) { + bus = qbus_find(path); + if (!bus) { + return NULL; + } + if (bus->info != k->bus_info) { + qerror_report(QERR_BAD_BUS_FOR_DEVICE, + driver, bus->info->name); + return NULL; + } + } else { + bus = qbus_find_recursive(sysbus_get_default(), NULL, k->bus_info); + if (!bus) { + qerror_report(QERR_NO_BUS_FOR_DEVICE, + driver, k->bus_info->name); + return NULL; + } + } + if (qdev_hotplug && !bus->allow_hotplug) { + qerror_report(QERR_BUS_NO_HOTPLUG, bus->name); + return NULL; + } + + if (!bus) { + bus = sysbus_get_default(); + } + + /* create device, set properties */ + qdev = DEVICE(object_new(driver)); + qdev_set_parent_bus(qdev, bus); + qdev_prop_set_globals(qdev); + + id = qemu_opts_id(opts); + if (id) { + qdev->id = id; + qdev_property_add_child(qdev_get_peripheral(), qdev->id, qdev, NULL); + } else { + static int anon_count; + gchar *name = g_strdup_printf("device[%d]", anon_count++); + qdev_property_add_child(qdev_get_peripheral_anon(), name, + qdev, NULL); + g_free(name); + } + if (qemu_opt_foreach(opts, set_property, qdev, 1) != 0) { + qdev_free(qdev); + return NULL; + } + if (qdev_init(qdev) < 0) { + qerror_report(QERR_DEVICE_INIT_FAILED, driver); + return NULL; + } + qdev->opts = opts; + return qdev; +} + + +#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, + const char *prefix, int indent) +{ + char buf[64]; + + if (!props) + return; + while (props->name) { + /* + * TODO Properties without a print method are just for dirty + * hacks. qdev_prop_ptr is the only such PropertyInfo. It's + * marked for removal. The test props->info->print should be + * removed along with it. + */ + if (props->info->print) { + props->info->print(dev, props, buf, sizeof(buf)); + qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf); + } + props++; + } +} + +static void qdev_print(Monitor *mon, DeviceState *dev, int indent) +{ + BusState *child; + qdev_printf("dev: %s, id \"%s\"\n", object_get_typename(OBJECT(dev)), + dev->id ? dev->id : ""); + indent += 2; + if (dev->num_gpio_in) { + qdev_printf("gpio-in %d\n", dev->num_gpio_in); + } + if (dev->num_gpio_out) { + qdev_printf("gpio-out %d\n", dev->num_gpio_out); + } + qdev_print_props(mon, dev, qdev_get_props(dev), "dev", indent); + qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent); + if (dev->parent_bus->info->print_dev) + dev->parent_bus->info->print_dev(mon, dev, indent); + QLIST_FOREACH(child, &dev->child_bus, sibling) { + qbus_print(mon, child, indent); + } +} + +static void qbus_print(Monitor *mon, BusState *bus, int indent) +{ + struct DeviceState *dev; + + qdev_printf("bus: %s\n", bus->name); + indent += 2; + qdev_printf("type %s\n", bus->info->name); + QTAILQ_FOREACH(dev, &bus->children, sibling) { + qdev_print(mon, dev, indent); + } +} +#undef qdev_printf + +void do_info_qtree(Monitor *mon) +{ + if (sysbus_get_default()) + qbus_print(mon, sysbus_get_default(), 0); +} + +void do_info_qdm(Monitor *mon) +{ + object_class_foreach(qdev_print_devinfo, TYPE_DEVICE, false, NULL); +} + +int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data) +{ + QemuOpts *opts; + + opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict); + if (!opts) { + return -1; + } + if (!monitor_cur_is_qmp() && qdev_device_help(opts)) { + qemu_opts_del(opts); + return 0; + } + if (!qdev_device_add(opts)) { + qemu_opts_del(opts); + return -1; + } + return 0; +} + +int do_device_del(Monitor *mon, const QDict *qdict, QObject **ret_data) +{ + const char *id = qdict_get_str(qdict, "id"); + DeviceState *dev; + + dev = qdev_find_recursive(sysbus_get_default(), id); + if (NULL == dev) { + qerror_report(QERR_DEVICE_NOT_FOUND, id); + return -1; + } + return qdev_unplug(dev); +} + +void qdev_machine_init(void) +{ + qdev_get_peripheral_anon(); + qdev_get_peripheral(); +} diff --git a/hw/qdev.c b/hw/qdev.c index 5c8dc53..e82165d 100644 --- a/hw/qdev.c +++ b/hw/qdev.c @@ -28,9 +28,8 @@ #include "net.h" #include "qdev.h" #include "sysemu.h" -#include "monitor.h" -static int qdev_hotplug = 0; +int qdev_hotplug = 0; static bool qdev_hot_added = false; static bool qdev_hot_removed = false; @@ -38,10 +37,6 @@ static bool qdev_hot_removed = false; static BusState *main_system_bus; static void main_system_bus_create(void); -static BusState *qbus_find_recursive(BusState *bus, const char *name, - const BusInfo *info); -static BusState *qbus_find(const char *path); - /* Register a new device type. */ const VMStateDescription *qdev_get_vmsd(DeviceState *dev) { @@ -61,50 +56,12 @@ Property *qdev_get_props(DeviceState *dev) return dc->props; } -/* - * Aliases were a bad idea from the start. Let's keep them - * from spreading further. - */ -static const char *qdev_class_get_alias(DeviceClass *dc) -{ - const char *typename = object_class_get_name(OBJECT_CLASS(dc)); - - if (strcmp(typename, "virtio-blk-pci") == 0) { - return "virtio-blk"; - } else if (strcmp(typename, "virtio-net-pci") == 0) { - return "virtio-net"; - } else if (strcmp(typename, "virtio-serial-pci") == 0) { - return "virtio-serial"; - } else if (strcmp(typename, "virtio-balloon-pci") == 0) { - return "virtio-balloon"; - } else if (strcmp(typename, "virtio-blk-s390") == 0) { - return "virtio-blk"; - } else if (strcmp(typename, "virtio-net-s390") == 0) { - return "virtio-net"; - } else if (strcmp(typename, "virtio-serial-s390") == 0) { - return "virtio-serial"; - } else if (strcmp(typename, "lsi53c895a") == 0) { - return "lsi"; - } else if (strcmp(typename, "ich9-ahci") == 0) { - return "ahci"; - } - - return NULL; -} - -static bool qdev_class_has_alias(DeviceClass *dc) -{ - return (qdev_class_get_alias(dc) != NULL); -} - const char *qdev_fw_name(DeviceState *dev) { DeviceClass *dc = DEVICE_GET_CLASS(dev); if (dc->fw_name) { return dc->fw_name; - } else if (qdev_class_has_alias(dc)) { - return qdev_class_get_alias(dc); } return object_get_typename(OBJECT(dev)); @@ -175,240 +132,6 @@ DeviceState *qdev_try_create(BusState *bus, const char *name) return dev; } -static void qdev_print_devinfo(ObjectClass *klass, void *opaque) -{ - DeviceClass *dc; - bool *show_no_user = opaque; - - dc = (DeviceClass *)object_class_dynamic_cast(klass, TYPE_DEVICE); - - if (!dc || (show_no_user && !*show_no_user && dc->no_user)) { - return; - } - - error_printf("name \"%s\"", object_class_get_name(klass)); - if (dc->bus_info) { - error_printf(", bus %s", dc->bus_info->name); - } - if (qdev_class_has_alias(dc)) { - error_printf(", alias \"%s\"", qdev_class_get_alias(dc)); - } - if (dc->desc) { - error_printf(", desc \"%s\"", dc->desc); - } - if (dc->no_user) { - error_printf(", no-user"); - } - error_printf("\n"); -} - -static int set_property(const char *name, const char *value, void *opaque) -{ - DeviceState *dev = opaque; - - if (strcmp(name, "driver") == 0) - return 0; - if (strcmp(name, "bus") == 0) - return 0; - - if (qdev_prop_parse(dev, name, value) == -1) { - return -1; - } - return 0; -} - -static const char *find_typename_by_alias(const char *alias) -{ - /* I don't think s390 aliasing could have ever worked... */ - - if (strcmp(alias, "virtio-blk") == 0) { - return "virtio-blk-pci"; - } else if (strcmp(alias, "virtio-net") == 0) { - return "virtio-net-pci"; - } else if (strcmp(alias, "virtio-serial") == 0) { - return "virtio-serial-pci"; - } else if (strcmp(alias, "virtio-balloon") == 0) { - return "virtio-balloon-pci"; - } else if (strcmp(alias, "lsi") == 0) { - return "lsi53c895a"; - } else if (strcmp(alias, "ahci") == 0) { - return "ich9-ahci"; - } - - return NULL; -} - -int qdev_device_help(QemuOpts *opts) -{ - const char *driver; - Property *prop; - ObjectClass *klass; - DeviceClass *info; - - driver = qemu_opt_get(opts, "driver"); - if (driver && !strcmp(driver, "?")) { - bool show_no_user = false; - object_class_foreach(qdev_print_devinfo, TYPE_DEVICE, false, &show_no_user); - return 1; - } - - if (!driver || !qemu_opt_get(opts, "?")) { - return 0; - } - - klass = object_class_by_name(driver); - if (!klass) { - const char *typename = find_typename_by_alias(driver); - - if (typename) { - driver = typename; - klass = object_class_by_name(driver); - } - } - - if (!klass) { - return 0; - } - info = DEVICE_CLASS(klass); - - for (prop = info->props; prop && prop->name; prop++) { - /* - * 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->parse) { - continue; /* no way to set it, don't show */ - } - error_printf("%s.%s=%s\n", driver, prop->name, - prop->info->legacy_name ?: prop->info->name); - } - for (prop = info->bus_info->props; prop && prop->name; prop++) { - if (!prop->info->parse) { - continue; /* no way to set it, don't show */ - } - error_printf("%s.%s=%s\n", driver, prop->name, - prop->info->legacy_name ?: prop->info->name); - } - return 1; -} - -static DeviceState *qdev_get_peripheral(void) -{ - static DeviceState *dev; - - if (dev == NULL) { - dev = qdev_create(NULL, "container"); - qdev_property_add_child(qdev_get_root(), "peripheral", dev, NULL); - qdev_init_nofail(dev); - } - - return dev; -} - -static DeviceState *qdev_get_peripheral_anon(void) -{ - static DeviceState *dev; - - if (dev == NULL) { - dev = qdev_create(NULL, "container"); - qdev_property_add_child(qdev_get_root(), "peripheral-anon", dev, NULL); - qdev_init_nofail(dev); - } - - return dev; -} - -DeviceState *qdev_device_add(QemuOpts *opts) -{ - ObjectClass *obj; - DeviceClass *k; - const char *driver, *path, *id; - DeviceState *qdev; - BusState *bus; - - driver = qemu_opt_get(opts, "driver"); - if (!driver) { - qerror_report(QERR_MISSING_PARAMETER, "driver"); - return NULL; - } - - /* find driver */ - obj = object_class_by_name(driver); - if (!obj) { - const char *typename = find_typename_by_alias(driver); - - if (typename) { - driver = typename; - obj = object_class_by_name(driver); - } - } - - if (!obj) { - qerror_report(QERR_INVALID_PARAMETER_VALUE, "driver", "device type"); - return NULL; - } - - k = DEVICE_CLASS(obj); - - /* find bus */ - path = qemu_opt_get(opts, "bus"); - if (path != NULL) { - bus = qbus_find(path); - if (!bus) { - return NULL; - } - if (bus->info != k->bus_info) { - qerror_report(QERR_BAD_BUS_FOR_DEVICE, - driver, bus->info->name); - return NULL; - } - } else { - bus = qbus_find_recursive(main_system_bus, NULL, k->bus_info); - if (!bus) { - qerror_report(QERR_NO_BUS_FOR_DEVICE, - driver, k->bus_info->name); - return NULL; - } - } - if (qdev_hotplug && !bus->allow_hotplug) { - qerror_report(QERR_BUS_NO_HOTPLUG, bus->name); - return NULL; - } - - if (!bus) { - bus = sysbus_get_default(); - } - - /* create device, set properties */ - qdev = DEVICE(object_new(driver)); - qdev_set_parent_bus(qdev, bus); - qdev_prop_set_globals(qdev); - - id = qemu_opts_id(opts); - if (id) { - qdev->id = id; - qdev_property_add_child(qdev_get_peripheral(), qdev->id, qdev, NULL); - } else { - static int anon_count; - gchar *name = g_strdup_printf("device[%d]", anon_count++); - qdev_property_add_child(qdev_get_peripheral_anon(), name, - qdev, NULL); - g_free(name); - } - if (qemu_opt_foreach(opts, set_property, qdev, 1) != 0) { - qdev_free(qdev); - return NULL; - } - if (qdev_init(qdev) < 0) { - qerror_report(QERR_DEVICE_INIT_FAILED, driver); - return NULL; - } - qdev->opts = opts; - return qdev; -} - /* Initialize a device. Device properties should be set before calling this function. IRQs and MMIO regions should be connected/mapped after calling this function. @@ -725,34 +448,6 @@ int qdev_walk_children(DeviceState *dev, qdev_walkerfn *devfn, return 0; } -static BusState *qbus_find_recursive(BusState *bus, const char *name, - const BusInfo *info) -{ - DeviceState *dev; - BusState *child, *ret; - int match = 1; - - if (name && (strcmp(bus->name, name) != 0)) { - match = 0; - } - if (info && (bus->info != info)) { - match = 0; - } - if (match) { - return bus; - } - - QTAILQ_FOREACH(dev, &bus->children, sibling) { - QLIST_FOREACH(child, &dev->child_bus, sibling) { - ret = qbus_find_recursive(child, name, info); - if (ret) { - return ret; - } - } - } - return NULL; -} - DeviceState *qdev_find_recursive(BusState *bus, const char *id) { DeviceState *dev, *ret; @@ -771,165 +466,6 @@ DeviceState *qdev_find_recursive(BusState *bus, const char *id) return NULL; } -static void qbus_list_bus(DeviceState *dev) -{ - BusState *child; - const char *sep = " "; - - error_printf("child busses at \"%s\":", - 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) -{ - DeviceState *dev; - const char *sep = " "; - - error_printf("devices at \"%s\":", bus->name); - QTAILQ_FOREACH(dev, &bus->children, sibling) { - error_printf("%s\"%s\"", sep, object_get_typename(OBJECT(dev))); - if (dev->id) - error_printf("/\"%s\"", dev->id); - sep = ", "; - } - error_printf("\n"); -} - -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) -{ - DeviceState *dev; - - /* - * try to match in order: - * (1) instance id, if present - * (2) driver name - * (3) driver alias, if present - */ - QTAILQ_FOREACH(dev, &bus->children, sibling) { - if (dev->id && strcmp(dev->id, elem) == 0) { - return dev; - } - } - QTAILQ_FOREACH(dev, &bus->children, sibling) { - if (strcmp(object_get_typename(OBJECT(dev)), elem) == 0) { - return dev; - } - } - QTAILQ_FOREACH(dev, &bus->children, sibling) { - DeviceClass *dc = DEVICE_GET_CLASS(dev); - - if (qdev_class_has_alias(dc) && - strcmp(qdev_class_get_alias(dc), elem) == 0) { - return dev; - } - } - return NULL; -} - -static BusState *qbus_find(const char *path) -{ - DeviceState *dev; - BusState *bus; - char elem[128]; - int pos, len; - - /* find start element */ - if (path[0] == '/') { - bus = main_system_bus; - pos = 0; - } else { - if (sscanf(path, "%127[^/]%n", elem, &len) != 1) { - assert(!path[0]); - elem[0] = len = 0; - } - bus = qbus_find_recursive(main_system_bus, elem, NULL); - if (!bus) { - qerror_report(QERR_BUS_NOT_FOUND, elem); - return NULL; - } - pos = len; - } - - for (;;) { - assert(path[pos] == '/' || !path[pos]); - while (path[pos] == '/') { - pos++; - } - if (path[pos] == '\0') { - return bus; - } - - /* find device */ - if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) { - assert(0); - elem[0] = len = 0; - } - pos += len; - dev = qbus_find_dev(bus, elem); - if (!dev) { - qerror_report(QERR_DEVICE_NOT_FOUND, elem); - if (!monitor_cur_is_qmp()) { - qbus_list_dev(bus); - } - 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 */ - switch (dev->num_child_bus) { - case 0: - qerror_report(QERR_DEVICE_NO_BUS, elem); - return NULL; - case 1: - return QLIST_FIRST(&dev->child_bus); - default: - qerror_report(QERR_DEVICE_MULTIPLE_BUSSES, elem); - if (!monitor_cur_is_qmp()) { - qbus_list_bus(dev); - } - return NULL; - } - } - - /* find bus */ - if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) { - assert(0); - elem[0] = len = 0; - } - pos += len; - bus = qbus_find_bus(dev, elem); - if (!bus) { - qerror_report(QERR_BUS_NOT_FOUND, elem); - if (!monitor_cur_is_qmp()) { - qbus_list_bus(dev); - } - return NULL; - } - } -} - void qbus_create_inplace(BusState *bus, BusInfo *info, DeviceState *parent, const char *name) { @@ -1010,108 +546,6 @@ void qbus_free(BusState *bus) } } -#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, - const char *prefix, int indent) -{ - char buf[64]; - - if (!props) - return; - while (props->name) { - /* - * TODO Properties without a print method are just for dirty - * hacks. qdev_prop_ptr is the only such PropertyInfo. It's - * marked for removal. The test props->info->print should be - * removed along with it. - */ - if (props->info->print) { - props->info->print(dev, props, buf, sizeof(buf)); - qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf); - } - props++; - } -} - -static void qdev_print(Monitor *mon, DeviceState *dev, int indent) -{ - BusState *child; - qdev_printf("dev: %s, id \"%s\"\n", object_get_typename(OBJECT(dev)), - dev->id ? dev->id : ""); - indent += 2; - if (dev->num_gpio_in) { - qdev_printf("gpio-in %d\n", dev->num_gpio_in); - } - if (dev->num_gpio_out) { - qdev_printf("gpio-out %d\n", dev->num_gpio_out); - } - qdev_print_props(mon, dev, qdev_get_props(dev), "dev", indent); - qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent); - if (dev->parent_bus->info->print_dev) - dev->parent_bus->info->print_dev(mon, dev, indent); - QLIST_FOREACH(child, &dev->child_bus, sibling) { - qbus_print(mon, child, indent); - } -} - -static void qbus_print(Monitor *mon, BusState *bus, int indent) -{ - struct DeviceState *dev; - - qdev_printf("bus: %s\n", bus->name); - indent += 2; - qdev_printf("type %s\n", bus->info->name); - QTAILQ_FOREACH(dev, &bus->children, sibling) { - qdev_print(mon, dev, indent); - } -} -#undef qdev_printf - -void do_info_qtree(Monitor *mon) -{ - if (main_system_bus) - qbus_print(mon, main_system_bus, 0); -} - -void do_info_qdm(Monitor *mon) -{ - object_class_foreach(qdev_print_devinfo, TYPE_DEVICE, false, NULL); -} - -int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data) -{ - QemuOpts *opts; - - opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict); - if (!opts) { - return -1; - } - if (!monitor_cur_is_qmp() && qdev_device_help(opts)) { - qemu_opts_del(opts); - return 0; - } - if (!qdev_device_add(opts)) { - qemu_opts_del(opts); - return -1; - } - return 0; -} - -int do_device_del(Monitor *mon, const QDict *qdict, QObject **ret_data) -{ - const char *id = qdict_get_str(qdict, "id"); - DeviceState *dev; - - dev = qdev_find_recursive(main_system_bus, id); - if (NULL == dev) { - qerror_report(QERR_DEVICE_NOT_FOUND, id); - return -1; - } - return qdev_unplug(dev); -} - static int qdev_get_fw_dev_path_helper(DeviceState *dev, char *p, int size) { int l = 0; @@ -1643,12 +1077,6 @@ void qdev_property_add_str(DeviceState *dev, const char *name, prop, errp); } -void qdev_machine_init(void) -{ - qdev_get_peripheral_anon(); - qdev_get_peripheral(); -} - static void device_initfn(Object *obj) { DeviceState *dev = DEVICE(obj); diff --git a/hw/qdev.h b/hw/qdev.h index e611804..9535e57 100644 --- a/hw/qdev.h +++ b/hw/qdev.h @@ -639,4 +639,6 @@ Property *qdev_get_props(DeviceState *dev); /* FIXME: make this a link<> */ void qdev_set_parent_bus(DeviceState *dev, BusState *bus); +extern int qdev_hotplug; + #endif