2011-12-23 05:24:20 +08:00
|
|
|
/*
|
|
|
|
* 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/>.
|
|
|
|
*/
|
|
|
|
|
2016-01-30 01:50:05 +08:00
|
|
|
#include "qemu/osdep.h"
|
2013-04-16 09:50:21 +08:00
|
|
|
#include "hw/sysbus.h"
|
2019-07-10 02:59:36 +08:00
|
|
|
#include "monitor/hmp.h"
|
2012-12-18 01:19:49 +08:00
|
|
|
#include "monitor/monitor.h"
|
2013-02-04 18:37:52 +08:00
|
|
|
#include "monitor/qdev.h"
|
2012-12-18 01:20:04 +08:00
|
|
|
#include "sysemu/arch_init.h"
|
2018-02-01 19:18:31 +08:00
|
|
|
#include "qapi/error.h"
|
2019-06-20 04:10:37 +08:00
|
|
|
#include "qapi/qapi-commands-qdev.h"
|
2018-02-01 19:18:39 +08:00
|
|
|
#include "qapi/qmp/qdict.h"
|
2015-03-18 00:22:46 +08:00
|
|
|
#include "qapi/qmp/qerror.h"
|
2012-12-18 01:20:00 +08:00
|
|
|
#include "qemu/config-file.h"
|
2015-03-18 01:29:20 +08:00
|
|
|
#include "qemu/error-report.h"
|
2016-03-21 01:16:19 +08:00
|
|
|
#include "qemu/help_option.h"
|
2018-02-01 19:18:46 +08:00
|
|
|
#include "qemu/option.h"
|
2019-04-18 03:06:41 +08:00
|
|
|
#include "qemu/qemu-print.h"
|
2019-10-29 19:48:55 +08:00
|
|
|
#include "qemu/option_int.h"
|
2016-09-20 19:38:42 +08:00
|
|
|
#include "sysemu/block-backend.h"
|
2019-08-12 13:23:56 +08:00
|
|
|
#include "sysemu/sysemu.h"
|
2017-04-25 01:02:44 +08:00
|
|
|
#include "migration/misc.h"
|
2019-10-29 19:48:55 +08:00
|
|
|
#include "migration/migration.h"
|
2020-01-10 23:30:39 +08:00
|
|
|
#include "qemu/cutils.h"
|
2020-04-06 21:52:51 +08:00
|
|
|
#include "hw/clock.h"
|
2011-12-23 05:24:20 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Aliases were a bad idea from the start. Let's keep them
|
|
|
|
* from spreading further.
|
|
|
|
*/
|
|
|
|
typedef struct QDevAlias
|
|
|
|
{
|
|
|
|
const char *typename;
|
|
|
|
const char *alias;
|
2012-05-18 08:36:26 +08:00
|
|
|
uint32_t arch_mask;
|
2011-12-23 05:24:20 +08:00
|
|
|
} QDevAlias;
|
|
|
|
|
2016-02-19 05:44:13 +08:00
|
|
|
/* Please keep this table sorted by typename. */
|
2011-12-23 05:24:20 +08:00
|
|
|
static const QDevAlias qdev_alias_table[] = {
|
2016-02-19 05:44:13 +08:00
|
|
|
{ "e1000", "e1000-82540em" },
|
|
|
|
{ "ich9-ahci", "ahci" },
|
|
|
|
{ "lsi53c895a", "lsi" },
|
2016-02-19 05:44:14 +08:00
|
|
|
{ "virtio-9p-ccw", "virtio-9p", QEMU_ARCH_S390X },
|
|
|
|
{ "virtio-9p-pci", "virtio-9p", QEMU_ARCH_ALL & ~QEMU_ARCH_S390X },
|
|
|
|
{ "virtio-balloon-ccw", "virtio-balloon", QEMU_ARCH_S390X },
|
2012-05-18 08:36:26 +08:00
|
|
|
{ "virtio-balloon-pci", "virtio-balloon",
|
|
|
|
QEMU_ARCH_ALL & ~QEMU_ARCH_S390X },
|
2015-06-17 05:06:33 +08:00
|
|
|
{ "virtio-blk-ccw", "virtio-blk", QEMU_ARCH_S390X },
|
2016-02-19 05:44:13 +08:00
|
|
|
{ "virtio-blk-pci", "virtio-blk", QEMU_ARCH_ALL & ~QEMU_ARCH_S390X },
|
2016-02-19 05:44:14 +08:00
|
|
|
{ "virtio-gpu-ccw", "virtio-gpu", QEMU_ARCH_S390X },
|
|
|
|
{ "virtio-gpu-pci", "virtio-gpu", QEMU_ARCH_ALL & ~QEMU_ARCH_S390X },
|
|
|
|
{ "virtio-input-host-ccw", "virtio-input-host", QEMU_ARCH_S390X },
|
|
|
|
{ "virtio-input-host-pci", "virtio-input-host",
|
|
|
|
QEMU_ARCH_ALL & ~QEMU_ARCH_S390X },
|
2020-02-14 21:27:43 +08:00
|
|
|
{ "virtio-iommu-pci", "virtio-iommu", QEMU_ARCH_ALL & ~QEMU_ARCH_S390X },
|
2016-02-19 05:44:14 +08:00
|
|
|
{ "virtio-keyboard-ccw", "virtio-keyboard", QEMU_ARCH_S390X },
|
|
|
|
{ "virtio-keyboard-pci", "virtio-keyboard",
|
|
|
|
QEMU_ARCH_ALL & ~QEMU_ARCH_S390X },
|
|
|
|
{ "virtio-mouse-ccw", "virtio-mouse", QEMU_ARCH_S390X },
|
|
|
|
{ "virtio-mouse-pci", "virtio-mouse", QEMU_ARCH_ALL & ~QEMU_ARCH_S390X },
|
2015-06-17 05:06:33 +08:00
|
|
|
{ "virtio-net-ccw", "virtio-net", QEMU_ARCH_S390X },
|
2016-02-19 05:44:13 +08:00
|
|
|
{ "virtio-net-pci", "virtio-net", QEMU_ARCH_ALL & ~QEMU_ARCH_S390X },
|
2016-02-19 05:44:14 +08:00
|
|
|
{ "virtio-rng-ccw", "virtio-rng", QEMU_ARCH_S390X },
|
|
|
|
{ "virtio-rng-pci", "virtio-rng", QEMU_ARCH_ALL & ~QEMU_ARCH_S390X },
|
|
|
|
{ "virtio-scsi-ccw", "virtio-scsi", QEMU_ARCH_S390X },
|
|
|
|
{ "virtio-scsi-pci", "virtio-scsi", QEMU_ARCH_ALL & ~QEMU_ARCH_S390X },
|
2015-06-17 05:06:33 +08:00
|
|
|
{ "virtio-serial-ccw", "virtio-serial", QEMU_ARCH_S390X },
|
2016-02-19 05:44:13 +08:00
|
|
|
{ "virtio-serial-pci", "virtio-serial", QEMU_ARCH_ALL & ~QEMU_ARCH_S390X },
|
2016-02-19 05:44:14 +08:00
|
|
|
{ "virtio-tablet-ccw", "virtio-tablet", QEMU_ARCH_S390X },
|
|
|
|
{ "virtio-tablet-pci", "virtio-tablet", QEMU_ARCH_ALL & ~QEMU_ARCH_S390X },
|
2011-12-23 05:24:20 +08:00
|
|
|
{ }
|
|
|
|
};
|
|
|
|
|
|
|
|
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++) {
|
2012-05-18 08:36:26 +08:00
|
|
|
if (qdev_alias_table[i].arch_mask &&
|
|
|
|
!(qdev_alias_table[i].arch_mask & arch_type)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2011-12-23 05:24:20 +08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2013-10-10 21:00:21 +08:00
|
|
|
static void qdev_print_devinfo(DeviceClass *dc)
|
2011-12-23 05:24:20 +08:00
|
|
|
{
|
2019-04-18 03:06:41 +08:00
|
|
|
qemu_printf("name \"%s\"", object_class_get_name(OBJECT_CLASS(dc)));
|
2012-05-02 15:00:20 +08:00
|
|
|
if (dc->bus_type) {
|
2019-04-18 03:06:41 +08:00
|
|
|
qemu_printf(", bus %s", dc->bus_type);
|
2011-12-23 05:24:20 +08:00
|
|
|
}
|
|
|
|
if (qdev_class_has_alias(dc)) {
|
2019-04-18 03:06:41 +08:00
|
|
|
qemu_printf(", alias \"%s\"", qdev_class_get_alias(dc));
|
2011-12-23 05:24:20 +08:00
|
|
|
}
|
|
|
|
if (dc->desc) {
|
2019-04-18 03:06:41 +08:00
|
|
|
qemu_printf(", desc \"%s\"", dc->desc);
|
2011-12-23 05:24:20 +08:00
|
|
|
}
|
2017-05-04 04:35:44 +08:00
|
|
|
if (!dc->user_creatable) {
|
2019-04-18 03:06:41 +08:00
|
|
|
qemu_printf(", no-user");
|
2011-12-23 05:24:20 +08:00
|
|
|
}
|
2019-04-18 03:06:41 +08:00
|
|
|
qemu_printf("\n");
|
2011-12-23 05:24:20 +08:00
|
|
|
}
|
|
|
|
|
2013-10-10 21:00:21 +08:00
|
|
|
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",
|
2017-01-20 21:01:16 +08:00
|
|
|
[DEVICE_CATEGORY_CPU] = "CPU",
|
2013-10-10 21:00:21 +08:00
|
|
|
[DEVICE_CATEGORY_MAX] = "Uncategorized",
|
|
|
|
};
|
|
|
|
GSList *list, *elt;
|
|
|
|
int i;
|
|
|
|
bool cat_printed;
|
|
|
|
|
2018-03-03 15:33:10 +08:00
|
|
|
list = object_class_get_list_sorted(TYPE_DEVICE, false);
|
2013-10-10 21:00:21 +08:00
|
|
|
|
|
|
|
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))
|
qdev: Replace no_user by cannot_instantiate_with_device_add_yet
In an ideal world, machines can be built by wiring devices together
with configuration, not code. Unfortunately, that's not the world we
live in right now. We still have quite a few devices that need to be
wired up by code. If you try to device_add such a device, it'll fail
in sometimes mysterious ways. If you're lucky, you get an
unmysterious immediate crash.
To protect users from such badness, DeviceClass member no_user used to
make device models unavailable with -device / device_add, but that
regressed in commit 18b6dad. The device model is still omitted from
help, but is available anyway.
Attempts to fix the regression have been rejected with the argument
that the purpose of no_user isn't clear, and it's prone to misuse.
This commit clarifies no_user's purpose. Anthony suggested to rename
it cannot_instantiate_with_device_add_yet_due_to_internal_bugs, which
I shorten somewhat to keep checkpatch happy. While there, make it
bool.
Every use of cannot_instantiate_with_device_add_yet gets a FIXME
comment asking for rationale. The next few commits will clean them
all up, either by providing a rationale, or by getting rid of the use.
With that done, the regression fix is hopefully acceptable.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Marcel Apfelbaum <marcel.a@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2013-11-29 00:26:54 +08:00
|
|
|
|| (!show_no_user
|
2017-05-04 04:35:44 +08:00
|
|
|
&& !dc->user_creatable)) {
|
2013-10-10 21:00:21 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!cat_printed) {
|
2019-04-18 03:06:41 +08:00
|
|
|
qemu_printf("%s%s devices:\n", i ? "\n" : "", cat_name[i]);
|
2013-10-10 21:00:21 +08:00
|
|
|
cat_printed = true;
|
|
|
|
}
|
|
|
|
qdev_print_devinfo(dc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
g_slist_free(list);
|
|
|
|
}
|
|
|
|
|
2015-03-12 15:40:25 +08:00
|
|
|
static int set_property(void *opaque, const char *name, const char *value,
|
|
|
|
Error **errp)
|
2011-12-23 05:24:20 +08:00
|
|
|
{
|
2014-02-08 18:01:49 +08:00
|
|
|
Object *obj = opaque;
|
2013-05-01 22:10:24 +08:00
|
|
|
Error *err = NULL;
|
2011-12-23 05:24:20 +08:00
|
|
|
|
|
|
|
if (strcmp(name, "driver") == 0)
|
|
|
|
return 0;
|
|
|
|
if (strcmp(name, "bus") == 0)
|
|
|
|
return 0;
|
|
|
|
|
2014-02-08 18:01:49 +08:00
|
|
|
object_property_parse(obj, value, name, &err);
|
2013-05-01 22:10:24 +08:00
|
|
|
if (err != NULL) {
|
2015-03-12 20:58:02 +08:00
|
|
|
error_propagate(errp, err);
|
2011-12-23 05:24:20 +08:00
|
|
|
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++) {
|
2012-05-18 08:36:26 +08:00
|
|
|
if (qdev_alias_table[i].arch_mask &&
|
|
|
|
!(qdev_alias_table[i].arch_mask & arch_type)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2011-12-23 05:24:20 +08:00
|
|
|
if (strcmp(qdev_alias_table[i].alias, alias) == 0) {
|
|
|
|
return qdev_alias_table[i].typename;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2014-11-01 23:56:09 +08:00
|
|
|
static DeviceClass *qdev_get_device_class(const char **driver, Error **errp)
|
|
|
|
{
|
|
|
|
ObjectClass *oc;
|
|
|
|
DeviceClass *dc;
|
2016-02-19 05:44:12 +08:00
|
|
|
const char *original_name = *driver;
|
2014-11-01 23:56:09 +08:00
|
|
|
|
|
|
|
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)) {
|
2016-02-19 05:44:12 +08:00
|
|
|
if (*driver != original_name) {
|
|
|
|
error_setg(errp, "'%s' (alias '%s') is not a valid device model"
|
|
|
|
" name", original_name, *driver);
|
|
|
|
} else {
|
|
|
|
error_setg(errp, "'%s' is not a valid device model name", *driver);
|
|
|
|
}
|
2014-11-01 23:56:09 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (object_class_is_abstract(oc)) {
|
2015-03-17 18:54:50 +08:00
|
|
|
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "driver",
|
|
|
|
"non-abstract device type");
|
2014-11-01 23:56:09 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
dc = DEVICE_CLASS(oc);
|
2017-05-04 04:35:44 +08:00
|
|
|
if (!dc->user_creatable ||
|
2014-11-01 23:56:09 +08:00
|
|
|
(qdev_hotplug && !dc->hotpluggable)) {
|
2015-03-17 18:54:50 +08:00
|
|
|
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "driver",
|
|
|
|
"pluggable device type");
|
2014-11-01 23:56:09 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return dc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-12-23 05:24:20 +08:00
|
|
|
int qdev_device_help(QemuOpts *opts)
|
|
|
|
{
|
2014-07-09 20:01:32 +08:00
|
|
|
Error *local_err = NULL;
|
2011-12-23 05:24:20 +08:00
|
|
|
const char *driver;
|
2018-03-01 21:09:38 +08:00
|
|
|
ObjectPropertyInfoList *prop_list;
|
|
|
|
ObjectPropertyInfoList *prop;
|
2020-01-10 23:30:39 +08:00
|
|
|
GPtrArray *array;
|
|
|
|
int i;
|
2011-12-23 05:24:20 +08:00
|
|
|
|
|
|
|
driver = qemu_opt_get(opts, "driver");
|
2012-08-02 20:45:54 +08:00
|
|
|
if (driver && is_help_option(driver)) {
|
2013-10-10 21:00:21 +08:00
|
|
|
qdev_print_devinfos(false);
|
2011-12-23 05:24:20 +08:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2012-08-02 20:45:54 +08:00
|
|
|
if (!driver || !qemu_opt_has_help_opt(opts)) {
|
2011-12-23 05:24:20 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
Revert "qdev: Use qdev_get_device_class() for -device <type>,help"
This reverts commit 31bed5509dfcbdfc293154ce81086a4dbd7a80b6.
The reverted commit changed qdev_device_help() to reject abstract
devices and devices that have cannot_instantiate_with_device_add_yet
set, to fix crash bugs like -device x86_64-cpu,help.
Rejecting abstract devices makes sense: they're purely internal, and
the implementation of the help feature can't cope with them.
Rejecting non-pluggable devices makes less sense: even though you
can't use them with -device, the help may still be useful elsewhere,
for instance with -global. This is a regression: -device FOO,help
used to help even for FOO that aren't pluggable.
The previous two commits fixed the crash bug at a lower layer, so
reverting this one is now safe. Fixes the -device FOO,help
regression, except for the broken devices marked
cannot_even_create_with_object_new_yet. For those, the error message
is improved.
Example of a device where the regression is fixed:
$ qemu-system-x86_64 -device PIIX4_PM,help
PIIX4_PM.command_serr_enable=bool (on/off)
PIIX4_PM.multifunction=bool (on/off)
PIIX4_PM.rombar=uint32
PIIX4_PM.romfile=str
PIIX4_PM.addr=int32 (Slot and optional function number, example: 06.0 or 06)
PIIX4_PM.memory-hotplug-support=bool
PIIX4_PM.acpi-pci-hotplug-with-bridge-support=bool
PIIX4_PM.s4_val=uint8
PIIX4_PM.disable_s4=uint8
PIIX4_PM.disable_s3=uint8
PIIX4_PM.smb_io_base=uint32
Example of a device where it isn't fixed:
$ qemu-system-x86_64 -device host-x86_64-cpu,help
Can't list properties of device 'host-x86_64-cpu'
Both failed with "Parameter 'driver' expects pluggable device type"
before.
Cc: qemu-stable@nongnu.org
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Eduardo Habkost <ehabkost@redhat.com>
Message-Id: <1443689999-12182-11-git-send-email-armbru@redhat.com>
2015-10-01 16:59:59 +08:00
|
|
|
if (!object_class_by_name(driver)) {
|
|
|
|
const char *typename = find_typename_by_alias(driver);
|
|
|
|
|
|
|
|
if (typename) {
|
|
|
|
driver = typename;
|
|
|
|
}
|
2011-12-23 05:24:20 +08:00
|
|
|
}
|
|
|
|
|
2014-07-09 20:01:32 +08:00
|
|
|
prop_list = qmp_device_list_properties(driver, &local_err);
|
2014-09-16 10:19:33 +08:00
|
|
|
if (local_err) {
|
2014-11-01 23:56:10 +08:00
|
|
|
goto error;
|
2011-12-23 05:24:20 +08:00
|
|
|
}
|
2014-07-09 20:01:32 +08:00
|
|
|
|
2018-10-20 00:49:27 +08:00
|
|
|
if (prop_list) {
|
2019-04-18 03:06:41 +08:00
|
|
|
qemu_printf("%s options:\n", driver);
|
2018-10-20 00:49:27 +08:00
|
|
|
} else {
|
2019-04-18 03:06:41 +08:00
|
|
|
qemu_printf("There are no options for %s.\n", driver);
|
2018-10-20 00:49:27 +08:00
|
|
|
}
|
2020-01-10 23:30:39 +08:00
|
|
|
array = g_ptr_array_new();
|
2014-07-09 20:01:32 +08:00
|
|
|
for (prop = prop_list; prop; prop = prop->next) {
|
2020-01-10 23:30:39 +08:00
|
|
|
g_ptr_array_add(array,
|
|
|
|
object_property_help(prop->value->name,
|
|
|
|
prop->value->type,
|
|
|
|
prop->value->default_value,
|
|
|
|
prop->value->description));
|
2014-07-09 20:01:32 +08:00
|
|
|
}
|
2020-01-10 23:30:39 +08:00
|
|
|
g_ptr_array_sort(array, (GCompareFunc)qemu_pstrcmp0);
|
|
|
|
for (i = 0; i < array->len; i++) {
|
|
|
|
printf("%s\n", (char *)array->pdata[i]);
|
|
|
|
}
|
|
|
|
g_ptr_array_set_free_func(array, g_free);
|
|
|
|
g_ptr_array_free(array, true);
|
2018-03-01 21:09:38 +08:00
|
|
|
qapi_free_ObjectPropertyInfoList(prop_list);
|
2011-12-23 05:24:20 +08:00
|
|
|
return 1;
|
2014-11-01 23:56:10 +08:00
|
|
|
|
|
|
|
error:
|
2015-12-18 23:35:07 +08:00
|
|
|
error_report_err(local_err);
|
2014-11-01 23:56:10 +08:00
|
|
|
return 1;
|
2011-12-23 05:24:20 +08:00
|
|
|
}
|
|
|
|
|
2012-01-30 22:55:55 +08:00
|
|
|
static Object *qdev_get_peripheral(void)
|
2011-12-23 05:24:20 +08:00
|
|
|
{
|
2011-12-23 23:08:05 +08:00
|
|
|
static Object *dev;
|
2011-12-23 05:24:20 +08:00
|
|
|
|
|
|
|
if (dev == NULL) {
|
2012-04-05 19:21:46 +08:00
|
|
|
dev = container_get(qdev_get_machine(), "/peripheral");
|
2011-12-23 05:24:20 +08:00
|
|
|
}
|
|
|
|
|
2011-12-23 23:08:05 +08:00
|
|
|
return dev;
|
2011-12-23 05:24:20 +08:00
|
|
|
}
|
|
|
|
|
2012-01-30 22:55:55 +08:00
|
|
|
static Object *qdev_get_peripheral_anon(void)
|
2011-12-23 05:24:20 +08:00
|
|
|
{
|
2011-12-23 23:08:05 +08:00
|
|
|
static Object *dev;
|
2011-12-23 05:24:20 +08:00
|
|
|
|
|
|
|
if (dev == NULL) {
|
2012-04-05 19:21:46 +08:00
|
|
|
dev = container_get(qdev_get_machine(), "/peripheral-anon");
|
2011-12-23 05:24:20 +08:00
|
|
|
}
|
|
|
|
|
2011-12-23 23:08:05 +08:00
|
|
|
return dev;
|
2011-12-23 05:24:20 +08:00
|
|
|
}
|
|
|
|
|
2019-12-06 01:46:20 +08:00
|
|
|
static void qbus_error_append_bus_list_hint(DeviceState *dev,
|
|
|
|
Error *const *errp)
|
2011-12-23 05:24:20 +08:00
|
|
|
{
|
|
|
|
BusState *child;
|
|
|
|
const char *sep = " ";
|
|
|
|
|
hmp: Allow for error message hints on HMP
Commits 7216ae3d and d2828429 disabled some error message hints,
all because a change to use modern error reporting meant that the
hint would be output prior to the actual error. Fix this by making
hints a first-class member of Error.
For example, we are now back to the pleasant:
$ qemu-system-x86_64 --nodefaults -S --vnc :0 --chardev null,id=,
qemu-system-x86_64: --chardev null,id=,: Parameter 'id' expects an identifier
Identifiers consist of letters, digits, '-', '.', '_', starting with a letter.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <1441901956-21991-1-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-09-11 00:19:16 +08:00
|
|
|
error_append_hint(errp, "child buses at \"%s\":",
|
|
|
|
dev->id ? dev->id : object_get_typename(OBJECT(dev)));
|
2011-12-23 05:24:20 +08:00
|
|
|
QLIST_FOREACH(child, &dev->child_bus, sibling) {
|
hmp: Allow for error message hints on HMP
Commits 7216ae3d and d2828429 disabled some error message hints,
all because a change to use modern error reporting meant that the
hint would be output prior to the actual error. Fix this by making
hints a first-class member of Error.
For example, we are now back to the pleasant:
$ qemu-system-x86_64 --nodefaults -S --vnc :0 --chardev null,id=,
qemu-system-x86_64: --chardev null,id=,: Parameter 'id' expects an identifier
Identifiers consist of letters, digits, '-', '.', '_', starting with a letter.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <1441901956-21991-1-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-09-11 00:19:16 +08:00
|
|
|
error_append_hint(errp, "%s\"%s\"", sep, child->name);
|
2011-12-23 05:24:20 +08:00
|
|
|
sep = ", ";
|
|
|
|
}
|
2015-12-18 00:35:14 +08:00
|
|
|
error_append_hint(errp, "\n");
|
2011-12-23 05:24:20 +08:00
|
|
|
}
|
|
|
|
|
2019-12-06 01:46:20 +08:00
|
|
|
static void qbus_error_append_dev_list_hint(BusState *bus,
|
|
|
|
Error *const *errp)
|
2011-12-23 05:24:20 +08:00
|
|
|
{
|
2011-12-24 05:34:39 +08:00
|
|
|
BusChild *kid;
|
2011-12-23 05:24:20 +08:00
|
|
|
const char *sep = " ";
|
|
|
|
|
hmp: Allow for error message hints on HMP
Commits 7216ae3d and d2828429 disabled some error message hints,
all because a change to use modern error reporting meant that the
hint would be output prior to the actual error. Fix this by making
hints a first-class member of Error.
For example, we are now back to the pleasant:
$ qemu-system-x86_64 --nodefaults -S --vnc :0 --chardev null,id=,
qemu-system-x86_64: --chardev null,id=,: Parameter 'id' expects an identifier
Identifiers consist of letters, digits, '-', '.', '_', starting with a letter.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <1441901956-21991-1-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-09-11 00:19:16 +08:00
|
|
|
error_append_hint(errp, "devices at \"%s\":", bus->name);
|
2011-12-24 05:34:39 +08:00
|
|
|
QTAILQ_FOREACH(kid, &bus->children, sibling) {
|
|
|
|
DeviceState *dev = kid->child;
|
hmp: Allow for error message hints on HMP
Commits 7216ae3d and d2828429 disabled some error message hints,
all because a change to use modern error reporting meant that the
hint would be output prior to the actual error. Fix this by making
hints a first-class member of Error.
For example, we are now back to the pleasant:
$ qemu-system-x86_64 --nodefaults -S --vnc :0 --chardev null,id=,
qemu-system-x86_64: --chardev null,id=,: Parameter 'id' expects an identifier
Identifiers consist of letters, digits, '-', '.', '_', starting with a letter.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <1441901956-21991-1-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-09-11 00:19:16 +08:00
|
|
|
error_append_hint(errp, "%s\"%s\"", sep,
|
|
|
|
object_get_typename(OBJECT(dev)));
|
|
|
|
if (dev->id) {
|
|
|
|
error_append_hint(errp, "/\"%s\"", dev->id);
|
|
|
|
}
|
2011-12-23 05:24:20 +08:00
|
|
|
sep = ", ";
|
|
|
|
}
|
2015-12-18 00:35:14 +08:00
|
|
|
error_append_hint(errp, "\n");
|
2011-12-23 05:24:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2011-12-24 05:34:39 +08:00
|
|
|
BusChild *kid;
|
2011-12-23 05:24:20 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* try to match in order:
|
|
|
|
* (1) instance id, if present
|
|
|
|
* (2) driver name
|
|
|
|
* (3) driver alias, if present
|
|
|
|
*/
|
2011-12-24 05:34:39 +08:00
|
|
|
QTAILQ_FOREACH(kid, &bus->children, sibling) {
|
|
|
|
DeviceState *dev = kid->child;
|
2011-12-23 05:24:20 +08:00
|
|
|
if (dev->id && strcmp(dev->id, elem) == 0) {
|
|
|
|
return dev;
|
|
|
|
}
|
|
|
|
}
|
2011-12-24 05:34:39 +08:00
|
|
|
QTAILQ_FOREACH(kid, &bus->children, sibling) {
|
|
|
|
DeviceState *dev = kid->child;
|
2011-12-23 05:24:20 +08:00
|
|
|
if (strcmp(object_get_typename(OBJECT(dev)), elem) == 0) {
|
|
|
|
return dev;
|
|
|
|
}
|
|
|
|
}
|
2011-12-24 05:34:39 +08:00
|
|
|
QTAILQ_FOREACH(kid, &bus->children, sibling) {
|
|
|
|
DeviceState *dev = kid->child;
|
2011-12-23 05:24:20 +08:00
|
|
|
DeviceClass *dc = DEVICE_GET_CLASS(dev);
|
|
|
|
|
|
|
|
if (qdev_class_has_alias(dc) &&
|
|
|
|
strcmp(qdev_class_get_alias(dc), elem) == 0) {
|
|
|
|
return dev;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2015-03-12 00:26:31 +08:00
|
|
|
static inline bool qbus_is_full(BusState *bus)
|
|
|
|
{
|
|
|
|
BusClass *bus_class = BUS_GET_CLASS(bus);
|
2018-12-17 23:57:30 +08:00
|
|
|
return bus_class->max_dev && bus->num_children >= bus_class->max_dev;
|
2015-03-12 00:26:31 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
2011-12-23 05:24:20 +08:00
|
|
|
static BusState *qbus_find_recursive(BusState *bus, const char *name,
|
2012-05-02 15:00:20 +08:00
|
|
|
const char *bus_typename)
|
2011-12-23 05:24:20 +08:00
|
|
|
{
|
2011-12-24 05:34:39 +08:00
|
|
|
BusChild *kid;
|
2015-03-12 00:26:31 +08:00
|
|
|
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);
|
2013-01-15 07:08:00 +08:00
|
|
|
}
|
2015-03-12 00:26:31 +08:00
|
|
|
|
|
|
|
if (match && !qbus_is_full(bus)) {
|
|
|
|
return bus; /* root matches and isn't full */
|
2011-12-23 05:24:20 +08:00
|
|
|
}
|
|
|
|
|
2015-03-12 00:26:31 +08:00
|
|
|
pick = match ? bus : NULL;
|
|
|
|
|
2011-12-24 05:34:39 +08:00
|
|
|
QTAILQ_FOREACH(kid, &bus->children, sibling) {
|
|
|
|
DeviceState *dev = kid->child;
|
2011-12-23 05:24:20 +08:00
|
|
|
QLIST_FOREACH(child, &dev->child_bus, sibling) {
|
2012-05-02 15:00:20 +08:00
|
|
|
ret = qbus_find_recursive(child, name, bus_typename);
|
2015-03-12 00:26:31 +08:00
|
|
|
if (ret && !qbus_is_full(ret)) {
|
|
|
|
return ret; /* a descendant matches and isn't full */
|
|
|
|
}
|
|
|
|
if (ret && !pick) {
|
|
|
|
pick = ret;
|
2011-12-23 05:24:20 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-03-12 00:26:31 +08:00
|
|
|
|
|
|
|
/* root or a descendant matches, but is full */
|
|
|
|
return pick;
|
2011-12-23 05:24:20 +08:00
|
|
|
}
|
|
|
|
|
2015-03-12 02:16:04 +08:00
|
|
|
static BusState *qbus_find(const char *path, Error **errp)
|
2011-12-23 05:24:20 +08:00
|
|
|
{
|
|
|
|
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) {
|
2015-03-12 02:16:04 +08:00
|
|
|
error_setg(errp, "Bus '%s' not found", elem);
|
2011-12-23 05:24:20 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
pos = len;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
assert(path[pos] == '/' || !path[pos]);
|
|
|
|
while (path[pos] == '/') {
|
|
|
|
pos++;
|
|
|
|
}
|
|
|
|
if (path[pos] == '\0') {
|
2015-03-12 01:39:16 +08:00
|
|
|
break;
|
2011-12-23 05:24:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* find device */
|
|
|
|
if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {
|
2013-07-26 00:21:28 +08:00
|
|
|
g_assert_not_reached();
|
2011-12-23 05:24:20 +08:00
|
|
|
elem[0] = len = 0;
|
|
|
|
}
|
|
|
|
pos += len;
|
|
|
|
dev = qbus_find_dev(bus, elem);
|
|
|
|
if (!dev) {
|
2015-03-16 15:57:47 +08:00
|
|
|
error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
|
|
|
|
"Device '%s' not found", elem);
|
2019-12-06 01:46:20 +08:00
|
|
|
qbus_error_append_dev_list_hint(bus, errp);
|
2011-12-23 05:24:20 +08:00
|
|
|
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 */
|
2015-03-12 01:39:16 +08:00
|
|
|
if (dev->num_child_bus == 1) {
|
|
|
|
bus = QLIST_FIRST(&dev->child_bus);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (dev->num_child_bus) {
|
2015-03-12 02:16:04 +08:00
|
|
|
error_setg(errp, "Device '%s' has multiple child buses",
|
|
|
|
elem);
|
2019-12-06 01:46:20 +08:00
|
|
|
qbus_error_append_bus_list_hint(dev, errp);
|
2015-03-12 01:39:16 +08:00
|
|
|
} else {
|
2015-03-12 02:16:04 +08:00
|
|
|
error_setg(errp, "Device '%s' has no child bus", elem);
|
2011-12-23 05:24:20 +08:00
|
|
|
}
|
2015-03-12 01:39:16 +08:00
|
|
|
return NULL;
|
2011-12-23 05:24:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* find bus */
|
|
|
|
if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {
|
2013-07-26 00:21:28 +08:00
|
|
|
g_assert_not_reached();
|
2011-12-23 05:24:20 +08:00
|
|
|
elem[0] = len = 0;
|
|
|
|
}
|
|
|
|
pos += len;
|
|
|
|
bus = qbus_find_bus(dev, elem);
|
|
|
|
if (!bus) {
|
2015-03-12 02:16:04 +08:00
|
|
|
error_setg(errp, "Bus '%s' not found", elem);
|
2019-12-06 01:46:20 +08:00
|
|
|
qbus_error_append_bus_list_hint(dev, errp);
|
2011-12-23 05:24:20 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
2015-03-12 01:39:16 +08:00
|
|
|
|
|
|
|
if (qbus_is_full(bus)) {
|
2015-03-12 02:16:04 +08:00
|
|
|
error_setg(errp, "Bus '%s' is full", path);
|
2015-03-12 01:39:16 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return bus;
|
2011-12-23 05:24:20 +08:00
|
|
|
}
|
|
|
|
|
2016-11-22 14:10:57 +08:00
|
|
|
void qdev_set_id(DeviceState *dev, const char *id)
|
|
|
|
{
|
|
|
|
if (id) {
|
|
|
|
dev->id = id;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dev->id) {
|
|
|
|
object_property_add_child(qdev_get_peripheral(), dev->id,
|
|
|
|
OBJECT(dev), NULL);
|
|
|
|
} else {
|
|
|
|
static int anon_count;
|
|
|
|
gchar *name = g_strdup_printf("device[%d]", anon_count++);
|
|
|
|
object_property_add_child(qdev_get_peripheral_anon(), name,
|
|
|
|
OBJECT(dev), NULL);
|
|
|
|
g_free(name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-29 19:48:55 +08:00
|
|
|
static int is_failover_device(void *opaque, const char *name, const char *value,
|
|
|
|
Error **errp)
|
|
|
|
{
|
|
|
|
if (strcmp(name, "failover_pair_id") == 0) {
|
|
|
|
QemuOpts *opts = (QemuOpts *)opaque;
|
|
|
|
|
|
|
|
if (qdev_should_hide_device(opts)) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool should_hide_device(QemuOpts *opts)
|
|
|
|
{
|
|
|
|
if (qemu_opt_foreach(opts, is_failover_device, opts, NULL) == 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-03-12 21:00:41 +08:00
|
|
|
DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
|
2011-12-23 05:24:20 +08:00
|
|
|
{
|
2013-08-24 07:21:22 +08:00
|
|
|
DeviceClass *dc;
|
2016-11-22 14:10:57 +08:00
|
|
|
const char *driver, *path;
|
2019-10-29 19:48:55 +08:00
|
|
|
DeviceState *dev = NULL;
|
2013-04-16 09:50:21 +08:00
|
|
|
BusState *bus = NULL;
|
2013-10-07 22:42:34 +08:00
|
|
|
Error *err = NULL;
|
2019-10-29 19:48:55 +08:00
|
|
|
bool hide;
|
2011-12-23 05:24:20 +08:00
|
|
|
|
|
|
|
driver = qemu_opt_get(opts, "driver");
|
|
|
|
if (!driver) {
|
2015-03-17 18:54:50 +08:00
|
|
|
error_setg(errp, QERR_MISSING_PARAMETER, "driver");
|
2011-12-23 05:24:20 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* find driver */
|
2015-03-12 21:00:41 +08:00
|
|
|
dc = qdev_get_device_class(&driver, errp);
|
|
|
|
if (!dc) {
|
2013-11-29 00:27:03 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
2011-12-23 05:24:20 +08:00
|
|
|
|
|
|
|
/* find bus */
|
|
|
|
path = qemu_opt_get(opts, "bus");
|
|
|
|
if (path != NULL) {
|
2015-03-12 21:00:41 +08:00
|
|
|
bus = qbus_find(path, errp);
|
2011-12-23 05:24:20 +08:00
|
|
|
if (!bus) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2013-08-24 07:21:22 +08:00
|
|
|
if (!object_dynamic_cast(OBJECT(bus), dc->bus_type)) {
|
2015-03-12 21:00:41 +08:00
|
|
|
error_setg(errp, "Device '%s' can't go on %s bus",
|
|
|
|
driver, object_get_typename(OBJECT(bus)));
|
2011-12-23 05:24:20 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
2013-08-24 07:21:22 +08:00
|
|
|
} else if (dc->bus_type != NULL) {
|
|
|
|
bus = qbus_find_recursive(sysbus_get_default(), NULL, dc->bus_type);
|
2015-03-12 00:26:31 +08:00
|
|
|
if (!bus || qbus_is_full(bus)) {
|
2015-03-12 21:00:41 +08:00
|
|
|
error_setg(errp, "No '%s' bus found for device '%s'",
|
|
|
|
dc->bus_type, driver);
|
2011-12-23 05:24:20 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
2019-10-29 19:48:55 +08:00
|
|
|
hide = should_hide_device(opts);
|
|
|
|
|
|
|
|
if ((hide || qdev_hotplug) && bus && !qbus_is_hotpluggable(bus)) {
|
2015-03-17 18:54:50 +08:00
|
|
|
error_setg(errp, QERR_BUS_NO_HOTPLUG, bus->name);
|
2011-12-23 05:24:20 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2019-10-29 19:48:55 +08:00
|
|
|
if (hide) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-03-23 00:34:27 +08:00
|
|
|
if (!migration_is_idle()) {
|
|
|
|
error_setg(errp, "device_add not allowed while migrating");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2014-03-03 15:57:55 +08:00
|
|
|
/* create device */
|
2013-10-07 22:17:54 +08:00
|
|
|
dev = DEVICE(object_new(driver));
|
2013-04-16 09:50:21 +08:00
|
|
|
|
2019-09-16 16:07:16 +08:00
|
|
|
/* Check whether the hotplug is allowed by the machine */
|
|
|
|
if (qdev_hotplug && !qdev_hotplug_allowed(dev, &err)) {
|
|
|
|
/* Error must be set in the machine hook */
|
|
|
|
assert(err);
|
|
|
|
goto err_del_dev;
|
|
|
|
}
|
|
|
|
|
2013-04-16 09:50:21 +08:00
|
|
|
if (bus) {
|
2013-10-07 22:17:54 +08:00
|
|
|
qdev_set_parent_bus(dev, bus);
|
2017-11-02 18:10:06 +08:00
|
|
|
} else if (qdev_hotplug && !qdev_get_machine_hotplug_handler(dev)) {
|
|
|
|
/* No bus, no machine hotplug handler --> device is not hotpluggable */
|
|
|
|
error_setg(&err, "Device '%s' can not be hotplugged on this machine",
|
|
|
|
driver);
|
|
|
|
goto err_del_dev;
|
2013-04-16 09:50:21 +08:00
|
|
|
}
|
2011-12-23 05:24:20 +08:00
|
|
|
|
2016-11-22 14:10:57 +08:00
|
|
|
qdev_set_id(dev, qemu_opts_id(opts));
|
2014-02-27 01:32:40 +08:00
|
|
|
|
2014-03-03 15:57:55 +08:00
|
|
|
/* set properties */
|
2015-03-12 20:58:02 +08:00
|
|
|
if (qemu_opt_foreach(opts, set_property, dev, &err)) {
|
2017-11-02 18:10:05 +08:00
|
|
|
goto err_del_dev;
|
2014-03-03 15:57:55 +08:00
|
|
|
}
|
|
|
|
|
2014-02-27 01:32:40 +08:00
|
|
|
dev->opts = opts;
|
2013-10-07 22:42:34 +08:00
|
|
|
object_property_set_bool(OBJECT(dev), true, "realized", &err);
|
|
|
|
if (err != NULL) {
|
2014-02-27 01:32:40 +08:00
|
|
|
dev->opts = NULL;
|
2017-11-02 18:10:05 +08:00
|
|
|
goto err_del_dev;
|
2012-03-28 00:38:46 +08:00
|
|
|
}
|
2013-10-07 22:17:54 +08:00
|
|
|
return dev;
|
2017-11-02 18:10:05 +08:00
|
|
|
|
|
|
|
err_del_dev:
|
|
|
|
error_propagate(errp, err);
|
2019-10-29 19:48:55 +08:00
|
|
|
if (dev) {
|
|
|
|
object_unparent(OBJECT(dev));
|
|
|
|
object_unref(OBJECT(dev));
|
|
|
|
}
|
2017-11-02 18:10:05 +08:00
|
|
|
return NULL;
|
2011-12-23 05:24:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#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,
|
2012-03-29 00:12:47 +08:00
|
|
|
int indent)
|
2011-12-23 05:24:20 +08:00
|
|
|
{
|
|
|
|
if (!props)
|
|
|
|
return;
|
2012-02-02 16:47:13 +08:00
|
|
|
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 {
|
2014-02-08 18:01:51 +08:00
|
|
|
value = object_property_print(OBJECT(dev), props->name, true, &err);
|
2012-02-02 16:47:13 +08:00
|
|
|
}
|
|
|
|
g_free(legacy_name);
|
|
|
|
|
|
|
|
if (err) {
|
|
|
|
error_free(err);
|
|
|
|
continue;
|
2011-12-23 05:24:20 +08:00
|
|
|
}
|
2012-03-29 00:12:47 +08:00
|
|
|
qdev_printf("%s = %s\n", props->name,
|
2012-02-02 16:47:13 +08:00
|
|
|
value && *value ? value : "<null>");
|
|
|
|
g_free(value);
|
2011-12-23 05:24:20 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-02 15:00:20 +08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-23 05:24:20 +08:00
|
|
|
static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
|
|
|
|
{
|
2012-03-29 00:12:47 +08:00
|
|
|
ObjectClass *class;
|
2011-12-23 05:24:20 +08:00
|
|
|
BusState *child;
|
2014-05-20 14:30:58 +08:00
|
|
|
NamedGPIOList *ngl;
|
2020-04-06 21:52:51 +08:00
|
|
|
NamedClockList *ncl;
|
2014-05-20 14:30:58 +08:00
|
|
|
|
2011-12-23 05:24:20 +08:00
|
|
|
qdev_printf("dev: %s, id \"%s\"\n", object_get_typename(OBJECT(dev)),
|
|
|
|
dev->id ? dev->id : "");
|
|
|
|
indent += 2;
|
2014-05-20 14:30:58 +08:00
|
|
|
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);
|
|
|
|
}
|
2011-12-23 05:24:20 +08:00
|
|
|
}
|
2020-04-06 21:52:51 +08:00
|
|
|
QLIST_FOREACH(ncl, &dev->clocks, node) {
|
|
|
|
qdev_printf("clock-%s%s \"%s\" freq_hz=%e\n",
|
|
|
|
ncl->output ? "out" : "in",
|
|
|
|
ncl->alias ? " (alias)" : "",
|
|
|
|
ncl->name,
|
|
|
|
CLOCK_PERIOD_TO_HZ(1.0 * clock_get(ncl->clock)));
|
|
|
|
}
|
2012-03-29 00:12:47 +08:00
|
|
|
class = object_get_class(OBJECT(dev));
|
|
|
|
do {
|
2020-01-23 19:11:38 +08:00
|
|
|
qdev_print_props(mon, dev, DEVICE_CLASS(class)->props_, indent);
|
2012-03-29 00:12:47 +08:00
|
|
|
class = object_class_get_parent(class);
|
|
|
|
} while (class != object_class_by_name(TYPE_DEVICE));
|
2012-07-11 18:21:23 +08:00
|
|
|
bus_print_dev(dev->parent_bus, mon, dev, indent);
|
2011-12-23 05:24:20 +08:00
|
|
|
QLIST_FOREACH(child, &dev->child_bus, sibling) {
|
|
|
|
qbus_print(mon, child, indent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void qbus_print(Monitor *mon, BusState *bus, int indent)
|
|
|
|
{
|
2011-12-24 05:34:39 +08:00
|
|
|
BusChild *kid;
|
2011-12-23 05:24:20 +08:00
|
|
|
|
|
|
|
qdev_printf("bus: %s\n", bus->name);
|
|
|
|
indent += 2;
|
2012-05-02 15:00:20 +08:00
|
|
|
qdev_printf("type %s\n", object_get_typename(OBJECT(bus)));
|
2011-12-24 05:34:39 +08:00
|
|
|
QTAILQ_FOREACH(kid, &bus->children, sibling) {
|
|
|
|
DeviceState *dev = kid->child;
|
2011-12-23 05:24:20 +08:00
|
|
|
qdev_print(mon, dev, indent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#undef qdev_printf
|
|
|
|
|
2015-02-06 21:18:24 +08:00
|
|
|
void hmp_info_qtree(Monitor *mon, const QDict *qdict)
|
2011-12-23 05:24:20 +08:00
|
|
|
{
|
|
|
|
if (sysbus_get_default())
|
|
|
|
qbus_print(mon, sysbus_get_default(), 0);
|
|
|
|
}
|
|
|
|
|
2015-02-06 21:18:24 +08:00
|
|
|
void hmp_info_qdm(Monitor *mon, const QDict *qdict)
|
2011-12-23 05:24:20 +08:00
|
|
|
{
|
2013-10-10 21:00:21 +08:00
|
|
|
qdev_print_devinfos(true);
|
2011-12-23 05:24:20 +08:00
|
|
|
}
|
|
|
|
|
qmp: Wean off qerror_report()
The traditional QMP command handler interface
int qmp_FOO(Monitor *mon, const QDict *params, QObject **ret_data);
doesn't provide for returning an Error object. Instead, the handler
is expected to stash it in the monitor with qerror_report().
When we rebased QMP on top of QAPI, we didn't change this interface.
Instead, commit 776574d introduced "middle mode" as a temporary aid
for converting existing QMP commands to QAPI one by one. More than
three years later, we're still using it.
Middle mode has two effects:
* Instead of the native input marshallers
static void qmp_marshal_input_FOO(QDict *, QObject **, Error **)
it generates input marshallers conforming to the traditional QMP
command handler interface.
* It suppresses generation of code to register them with
qmp_register_command()
This permits giving them internal linkage.
As long as we need qmp-commands.hx, we can't use the registry behind
qmp_register_command(), so the latter has to stay for now.
The former has to go to get rid of qerror_report(). Changing all QMP
commands to fit the QAPI mold in one go was impractical back when we
started, but by now there are just a few stragglers left:
do_qmp_capabilities(), qmp_qom_set(), qmp_qom_get(), qmp_object_add(),
qmp_netdev_add(), do_device_add().
Switch middle mode to generate native input marshallers, and adapt the
stragglers. Simplifies both the monitor code and the stragglers.
Rename do_qmp_capabilities() to qmp_capabilities(), and
do_device_add() to qmp_device_add, because that's how QMP command
handlers are named today.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Luiz Capitulino <lcapitulino@redhat.com>
2015-03-14 00:25:50 +08:00
|
|
|
void qmp_device_add(QDict *qdict, QObject **ret_data, Error **errp)
|
2011-12-23 05:24:20 +08:00
|
|
|
{
|
2012-04-19 04:24:01 +08:00
|
|
|
Error *local_err = NULL;
|
2011-12-23 05:24:20 +08:00
|
|
|
QemuOpts *opts;
|
2013-01-25 21:12:37 +08:00
|
|
|
DeviceState *dev;
|
2011-12-23 05:24:20 +08:00
|
|
|
|
2012-04-19 04:24:01 +08:00
|
|
|
opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict, &local_err);
|
2014-01-30 22:07:28 +08:00
|
|
|
if (local_err) {
|
qmp: Wean off qerror_report()
The traditional QMP command handler interface
int qmp_FOO(Monitor *mon, const QDict *params, QObject **ret_data);
doesn't provide for returning an Error object. Instead, the handler
is expected to stash it in the monitor with qerror_report().
When we rebased QMP on top of QAPI, we didn't change this interface.
Instead, commit 776574d introduced "middle mode" as a temporary aid
for converting existing QMP commands to QAPI one by one. More than
three years later, we're still using it.
Middle mode has two effects:
* Instead of the native input marshallers
static void qmp_marshal_input_FOO(QDict *, QObject **, Error **)
it generates input marshallers conforming to the traditional QMP
command handler interface.
* It suppresses generation of code to register them with
qmp_register_command()
This permits giving them internal linkage.
As long as we need qmp-commands.hx, we can't use the registry behind
qmp_register_command(), so the latter has to stay for now.
The former has to go to get rid of qerror_report(). Changing all QMP
commands to fit the QAPI mold in one go was impractical back when we
started, but by now there are just a few stragglers left:
do_qmp_capabilities(), qmp_qom_set(), qmp_qom_get(), qmp_object_add(),
qmp_netdev_add(), do_device_add().
Switch middle mode to generate native input marshallers, and adapt the
stragglers. Simplifies both the monitor code and the stragglers.
Rename do_qmp_capabilities() to qmp_capabilities(), and
do_device_add() to qmp_device_add, because that's how QMP command
handlers are named today.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Luiz Capitulino <lcapitulino@redhat.com>
2015-03-14 00:25:50 +08:00
|
|
|
error_propagate(errp, local_err);
|
|
|
|
return;
|
2011-12-23 05:24:20 +08:00
|
|
|
}
|
|
|
|
if (!monitor_cur_is_qmp() && qdev_device_help(opts)) {
|
|
|
|
qemu_opts_del(opts);
|
qmp: Wean off qerror_report()
The traditional QMP command handler interface
int qmp_FOO(Monitor *mon, const QDict *params, QObject **ret_data);
doesn't provide for returning an Error object. Instead, the handler
is expected to stash it in the monitor with qerror_report().
When we rebased QMP on top of QAPI, we didn't change this interface.
Instead, commit 776574d introduced "middle mode" as a temporary aid
for converting existing QMP commands to QAPI one by one. More than
three years later, we're still using it.
Middle mode has two effects:
* Instead of the native input marshallers
static void qmp_marshal_input_FOO(QDict *, QObject **, Error **)
it generates input marshallers conforming to the traditional QMP
command handler interface.
* It suppresses generation of code to register them with
qmp_register_command()
This permits giving them internal linkage.
As long as we need qmp-commands.hx, we can't use the registry behind
qmp_register_command(), so the latter has to stay for now.
The former has to go to get rid of qerror_report(). Changing all QMP
commands to fit the QAPI mold in one go was impractical back when we
started, but by now there are just a few stragglers left:
do_qmp_capabilities(), qmp_qom_set(), qmp_qom_get(), qmp_object_add(),
qmp_netdev_add(), do_device_add().
Switch middle mode to generate native input marshallers, and adapt the
stragglers. Simplifies both the monitor code and the stragglers.
Rename do_qmp_capabilities() to qmp_capabilities(), and
do_device_add() to qmp_device_add, because that's how QMP command
handlers are named today.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Luiz Capitulino <lcapitulino@redhat.com>
2015-03-14 00:25:50 +08:00
|
|
|
return;
|
2011-12-23 05:24:20 +08:00
|
|
|
}
|
2015-03-12 21:00:41 +08:00
|
|
|
dev = qdev_device_add(opts, &local_err);
|
2013-01-25 21:12:37 +08:00
|
|
|
if (!dev) {
|
qmp: Wean off qerror_report()
The traditional QMP command handler interface
int qmp_FOO(Monitor *mon, const QDict *params, QObject **ret_data);
doesn't provide for returning an Error object. Instead, the handler
is expected to stash it in the monitor with qerror_report().
When we rebased QMP on top of QAPI, we didn't change this interface.
Instead, commit 776574d introduced "middle mode" as a temporary aid
for converting existing QMP commands to QAPI one by one. More than
three years later, we're still using it.
Middle mode has two effects:
* Instead of the native input marshallers
static void qmp_marshal_input_FOO(QDict *, QObject **, Error **)
it generates input marshallers conforming to the traditional QMP
command handler interface.
* It suppresses generation of code to register them with
qmp_register_command()
This permits giving them internal linkage.
As long as we need qmp-commands.hx, we can't use the registry behind
qmp_register_command(), so the latter has to stay for now.
The former has to go to get rid of qerror_report(). Changing all QMP
commands to fit the QAPI mold in one go was impractical back when we
started, but by now there are just a few stragglers left:
do_qmp_capabilities(), qmp_qom_set(), qmp_qom_get(), qmp_object_add(),
qmp_netdev_add(), do_device_add().
Switch middle mode to generate native input marshallers, and adapt the
stragglers. Simplifies both the monitor code and the stragglers.
Rename do_qmp_capabilities() to qmp_capabilities(), and
do_device_add() to qmp_device_add, because that's how QMP command
handlers are named today.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Luiz Capitulino <lcapitulino@redhat.com>
2015-03-14 00:25:50 +08:00
|
|
|
error_propagate(errp, local_err);
|
2011-12-23 05:24:20 +08:00
|
|
|
qemu_opts_del(opts);
|
qmp: Wean off qerror_report()
The traditional QMP command handler interface
int qmp_FOO(Monitor *mon, const QDict *params, QObject **ret_data);
doesn't provide for returning an Error object. Instead, the handler
is expected to stash it in the monitor with qerror_report().
When we rebased QMP on top of QAPI, we didn't change this interface.
Instead, commit 776574d introduced "middle mode" as a temporary aid
for converting existing QMP commands to QAPI one by one. More than
three years later, we're still using it.
Middle mode has two effects:
* Instead of the native input marshallers
static void qmp_marshal_input_FOO(QDict *, QObject **, Error **)
it generates input marshallers conforming to the traditional QMP
command handler interface.
* It suppresses generation of code to register them with
qmp_register_command()
This permits giving them internal linkage.
As long as we need qmp-commands.hx, we can't use the registry behind
qmp_register_command(), so the latter has to stay for now.
The former has to go to get rid of qerror_report(). Changing all QMP
commands to fit the QAPI mold in one go was impractical back when we
started, but by now there are just a few stragglers left:
do_qmp_capabilities(), qmp_qom_set(), qmp_qom_get(), qmp_object_add(),
qmp_netdev_add(), do_device_add().
Switch middle mode to generate native input marshallers, and adapt the
stragglers. Simplifies both the monitor code and the stragglers.
Rename do_qmp_capabilities() to qmp_capabilities(), and
do_device_add() to qmp_device_add, because that's how QMP command
handlers are named today.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Luiz Capitulino <lcapitulino@redhat.com>
2015-03-14 00:25:50 +08:00
|
|
|
return;
|
2011-12-23 05:24:20 +08:00
|
|
|
}
|
2013-01-25 21:12:37 +08:00
|
|
|
object_unref(OBJECT(dev));
|
2011-12-23 05:24:20 +08:00
|
|
|
}
|
|
|
|
|
2016-09-20 19:38:41 +08:00
|
|
|
static DeviceState *find_device_state(const char *id, Error **errp)
|
2011-12-23 05:24:20 +08:00
|
|
|
{
|
2014-10-02 18:08:45 +08:00
|
|
|
Object *obj;
|
2011-12-23 05:24:20 +08:00
|
|
|
|
2015-09-11 20:33:56 +08:00
|
|
|
if (id[0] == '/') {
|
|
|
|
obj = object_resolve_path(id, NULL);
|
|
|
|
} else {
|
|
|
|
char *root_path = object_get_canonical_path(qdev_get_peripheral());
|
|
|
|
char *path = g_strdup_printf("%s/%s", root_path, id);
|
|
|
|
|
|
|
|
g_free(root_path);
|
|
|
|
obj = object_resolve_path_type(path, TYPE_DEVICE, NULL);
|
|
|
|
g_free(path);
|
|
|
|
}
|
2014-10-02 18:08:45 +08:00
|
|
|
|
|
|
|
if (!obj) {
|
2015-03-16 15:57:47 +08:00
|
|
|
error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
|
|
|
|
"Device '%s' not found", id);
|
2016-09-20 19:38:41 +08:00
|
|
|
return NULL;
|
2012-03-15 04:37:38 +08:00
|
|
|
}
|
|
|
|
|
2015-09-11 20:33:56 +08:00
|
|
|
if (!object_dynamic_cast(obj, TYPE_DEVICE)) {
|
|
|
|
error_setg(errp, "%s is not a hotpluggable device", id);
|
2016-09-20 19:38:41 +08:00
|
|
|
return NULL;
|
2015-09-11 20:33:56 +08:00
|
|
|
}
|
|
|
|
|
2016-09-20 19:38:41 +08:00
|
|
|
return DEVICE(obj);
|
|
|
|
}
|
|
|
|
|
2017-03-28 17:22:51 +08:00
|
|
|
void qdev_unplug(DeviceState *dev, Error **errp)
|
|
|
|
{
|
|
|
|
DeviceClass *dc = DEVICE_GET_CLASS(dev);
|
|
|
|
HotplugHandler *hotplug_ctrl;
|
|
|
|
HotplugHandlerClass *hdc;
|
qdev: Let the hotplug_handler_unplug() caller delete the device
When unplugging a device, at one point the device will be destroyed
via object_unparent(). This will, one the one hand, unrealize the
removed device hierarchy, and on the other hand, destroy/free the
device hierarchy.
When chaining hotplug handlers, we want to overwrite a bus hotplug
handler by the machine hotplug handler, to be able to perform
some part of the plug/unplug and to forward the calls to the bus hotplug
handler.
For now, the bus hotplug handler would trigger an object_unparent(), not
allowing us to perform some unplug action on a device after we forwarded
the call to the bus hotplug handler. The device would be gone at that
point.
machine_unplug_handler(dev)
/* eventually do unplug stuff */
bus_unplug_handler(dev)
/* dev is gone, we can't do more unplug stuff */
So move the object_unparent() to the original caller of the unplug. For
now, keep the unrealize() at the original places of the
object_unparent(). For implicitly chained hotplug handlers (e.g. pc
code calling acpi hotplug handlers), the object_unparent() has to be
done by the outermost caller. So when calling hotplug_handler_unplug()
from inside an unplug handler, nothing is to be done.
hotplug_handler_unplug(dev) -> calls machine_unplug_handler()
machine_unplug_handler(dev) {
/* eventually do unplug stuff */
bus_unplug_handler(dev) -> calls unrealize(dev)
/* we can do more unplug stuff but device already unrealized */
}
object_unparent(dev)
In the long run, every unplug action should be factored out of the
unrealize() function into the unplug handler (especially for PCI). Then
we can get rid of the additonal unrealize() calls and object_unparent()
will properly unrealize the device hierarchy after the device has been
unplugged.
hotplug_handler_unplug(dev) -> calls machine_unplug_handler()
machine_unplug_handler(dev) {
/* eventually do unplug stuff */
bus_unplug_handler(dev) -> only unplugs, does not unrealize
/* we can do more unplug stuff */
}
object_unparent(dev) -> will unrealize
The original approach was suggested by Igor Mammedov for the PCI
part, but I extended it to all hotplug handlers. I consider this one
step into the right direction.
To summarize:
- object_unparent() on synchronous unplugs is done by common code
-- "Caller of hotplug_handler_unplug"
- object_unparent() on asynchronous unplugs ("unplug requests") has to
be done manually
-- "Caller of hotplug_handler_unplug"
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
Acked-by: Cornelia Huck <cohuck@redhat.com>
Signed-off-by: David Hildenbrand <david@redhat.com>
Message-Id: <20190228122849.4296-2-david@redhat.com>
Reviewed-by: Greg Kurz <groug@kaod.org>
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
2019-02-28 20:28:47 +08:00
|
|
|
Error *local_err = NULL;
|
2017-03-28 17:22:51 +08:00
|
|
|
|
|
|
|
if (dev->parent_bus && !qbus_is_hotpluggable(dev->parent_bus)) {
|
|
|
|
error_setg(errp, QERR_BUS_NO_HOTPLUG, dev->parent_bus->name);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!dc->hotpluggable) {
|
|
|
|
error_setg(errp, QERR_DEVICE_NO_HOTPLUG,
|
|
|
|
object_get_typename(OBJECT(dev)));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-10-29 19:49:01 +08:00
|
|
|
if (!migration_is_idle() && !dev->allow_unplug_during_migration) {
|
2017-03-23 00:34:27 +08:00
|
|
|
error_setg(errp, "device_del not allowed while migrating");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-03-28 17:22:51 +08:00
|
|
|
qdev_hot_removed = true;
|
|
|
|
|
|
|
|
hotplug_ctrl = qdev_get_hotplug_handler(dev);
|
|
|
|
/* hotpluggable device MUST have HotplugHandler, if it doesn't
|
|
|
|
* then something is very wrong with it */
|
|
|
|
g_assert(hotplug_ctrl);
|
|
|
|
|
|
|
|
/* If device supports async unplug just request it to be done,
|
|
|
|
* otherwise just remove it synchronously */
|
|
|
|
hdc = HOTPLUG_HANDLER_GET_CLASS(hotplug_ctrl);
|
|
|
|
if (hdc->unplug_request) {
|
qdev: Let the hotplug_handler_unplug() caller delete the device
When unplugging a device, at one point the device will be destroyed
via object_unparent(). This will, one the one hand, unrealize the
removed device hierarchy, and on the other hand, destroy/free the
device hierarchy.
When chaining hotplug handlers, we want to overwrite a bus hotplug
handler by the machine hotplug handler, to be able to perform
some part of the plug/unplug and to forward the calls to the bus hotplug
handler.
For now, the bus hotplug handler would trigger an object_unparent(), not
allowing us to perform some unplug action on a device after we forwarded
the call to the bus hotplug handler. The device would be gone at that
point.
machine_unplug_handler(dev)
/* eventually do unplug stuff */
bus_unplug_handler(dev)
/* dev is gone, we can't do more unplug stuff */
So move the object_unparent() to the original caller of the unplug. For
now, keep the unrealize() at the original places of the
object_unparent(). For implicitly chained hotplug handlers (e.g. pc
code calling acpi hotplug handlers), the object_unparent() has to be
done by the outermost caller. So when calling hotplug_handler_unplug()
from inside an unplug handler, nothing is to be done.
hotplug_handler_unplug(dev) -> calls machine_unplug_handler()
machine_unplug_handler(dev) {
/* eventually do unplug stuff */
bus_unplug_handler(dev) -> calls unrealize(dev)
/* we can do more unplug stuff but device already unrealized */
}
object_unparent(dev)
In the long run, every unplug action should be factored out of the
unrealize() function into the unplug handler (especially for PCI). Then
we can get rid of the additonal unrealize() calls and object_unparent()
will properly unrealize the device hierarchy after the device has been
unplugged.
hotplug_handler_unplug(dev) -> calls machine_unplug_handler()
machine_unplug_handler(dev) {
/* eventually do unplug stuff */
bus_unplug_handler(dev) -> only unplugs, does not unrealize
/* we can do more unplug stuff */
}
object_unparent(dev) -> will unrealize
The original approach was suggested by Igor Mammedov for the PCI
part, but I extended it to all hotplug handlers. I consider this one
step into the right direction.
To summarize:
- object_unparent() on synchronous unplugs is done by common code
-- "Caller of hotplug_handler_unplug"
- object_unparent() on asynchronous unplugs ("unplug requests") has to
be done manually
-- "Caller of hotplug_handler_unplug"
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
Acked-by: Cornelia Huck <cohuck@redhat.com>
Signed-off-by: David Hildenbrand <david@redhat.com>
Message-Id: <20190228122849.4296-2-david@redhat.com>
Reviewed-by: Greg Kurz <groug@kaod.org>
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
2019-02-28 20:28:47 +08:00
|
|
|
hotplug_handler_unplug_request(hotplug_ctrl, dev, &local_err);
|
2017-03-28 17:22:51 +08:00
|
|
|
} else {
|
qdev: Let the hotplug_handler_unplug() caller delete the device
When unplugging a device, at one point the device will be destroyed
via object_unparent(). This will, one the one hand, unrealize the
removed device hierarchy, and on the other hand, destroy/free the
device hierarchy.
When chaining hotplug handlers, we want to overwrite a bus hotplug
handler by the machine hotplug handler, to be able to perform
some part of the plug/unplug and to forward the calls to the bus hotplug
handler.
For now, the bus hotplug handler would trigger an object_unparent(), not
allowing us to perform some unplug action on a device after we forwarded
the call to the bus hotplug handler. The device would be gone at that
point.
machine_unplug_handler(dev)
/* eventually do unplug stuff */
bus_unplug_handler(dev)
/* dev is gone, we can't do more unplug stuff */
So move the object_unparent() to the original caller of the unplug. For
now, keep the unrealize() at the original places of the
object_unparent(). For implicitly chained hotplug handlers (e.g. pc
code calling acpi hotplug handlers), the object_unparent() has to be
done by the outermost caller. So when calling hotplug_handler_unplug()
from inside an unplug handler, nothing is to be done.
hotplug_handler_unplug(dev) -> calls machine_unplug_handler()
machine_unplug_handler(dev) {
/* eventually do unplug stuff */
bus_unplug_handler(dev) -> calls unrealize(dev)
/* we can do more unplug stuff but device already unrealized */
}
object_unparent(dev)
In the long run, every unplug action should be factored out of the
unrealize() function into the unplug handler (especially for PCI). Then
we can get rid of the additonal unrealize() calls and object_unparent()
will properly unrealize the device hierarchy after the device has been
unplugged.
hotplug_handler_unplug(dev) -> calls machine_unplug_handler()
machine_unplug_handler(dev) {
/* eventually do unplug stuff */
bus_unplug_handler(dev) -> only unplugs, does not unrealize
/* we can do more unplug stuff */
}
object_unparent(dev) -> will unrealize
The original approach was suggested by Igor Mammedov for the PCI
part, but I extended it to all hotplug handlers. I consider this one
step into the right direction.
To summarize:
- object_unparent() on synchronous unplugs is done by common code
-- "Caller of hotplug_handler_unplug"
- object_unparent() on asynchronous unplugs ("unplug requests") has to
be done manually
-- "Caller of hotplug_handler_unplug"
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
Acked-by: Cornelia Huck <cohuck@redhat.com>
Signed-off-by: David Hildenbrand <david@redhat.com>
Message-Id: <20190228122849.4296-2-david@redhat.com>
Reviewed-by: Greg Kurz <groug@kaod.org>
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
2019-02-28 20:28:47 +08:00
|
|
|
hotplug_handler_unplug(hotplug_ctrl, dev, &local_err);
|
|
|
|
if (!local_err) {
|
|
|
|
object_unparent(OBJECT(dev));
|
|
|
|
}
|
2017-03-28 17:22:51 +08:00
|
|
|
}
|
qdev: Let the hotplug_handler_unplug() caller delete the device
When unplugging a device, at one point the device will be destroyed
via object_unparent(). This will, one the one hand, unrealize the
removed device hierarchy, and on the other hand, destroy/free the
device hierarchy.
When chaining hotplug handlers, we want to overwrite a bus hotplug
handler by the machine hotplug handler, to be able to perform
some part of the plug/unplug and to forward the calls to the bus hotplug
handler.
For now, the bus hotplug handler would trigger an object_unparent(), not
allowing us to perform some unplug action on a device after we forwarded
the call to the bus hotplug handler. The device would be gone at that
point.
machine_unplug_handler(dev)
/* eventually do unplug stuff */
bus_unplug_handler(dev)
/* dev is gone, we can't do more unplug stuff */
So move the object_unparent() to the original caller of the unplug. For
now, keep the unrealize() at the original places of the
object_unparent(). For implicitly chained hotplug handlers (e.g. pc
code calling acpi hotplug handlers), the object_unparent() has to be
done by the outermost caller. So when calling hotplug_handler_unplug()
from inside an unplug handler, nothing is to be done.
hotplug_handler_unplug(dev) -> calls machine_unplug_handler()
machine_unplug_handler(dev) {
/* eventually do unplug stuff */
bus_unplug_handler(dev) -> calls unrealize(dev)
/* we can do more unplug stuff but device already unrealized */
}
object_unparent(dev)
In the long run, every unplug action should be factored out of the
unrealize() function into the unplug handler (especially for PCI). Then
we can get rid of the additonal unrealize() calls and object_unparent()
will properly unrealize the device hierarchy after the device has been
unplugged.
hotplug_handler_unplug(dev) -> calls machine_unplug_handler()
machine_unplug_handler(dev) {
/* eventually do unplug stuff */
bus_unplug_handler(dev) -> only unplugs, does not unrealize
/* we can do more unplug stuff */
}
object_unparent(dev) -> will unrealize
The original approach was suggested by Igor Mammedov for the PCI
part, but I extended it to all hotplug handlers. I consider this one
step into the right direction.
To summarize:
- object_unparent() on synchronous unplugs is done by common code
-- "Caller of hotplug_handler_unplug"
- object_unparent() on asynchronous unplugs ("unplug requests") has to
be done manually
-- "Caller of hotplug_handler_unplug"
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
Acked-by: Cornelia Huck <cohuck@redhat.com>
Signed-off-by: David Hildenbrand <david@redhat.com>
Message-Id: <20190228122849.4296-2-david@redhat.com>
Reviewed-by: Greg Kurz <groug@kaod.org>
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
2019-02-28 20:28:47 +08:00
|
|
|
error_propagate(errp, local_err);
|
2017-03-28 17:22:51 +08:00
|
|
|
}
|
|
|
|
|
2016-09-20 19:38:41 +08:00
|
|
|
void qmp_device_del(const char *id, Error **errp)
|
|
|
|
{
|
|
|
|
DeviceState *dev = find_device_state(id, errp);
|
|
|
|
if (dev != NULL) {
|
2020-02-21 00:55:56 +08:00
|
|
|
if (dev->pending_deleted_event) {
|
|
|
|
error_setg(errp, "Device %s is already in the "
|
|
|
|
"process of unplug", id);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-09-20 19:38:41 +08:00
|
|
|
qdev_unplug(dev, errp);
|
|
|
|
}
|
2011-12-23 05:24:20 +08:00
|
|
|
}
|
|
|
|
|
2019-07-10 02:59:36 +08:00
|
|
|
void hmp_device_add(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
qmp_device_add((QDict *)qdict, NULL, &err);
|
2019-12-06 01:46:18 +08:00
|
|
|
hmp_handle_error(mon, err);
|
2019-07-10 02:59:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void hmp_device_del(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *id = qdict_get_str(qdict, "id");
|
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
qmp_device_del(id, &err);
|
2019-12-06 01:46:18 +08:00
|
|
|
hmp_handle_error(mon, err);
|
2019-07-10 02:59:36 +08:00
|
|
|
}
|
|
|
|
|
2016-09-20 19:38:42 +08:00
|
|
|
BlockBackend *blk_by_qdev_id(const char *id, Error **errp)
|
|
|
|
{
|
|
|
|
DeviceState *dev;
|
|
|
|
BlockBackend *blk;
|
|
|
|
|
|
|
|
dev = find_device_state(id, errp);
|
|
|
|
if (dev == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
blk = blk_by_dev(dev);
|
|
|
|
if (!blk) {
|
|
|
|
error_setg(errp, "Device does not have a block device backend");
|
|
|
|
}
|
|
|
|
return blk;
|
|
|
|
}
|
|
|
|
|
2011-12-23 05:24:20 +08:00
|
|
|
void qdev_machine_init(void)
|
|
|
|
{
|
|
|
|
qdev_get_peripheral_anon();
|
|
|
|
qdev_get_peripheral();
|
|
|
|
}
|
2012-11-26 23:03:42 +08:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2015-04-09 20:16:19 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
QemuOpts: Wean off qerror_report_err()
qerror_report_err() is a transitional interface to help with
converting existing monitor commands to QMP. It should not be used
elsewhere.
The only remaining user in qemu-option.c is qemu_opts_parse(). Is it
used in QMP context? If not, we can simply replace
qerror_report_err() by error_report_err().
The uses in qemu-img.c, qemu-io.c, qemu-nbd.c and under tests/ are
clearly not in QMP context.
The uses in vl.c aren't either, because the only QMP command handlers
there are qmp_query_status() and qmp_query_machines(), and they don't
call it.
Remaining uses:
* drive_def(): Command line -drive and such, HMP drive_add and pci_add
* hmp_chardev_add(): HMP chardev-add
* monitor_parse_command(): HMP core
* tmp_config_parse(): Command line -tpmdev
* net_host_device_add(): HMP host_net_add
* net_client_parse(): Command line -net and -netdev
* qemu_global_option(): Command line -global
* vnc_parse_func(): Command line -display, -vnc, default display, HMP
change, QMP change. Bummer.
* qemu_pci_hot_add_nic(): HMP pci_add
* usb_net_init(): Command line -usbdevice, HMP usb_add
Propagate errors through qemu_opts_parse(). Create a convenience
function qemu_opts_parse_noisily() that passes errors to
error_report_err(). Switch all non-QMP users outside tests to it.
That leaves vnc_parse_func(). Propagate errors through it. Since I'm
touching it anyway, rename it to vnc_parse().
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Luiz Capitulino <lcapitulino@redhat.com>
2015-02-13 19:50:26 +08:00
|
|
|
opts = qemu_opts_parse_noisily(&qemu_global_opts, str, false);
|
2015-04-09 20:16:19 +08:00
|
|
|
if (!opts) {
|
2012-11-26 23:03:42 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|