*/
#include "qdev.h"
-#include "monitor.h"
+#include "monitor/monitor.h"
#include "qmp-commands.h"
+#include "sysemu/arch_init.h"
+#include "qemu/config-file.h"
/*
* Aliases were a bad idea from the start. Let's keep them
{
const char *typename;
const char *alias;
+ uint32_t arch_mask;
} QDevAlias;
static const QDevAlias qdev_alias_table[] = {
- { "virtio-blk-pci", "virtio-blk" },
- { "virtio-net-pci", "virtio-net" },
- { "virtio-serial-pci", "virtio-serial" },
- { "virtio-balloon-pci", "virtio-balloon" },
- { "virtio-blk-s390", "virtio-blk" },
- { "virtio-net-s390", "virtio-net" },
- { "virtio-serial-s390", "virtio-serial" },
+ { "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 },
+ { "virtio-blk-s390", "virtio-blk", QEMU_ARCH_S390X },
+ { "virtio-net-s390", "virtio-net", QEMU_ARCH_S390X },
+ { "virtio-serial-s390", "virtio-serial", QEMU_ARCH_S390X },
{ "lsi53c895a", "lsi" },
{ "ich9-ahci", "ahci" },
+ { "kvm-pci-assign", "pci-assign" },
{ }
};
int i;
for (i = 0; qdev_alias_table[i].typename; i++) {
+ if (qdev_alias_table[i].arch_mask &&
+ !(qdev_alias_table[i].arch_mask & arch_type)) {
+ continue;
+ }
+
if (strcmp(qdev_alias_table[i].typename, typename) == 0) {
return qdev_alias_table[i].alias;
}
}
error_printf("name \"%s\"", object_class_get_name(klass));
- if (dc->bus_info) {
- error_printf(", bus %s", dc->bus_info->name);
+ if (dc->bus_type) {
+ error_printf(", bus %s", dc->bus_type);
}
if (qdev_class_has_alias(dc)) {
error_printf(", alias \"%s\"", qdev_class_get_alias(dc));
int i;
for (i = 0; qdev_alias_table[i].alias; i++) {
+ if (qdev_alias_table[i].arch_mask &&
+ !(qdev_alias_table[i].arch_mask & arch_type)) {
+ continue;
+ }
+
if (strcmp(qdev_alias_table[i].alias, alias) == 0) {
return qdev_alias_table[i].typename;
}
const char *driver;
Property *prop;
ObjectClass *klass;
- DeviceClass *info;
driver = qemu_opt_get(opts, "driver");
- if (driver && !strcmp(driver, "?")) {
+ if (driver && is_help_option(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, "?")) {
+ if (!driver || !qemu_opt_has_help_opt(opts)) {
return 0;
}
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->set) {
- 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);
- }
- if (info->bus_info) {
- for (prop = info->bus_info->props; prop && prop->name; prop++) {
+ do {
+ for (prop = DEVICE_CLASS(klass)->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->set) {
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);
}
- }
+ klass = object_class_get_parent(klass);
+ } while (klass != object_class_by_name(TYPE_DEVICE));
return 1;
}
static void qbus_list_dev(BusState *bus)
{
- DeviceState *dev;
+ BusChild *kid;
const char *sep = " ";
error_printf("devices at \"%s\":", bus->name);
- QTAILQ_FOREACH(dev, &bus->children, sibling) {
+ QTAILQ_FOREACH(kid, &bus->children, sibling) {
+ DeviceState *dev = kid->child;
error_printf("%s\"%s\"", sep, object_get_typename(OBJECT(dev)));
if (dev->id)
error_printf("/\"%s\"", dev->id);
static DeviceState *qbus_find_dev(BusState *bus, char *elem)
{
- DeviceState *dev;
+ BusChild *kid;
/*
* try to match in order:
* (2) driver name
* (3) driver alias, if present
*/
- QTAILQ_FOREACH(dev, &bus->children, sibling) {
+ QTAILQ_FOREACH(kid, &bus->children, sibling) {
+ DeviceState *dev = kid->child;
if (dev->id && strcmp(dev->id, elem) == 0) {
return dev;
}
}
- QTAILQ_FOREACH(dev, &bus->children, sibling) {
+ QTAILQ_FOREACH(kid, &bus->children, sibling) {
+ DeviceState *dev = kid->child;
if (strcmp(object_get_typename(OBJECT(dev)), elem) == 0) {
return dev;
}
}
- QTAILQ_FOREACH(dev, &bus->children, sibling) {
+ QTAILQ_FOREACH(kid, &bus->children, sibling) {
+ DeviceState *dev = kid->child;
DeviceClass *dc = DEVICE_GET_CLASS(dev);
if (qdev_class_has_alias(dc) &&
}
static BusState *qbus_find_recursive(BusState *bus, const char *name,
- const BusInfo *info)
+ const char *bus_typename)
{
- DeviceState *dev;
+ BusClass *bus_class = BUS_GET_CLASS(bus);
+ BusChild *kid;
BusState *child, *ret;
int match = 1;
if (name && (strcmp(bus->name, name) != 0)) {
match = 0;
}
- if (info && (bus->info != info)) {
+ if (bus_typename && !object_dynamic_cast(OBJECT(bus), bus_typename)) {
match = 0;
}
+ if ((bus_class->max_dev != 0) && (bus_class->max_dev <= bus->max_index)) {
+ if (name != NULL) {
+ /* bus was explicitly specified: return an error. */
+ qerror_report(ERROR_CLASS_GENERIC_ERROR, "Bus '%s' is full",
+ bus->name);
+ return NULL;
+ } else {
+ /* bus was not specified: try to find another one. */
+ match = 0;
+ }
+ }
if (match) {
return bus;
}
- QTAILQ_FOREACH(dev, &bus->children, sibling) {
+ QTAILQ_FOREACH(kid, &bus->children, sibling) {
+ DeviceState *dev = kid->child;
QLIST_FOREACH(child, &dev->child_bus, sibling) {
- ret = qbus_find_recursive(child, name, info);
+ ret = qbus_find_recursive(child, name, bus_typename);
if (ret) {
return ret;
}
if (!bus) {
return NULL;
}
- if (bus->info != k->bus_info) {
+ if (!object_dynamic_cast(OBJECT(bus), k->bus_type)) {
qerror_report(QERR_BAD_BUS_FOR_DEVICE,
- driver, bus->info->name);
+ driver, object_get_typename(OBJECT(bus)));
return NULL;
}
} else {
- bus = qbus_find_recursive(sysbus_get_default(), NULL, k->bus_info);
+ bus = qbus_find_recursive(sysbus_get_default(), NULL, k->bus_type);
if (!bus) {
qerror_report(QERR_NO_BUS_FOR_DEVICE,
- driver, k->bus_info->name);
+ k->bus_type, driver);
return NULL;
}
}
/* 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) {
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)
+ int indent)
{
if (!props)
return;
if (object_property_get_type(OBJECT(dev), legacy_name, NULL)) {
value = object_property_get_str(OBJECT(dev), legacy_name, &err);
} else {
- value = object_property_get_str(OBJECT(dev), props->name, &err);
+ value = object_property_print(OBJECT(dev), props->name, &err);
}
g_free(legacy_name);
error_free(err);
continue;
}
- qdev_printf("%s-prop: %s = %s\n", prefix, props->name,
+ qdev_printf("%s = %s\n", props->name,
value && *value ? value : "<null>");
g_free(value);
}
}
+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);
+ }
+}
+
static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
{
+ ObjectClass *class;
BusState *child;
qdev_printf("dev: %s, id \"%s\"\n", object_get_typename(OBJECT(dev)),
dev->id ? dev->id : "");
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);
+ 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));
+ bus_print_dev(dev->parent_bus, 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;
+ BusChild *kid;
qdev_printf("bus: %s\n", bus->name);
indent += 2;
- qdev_printf("type %s\n", bus->info->name);
- QTAILQ_FOREACH(dev, &bus->children, sibling) {
+ qdev_printf("type %s\n", object_get_typename(OBJECT(bus)));
+ QTAILQ_FOREACH(kid, &bus->children, sibling) {
+ DeviceState *dev = kid->child;
qdev_print(mon, dev, indent);
}
}
#undef qdev_printf
-void do_info_qtree(Monitor *mon)
+void do_info_qtree(Monitor *mon, const QDict *qdict)
{
if (sysbus_get_default())
qbus_print(mon, sysbus_get_default(), 0);
}
-void do_info_qdm(Monitor *mon)
+void do_info_qdm(Monitor *mon, const QDict *qdict)
{
object_class_foreach(qdev_print_devinfo, TYPE_DEVICE, false, NULL);
}
int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data)
{
+ Error *local_err = NULL;
QemuOpts *opts;
+ DeviceState *dev;
- opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict);
- if (!opts) {
+ opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict, &local_err);
+ if (error_is_set(&local_err)) {
+ qerror_report_err(local_err);
+ error_free(local_err);
return -1;
}
if (!monitor_cur_is_qmp() && qdev_device_help(opts)) {
qemu_opts_del(opts);
return 0;
}
- if (!qdev_device_add(opts)) {
+ dev = qdev_device_add(opts);
+ if (!dev) {
qemu_opts_del(opts);
return -1;
}
+ object_unref(OBJECT(dev));
return 0;
}
qdev_get_peripheral_anon();
qdev_get_peripheral();
}
+
+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;
+
+ rc = sscanf(str, "%63[^.].%63[^=]%n", driver, property, &offset);
+ if (rc < 2 || str[offset] != '=') {
+ error_report("can't parse: \"%s\"", str);
+ return -1;
+ }
+
+ opts = qemu_opts_create_nofail(&qemu_global_opts);
+ qemu_opt_set(opts, "driver", driver);
+ qemu_opt_set(opts, "property", property);
+ qemu_opt_set(opts, "value", str+offset+1);
+ return 0;
+}