2011-12-23 01:24:20 +04: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
|
2020-10-23 15:44:24 +03:00
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
2011-12-23 01:24:20 +04:00
|
|
|
*
|
|
|
|
* 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-29 20:50:05 +03:00
|
|
|
#include "qemu/osdep.h"
|
2013-04-16 05:50:21 +04:00
|
|
|
#include "hw/sysbus.h"
|
2019-07-09 21:59:36 +03:00
|
|
|
#include "monitor/hmp.h"
|
2012-12-17 21:19:49 +04:00
|
|
|
#include "monitor/monitor.h"
|
2013-02-04 14:37:52 +04:00
|
|
|
#include "monitor/qdev.h"
|
2012-12-17 21:20:04 +04:00
|
|
|
#include "sysemu/arch_init.h"
|
2018-02-01 14:18:31 +03:00
|
|
|
#include "qapi/error.h"
|
2019-06-19 23:10:37 +03:00
|
|
|
#include "qapi/qapi-commands-qdev.h"
|
2018-02-01 14:18:39 +03:00
|
|
|
#include "qapi/qmp/qdict.h"
|
2015-03-17 19:22:46 +03:00
|
|
|
#include "qapi/qmp/qerror.h"
|
2012-12-17 21:20:00 +04:00
|
|
|
#include "qemu/config-file.h"
|
2015-03-17 20:29:20 +03:00
|
|
|
#include "qemu/error-report.h"
|
2016-03-20 20:16:19 +03:00
|
|
|
#include "qemu/help_option.h"
|
2018-02-01 14:18:46 +03:00
|
|
|
#include "qemu/option.h"
|
2019-04-17 22:06:41 +03:00
|
|
|
#include "qemu/qemu-print.h"
|
2019-10-29 14:48:55 +03:00
|
|
|
#include "qemu/option_int.h"
|
2016-09-20 14:38:42 +03:00
|
|
|
#include "sysemu/block-backend.h"
|
2019-08-12 08:23:56 +03:00
|
|
|
#include "sysemu/sysemu.h"
|
2017-04-24 20:02:44 +03:00
|
|
|
#include "migration/misc.h"
|
2019-10-29 14:48:55 +03:00
|
|
|
#include "migration/migration.h"
|
2020-01-10 18:30:39 +03:00
|
|
|
#include "qemu/cutils.h"
|
2020-04-06 16:52:51 +03:00
|
|
|
#include "hw/clock.h"
|
2011-12-23 01:24:20 +04: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 04:36:26 +04:00
|
|
|
uint32_t arch_mask;
|
2011-12-23 01:24:20 +04:00
|
|
|
} QDevAlias;
|
|
|
|
|
2016-02-19 00:44:13 +03:00
|
|
|
/* Please keep this table sorted by typename. */
|
2011-12-23 01:24:20 +04:00
|
|
|
static const QDevAlias qdev_alias_table[] = {
|
2020-07-02 16:25:09 +03:00
|
|
|
{ "AC97", "ac97" }, /* -soundhw name */
|
2016-02-19 00:44:13 +03:00
|
|
|
{ "e1000", "e1000-82540em" },
|
2020-07-02 16:25:10 +03:00
|
|
|
{ "ES1370", "es1370" }, /* -soundhw name */
|
2016-02-19 00:44:13 +03:00
|
|
|
{ "ich9-ahci", "ahci" },
|
|
|
|
{ "lsi53c895a", "lsi" },
|
2016-02-19 00:44:14 +03: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 04:36:26 +04:00
|
|
|
{ "virtio-balloon-pci", "virtio-balloon",
|
|
|
|
QEMU_ARCH_ALL & ~QEMU_ARCH_S390X },
|
2015-06-17 00:06:33 +03:00
|
|
|
{ "virtio-blk-ccw", "virtio-blk", QEMU_ARCH_S390X },
|
2016-02-19 00:44:13 +03:00
|
|
|
{ "virtio-blk-pci", "virtio-blk", QEMU_ARCH_ALL & ~QEMU_ARCH_S390X },
|
2016-02-19 00:44:14 +03: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 16:27:43 +03:00
|
|
|
{ "virtio-iommu-pci", "virtio-iommu", QEMU_ARCH_ALL & ~QEMU_ARCH_S390X },
|
2016-02-19 00:44:14 +03: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 00:06:33 +03:00
|
|
|
{ "virtio-net-ccw", "virtio-net", QEMU_ARCH_S390X },
|
2016-02-19 00:44:13 +03:00
|
|
|
{ "virtio-net-pci", "virtio-net", QEMU_ARCH_ALL & ~QEMU_ARCH_S390X },
|
2016-02-19 00:44:14 +03: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 00:06:33 +03:00
|
|
|
{ "virtio-serial-ccw", "virtio-serial", QEMU_ARCH_S390X },
|
2016-02-19 00:44:13 +03:00
|
|
|
{ "virtio-serial-pci", "virtio-serial", QEMU_ARCH_ALL & ~QEMU_ARCH_S390X },
|
2016-02-19 00:44:14 +03:00
|
|
|
{ "virtio-tablet-ccw", "virtio-tablet", QEMU_ARCH_S390X },
|
|
|
|
{ "virtio-tablet-pci", "virtio-tablet", QEMU_ARCH_ALL & ~QEMU_ARCH_S390X },
|
2011-12-23 01:24:20 +04: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 04:36:26 +04:00
|
|
|
if (qdev_alias_table[i].arch_mask &&
|
|
|
|
!(qdev_alias_table[i].arch_mask & arch_type)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2011-12-23 01:24:20 +04: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 17:00:21 +04:00
|
|
|
static void qdev_print_devinfo(DeviceClass *dc)
|
2011-12-23 01:24:20 +04:00
|
|
|
{
|
2019-04-17 22:06:41 +03:00
|
|
|
qemu_printf("name \"%s\"", object_class_get_name(OBJECT_CLASS(dc)));
|
2012-05-02 11:00:20 +04:00
|
|
|
if (dc->bus_type) {
|
2019-04-17 22:06:41 +03:00
|
|
|
qemu_printf(", bus %s", dc->bus_type);
|
2011-12-23 01:24:20 +04:00
|
|
|
}
|
|
|
|
if (qdev_class_has_alias(dc)) {
|
2019-04-17 22:06:41 +03:00
|
|
|
qemu_printf(", alias \"%s\"", qdev_class_get_alias(dc));
|
2011-12-23 01:24:20 +04:00
|
|
|
}
|
|
|
|
if (dc->desc) {
|
2019-04-17 22:06:41 +03:00
|
|
|
qemu_printf(", desc \"%s\"", dc->desc);
|
2011-12-23 01:24:20 +04:00
|
|
|
}
|
2017-05-03 23:35:44 +03:00
|
|
|
if (!dc->user_creatable) {
|
2019-04-17 22:06:41 +03:00
|
|
|
qemu_printf(", no-user");
|
2011-12-23 01:24:20 +04:00
|
|
|
}
|
2019-04-17 22:06:41 +03:00
|
|
|
qemu_printf("\n");
|
2011-12-23 01:24:20 +04:00
|
|
|
}
|
|
|
|
|
2013-10-10 17:00:21 +04: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 16:01:16 +03:00
|
|
|
[DEVICE_CATEGORY_CPU] = "CPU",
|
2013-10-10 17:00:21 +04:00
|
|
|
[DEVICE_CATEGORY_MAX] = "Uncategorized",
|
|
|
|
};
|
|
|
|
GSList *list, *elt;
|
|
|
|
int i;
|
|
|
|
bool cat_printed;
|
|
|
|
|
2020-06-24 16:10:38 +03:00
|
|
|
module_load_qom_all();
|
2018-03-03 10:33:10 +03:00
|
|
|
list = object_class_get_list_sorted(TYPE_DEVICE, false);
|
2013-10-10 17:00:21 +04: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-28 20:26:54 +04:00
|
|
|
|| (!show_no_user
|
2017-05-03 23:35:44 +03:00
|
|
|
&& !dc->user_creatable)) {
|
2013-10-10 17:00:21 +04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!cat_printed) {
|
2019-04-17 22:06:41 +03:00
|
|
|
qemu_printf("%s%s devices:\n", i ? "\n" : "", cat_name[i]);
|
2013-10-10 17:00:21 +04:00
|
|
|
cat_printed = true;
|
|
|
|
}
|
|
|
|
qdev_print_devinfo(dc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
g_slist_free(list);
|
|
|
|
}
|
|
|
|
|
2015-03-12 10:40:25 +03:00
|
|
|
static int set_property(void *opaque, const char *name, const char *value,
|
|
|
|
Error **errp)
|
2011-12-23 01:24:20 +04:00
|
|
|
{
|
2014-02-08 14:01:49 +04:00
|
|
|
Object *obj = opaque;
|
2011-12-23 01:24:20 +04:00
|
|
|
|
|
|
|
if (strcmp(name, "driver") == 0)
|
|
|
|
return 0;
|
|
|
|
if (strcmp(name, "bus") == 0)
|
|
|
|
return 0;
|
|
|
|
|
error: Eliminate error_propagate() with Coccinelle, part 1
When all we do with an Error we receive into a local variable is
propagating to somewhere else, we can just as well receive it there
right away. Convert
if (!foo(..., &err)) {
...
error_propagate(errp, err);
...
return ...
}
to
if (!foo(..., errp)) {
...
...
return ...
}
where nothing else needs @err. Coccinelle script:
@rule1 forall@
identifier fun, err, errp, lbl;
expression list args, args2;
binary operator op;
constant c1, c2;
symbol false;
@@
if (
(
- fun(args, &err, args2)
+ fun(args, errp, args2)
|
- !fun(args, &err, args2)
+ !fun(args, errp, args2)
|
- fun(args, &err, args2) op c1
+ fun(args, errp, args2) op c1
)
)
{
... when != err
when != lbl:
when strict
- error_propagate(errp, err);
... when != err
(
return;
|
return c2;
|
return false;
)
}
@rule2 forall@
identifier fun, err, errp, lbl;
expression list args, args2;
expression var;
binary operator op;
constant c1, c2;
symbol false;
@@
- var = fun(args, &err, args2);
+ var = fun(args, errp, args2);
... when != err
if (
(
var
|
!var
|
var op c1
)
)
{
... when != err
when != lbl:
when strict
- error_propagate(errp, err);
... when != err
(
return;
|
return c2;
|
return false;
|
return var;
)
}
@depends on rule1 || rule2@
identifier err;
@@
- Error *err = NULL;
... when != err
Not exactly elegant, I'm afraid.
The "when != lbl:" is necessary to avoid transforming
if (fun(args, &err)) {
goto out
}
...
out:
error_propagate(errp, err);
even though other paths to label out still need the error_propagate().
For an actual example, see sclp_realize().
Without the "when strict", Coccinelle transforms vfio_msix_setup(),
incorrectly. I don't know what exactly "when strict" does, only that
it helps here.
The match of return is narrower than what I want, but I can't figure
out how to express "return where the operand doesn't use @err". For
an example where it's too narrow, see vfio_intx_enable().
Silently fails to convert hw/arm/armsse.c, because Coccinelle gets
confused by ARMSSE being used both as typedef and function-like macro
there. Converted manually.
Line breaks tidied up manually. One nested declaration of @local_err
deleted manually. Preexisting unwanted blank line dropped in
hw/riscv/sifive_e.c.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-Id: <20200707160613.848843-35-armbru@redhat.com>
2020-07-07 19:06:02 +03:00
|
|
|
if (!object_property_parse(obj, name, value, errp)) {
|
2011-12-23 01:24:20 +04: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 04:36:26 +04:00
|
|
|
if (qdev_alias_table[i].arch_mask &&
|
|
|
|
!(qdev_alias_table[i].arch_mask & arch_type)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2011-12-23 01:24:20 +04:00
|
|
|
if (strcmp(qdev_alias_table[i].alias, alias) == 0) {
|
|
|
|
return qdev_alias_table[i].typename;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2014-11-01 18:56:09 +03:00
|
|
|
static DeviceClass *qdev_get_device_class(const char **driver, Error **errp)
|
|
|
|
{
|
|
|
|
ObjectClass *oc;
|
|
|
|
DeviceClass *dc;
|
2016-02-19 00:44:12 +03:00
|
|
|
const char *original_name = *driver;
|
2014-11-01 18:56:09 +03:00
|
|
|
|
2020-06-24 16:10:38 +03:00
|
|
|
oc = module_object_class_by_name(*driver);
|
2014-11-01 18:56:09 +03:00
|
|
|
if (!oc) {
|
|
|
|
const char *typename = find_typename_by_alias(*driver);
|
|
|
|
|
|
|
|
if (typename) {
|
|
|
|
*driver = typename;
|
2020-06-24 16:10:38 +03:00
|
|
|
oc = module_object_class_by_name(*driver);
|
2014-11-01 18:56:09 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!object_class_dynamic_cast(oc, TYPE_DEVICE)) {
|
2016-02-19 00:44:12 +03: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 18:56:09 +03:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (object_class_is_abstract(oc)) {
|
2015-03-17 13:54:50 +03:00
|
|
|
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "driver",
|
|
|
|
"non-abstract device type");
|
2014-11-01 18:56:09 +03:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
dc = DEVICE_CLASS(oc);
|
2017-05-03 23:35:44 +03:00
|
|
|
if (!dc->user_creatable ||
|
2014-11-01 18:56:09 +03:00
|
|
|
(qdev_hotplug && !dc->hotpluggable)) {
|
2015-03-17 13:54:50 +03:00
|
|
|
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "driver",
|
|
|
|
"pluggable device type");
|
2014-11-01 18:56:09 +03:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return dc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-12-23 01:24:20 +04:00
|
|
|
int qdev_device_help(QemuOpts *opts)
|
|
|
|
{
|
2014-07-09 16:01:32 +04:00
|
|
|
Error *local_err = NULL;
|
2011-12-23 01:24:20 +04:00
|
|
|
const char *driver;
|
2018-03-01 16:09:38 +03:00
|
|
|
ObjectPropertyInfoList *prop_list;
|
|
|
|
ObjectPropertyInfoList *prop;
|
2020-01-10 18:30:39 +03:00
|
|
|
GPtrArray *array;
|
|
|
|
int i;
|
2011-12-23 01:24:20 +04:00
|
|
|
|
|
|
|
driver = qemu_opt_get(opts, "driver");
|
2012-08-02 16:45:54 +04:00
|
|
|
if (driver && is_help_option(driver)) {
|
2013-10-10 17:00:21 +04:00
|
|
|
qdev_print_devinfos(false);
|
2011-12-23 01:24:20 +04:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2012-08-02 16:45:54 +04:00
|
|
|
if (!driver || !qemu_opt_has_help_opt(opts)) {
|
2011-12-23 01:24:20 +04: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 11:59:59 +03:00
|
|
|
if (!object_class_by_name(driver)) {
|
|
|
|
const char *typename = find_typename_by_alias(driver);
|
|
|
|
|
|
|
|
if (typename) {
|
|
|
|
driver = typename;
|
|
|
|
}
|
2011-12-23 01:24:20 +04:00
|
|
|
}
|
|
|
|
|
2014-07-09 16:01:32 +04:00
|
|
|
prop_list = qmp_device_list_properties(driver, &local_err);
|
2014-09-16 06:19:33 +04:00
|
|
|
if (local_err) {
|
2014-11-01 18:56:10 +03:00
|
|
|
goto error;
|
2011-12-23 01:24:20 +04:00
|
|
|
}
|
2014-07-09 16:01:32 +04:00
|
|
|
|
2018-10-19 19:49:27 +03:00
|
|
|
if (prop_list) {
|
2019-04-17 22:06:41 +03:00
|
|
|
qemu_printf("%s options:\n", driver);
|
2018-10-19 19:49:27 +03:00
|
|
|
} else {
|
2019-04-17 22:06:41 +03:00
|
|
|
qemu_printf("There are no options for %s.\n", driver);
|
2018-10-19 19:49:27 +03:00
|
|
|
}
|
2020-01-10 18:30:39 +03:00
|
|
|
array = g_ptr_array_new();
|
2014-07-09 16:01:32 +04:00
|
|
|
for (prop = prop_list; prop; prop = prop->next) {
|
2020-01-10 18:30:39 +03: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 16:01:32 +04:00
|
|
|
}
|
2020-01-10 18:30:39 +03:00
|
|
|
g_ptr_array_sort(array, (GCompareFunc)qemu_pstrcmp0);
|
|
|
|
for (i = 0; i < array->len; i++) {
|
2020-07-14 19:01:58 +03:00
|
|
|
qemu_printf("%s\n", (char *)array->pdata[i]);
|
2020-01-10 18:30:39 +03:00
|
|
|
}
|
|
|
|
g_ptr_array_set_free_func(array, g_free);
|
|
|
|
g_ptr_array_free(array, true);
|
2018-03-01 16:09:38 +03:00
|
|
|
qapi_free_ObjectPropertyInfoList(prop_list);
|
2011-12-23 01:24:20 +04:00
|
|
|
return 1;
|
2014-11-01 18:56:10 +03:00
|
|
|
|
|
|
|
error:
|
2015-12-18 18:35:07 +03:00
|
|
|
error_report_err(local_err);
|
2014-11-01 18:56:10 +03:00
|
|
|
return 1;
|
2011-12-23 01:24:20 +04:00
|
|
|
}
|
|
|
|
|
2012-01-30 18:55:55 +04:00
|
|
|
static Object *qdev_get_peripheral(void)
|
2011-12-23 01:24:20 +04:00
|
|
|
{
|
2011-12-23 19:08:05 +04:00
|
|
|
static Object *dev;
|
2011-12-23 01:24:20 +04:00
|
|
|
|
|
|
|
if (dev == NULL) {
|
2012-04-05 15:21:46 +04:00
|
|
|
dev = container_get(qdev_get_machine(), "/peripheral");
|
2011-12-23 01:24:20 +04:00
|
|
|
}
|
|
|
|
|
2011-12-23 19:08:05 +04:00
|
|
|
return dev;
|
2011-12-23 01:24:20 +04:00
|
|
|
}
|
|
|
|
|
2012-01-30 18:55:55 +04:00
|
|
|
static Object *qdev_get_peripheral_anon(void)
|
2011-12-23 01:24:20 +04:00
|
|
|
{
|
2011-12-23 19:08:05 +04:00
|
|
|
static Object *dev;
|
2011-12-23 01:24:20 +04:00
|
|
|
|
|
|
|
if (dev == NULL) {
|
2012-04-05 15:21:46 +04:00
|
|
|
dev = container_get(qdev_get_machine(), "/peripheral-anon");
|
2011-12-23 01:24:20 +04:00
|
|
|
}
|
|
|
|
|
2011-12-23 19:08:05 +04:00
|
|
|
return dev;
|
2011-12-23 01:24:20 +04:00
|
|
|
}
|
|
|
|
|
2019-12-05 20:46:20 +03:00
|
|
|
static void qbus_error_append_bus_list_hint(DeviceState *dev,
|
|
|
|
Error *const *errp)
|
2011-12-23 01:24:20 +04: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-10 19:19:16 +03:00
|
|
|
error_append_hint(errp, "child buses at \"%s\":",
|
|
|
|
dev->id ? dev->id : object_get_typename(OBJECT(dev)));
|
2011-12-23 01:24:20 +04: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-10 19:19:16 +03:00
|
|
|
error_append_hint(errp, "%s\"%s\"", sep, child->name);
|
2011-12-23 01:24:20 +04:00
|
|
|
sep = ", ";
|
|
|
|
}
|
2015-12-17 19:35:14 +03:00
|
|
|
error_append_hint(errp, "\n");
|
2011-12-23 01:24:20 +04:00
|
|
|
}
|
|
|
|
|
2019-12-05 20:46:20 +03:00
|
|
|
static void qbus_error_append_dev_list_hint(BusState *bus,
|
|
|
|
Error *const *errp)
|
2011-12-23 01:24:20 +04:00
|
|
|
{
|
2011-12-24 01:34:39 +04:00
|
|
|
BusChild *kid;
|
2011-12-23 01:24:20 +04: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-10 19:19:16 +03:00
|
|
|
error_append_hint(errp, "devices at \"%s\":", bus->name);
|
2011-12-24 01:34:39 +04: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-10 19:19:16 +03: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 01:24:20 +04:00
|
|
|
sep = ", ";
|
|
|
|
}
|
2015-12-17 19:35:14 +03:00
|
|
|
error_append_hint(errp, "\n");
|
2011-12-23 01:24:20 +04: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 01:34:39 +04:00
|
|
|
BusChild *kid;
|
2011-12-23 01:24:20 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* try to match in order:
|
|
|
|
* (1) instance id, if present
|
|
|
|
* (2) driver name
|
|
|
|
* (3) driver alias, if present
|
|
|
|
*/
|
2011-12-24 01:34:39 +04:00
|
|
|
QTAILQ_FOREACH(kid, &bus->children, sibling) {
|
|
|
|
DeviceState *dev = kid->child;
|
2011-12-23 01:24:20 +04:00
|
|
|
if (dev->id && strcmp(dev->id, elem) == 0) {
|
|
|
|
return dev;
|
|
|
|
}
|
|
|
|
}
|
2011-12-24 01:34:39 +04:00
|
|
|
QTAILQ_FOREACH(kid, &bus->children, sibling) {
|
|
|
|
DeviceState *dev = kid->child;
|
2011-12-23 01:24:20 +04:00
|
|
|
if (strcmp(object_get_typename(OBJECT(dev)), elem) == 0) {
|
|
|
|
return dev;
|
|
|
|
}
|
|
|
|
}
|
2011-12-24 01:34:39 +04:00
|
|
|
QTAILQ_FOREACH(kid, &bus->children, sibling) {
|
|
|
|
DeviceState *dev = kid->child;
|
2011-12-23 01:24:20 +04: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-11 19:26:31 +03:00
|
|
|
static inline bool qbus_is_full(BusState *bus)
|
|
|
|
{
|
|
|
|
BusClass *bus_class = BUS_GET_CLASS(bus);
|
2018-12-17 18:57:30 +03:00
|
|
|
return bus_class->max_dev && bus->num_children >= bus_class->max_dev;
|
2015-03-11 19:26:31 +03: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 01:24:20 +04:00
|
|
|
static BusState *qbus_find_recursive(BusState *bus, const char *name,
|
2012-05-02 11:00:20 +04:00
|
|
|
const char *bus_typename)
|
2011-12-23 01:24:20 +04:00
|
|
|
{
|
2011-12-24 01:34:39 +04:00
|
|
|
BusChild *kid;
|
2015-03-11 19:26:31 +03: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 03:08:00 +04:00
|
|
|
}
|
2015-03-11 19:26:31 +03:00
|
|
|
|
|
|
|
if (match && !qbus_is_full(bus)) {
|
|
|
|
return bus; /* root matches and isn't full */
|
2011-12-23 01:24:20 +04:00
|
|
|
}
|
|
|
|
|
2015-03-11 19:26:31 +03:00
|
|
|
pick = match ? bus : NULL;
|
|
|
|
|
2011-12-24 01:34:39 +04:00
|
|
|
QTAILQ_FOREACH(kid, &bus->children, sibling) {
|
|
|
|
DeviceState *dev = kid->child;
|
2011-12-23 01:24:20 +04:00
|
|
|
QLIST_FOREACH(child, &dev->child_bus, sibling) {
|
2012-05-02 11:00:20 +04:00
|
|
|
ret = qbus_find_recursive(child, name, bus_typename);
|
2015-03-11 19:26:31 +03:00
|
|
|
if (ret && !qbus_is_full(ret)) {
|
|
|
|
return ret; /* a descendant matches and isn't full */
|
|
|
|
}
|
|
|
|
if (ret && !pick) {
|
|
|
|
pick = ret;
|
2011-12-23 01:24:20 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-03-11 19:26:31 +03:00
|
|
|
|
|
|
|
/* root or a descendant matches, but is full */
|
|
|
|
return pick;
|
2011-12-23 01:24:20 +04:00
|
|
|
}
|
|
|
|
|
2015-03-11 21:16:04 +03:00
|
|
|
static BusState *qbus_find(const char *path, Error **errp)
|
2011-12-23 01:24:20 +04: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-11 21:16:04 +03:00
|
|
|
error_setg(errp, "Bus '%s' not found", elem);
|
2011-12-23 01:24:20 +04:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
pos = len;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
assert(path[pos] == '/' || !path[pos]);
|
|
|
|
while (path[pos] == '/') {
|
|
|
|
pos++;
|
|
|
|
}
|
|
|
|
if (path[pos] == '\0') {
|
2015-03-11 20:39:16 +03:00
|
|
|
break;
|
2011-12-23 01:24:20 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* find device */
|
|
|
|
if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {
|
2013-07-25 20:21:28 +04:00
|
|
|
g_assert_not_reached();
|
2011-12-23 01:24:20 +04:00
|
|
|
elem[0] = len = 0;
|
|
|
|
}
|
|
|
|
pos += len;
|
|
|
|
dev = qbus_find_dev(bus, elem);
|
|
|
|
if (!dev) {
|
2015-03-16 10:57:47 +03:00
|
|
|
error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
|
|
|
|
"Device '%s' not found", elem);
|
2019-12-05 20:46:20 +03:00
|
|
|
qbus_error_append_dev_list_hint(bus, errp);
|
2011-12-23 01:24:20 +04: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-11 20:39:16 +03:00
|
|
|
if (dev->num_child_bus == 1) {
|
|
|
|
bus = QLIST_FIRST(&dev->child_bus);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (dev->num_child_bus) {
|
2015-03-11 21:16:04 +03:00
|
|
|
error_setg(errp, "Device '%s' has multiple child buses",
|
|
|
|
elem);
|
2019-12-05 20:46:20 +03:00
|
|
|
qbus_error_append_bus_list_hint(dev, errp);
|
2015-03-11 20:39:16 +03:00
|
|
|
} else {
|
2015-03-11 21:16:04 +03:00
|
|
|
error_setg(errp, "Device '%s' has no child bus", elem);
|
2011-12-23 01:24:20 +04:00
|
|
|
}
|
2015-03-11 20:39:16 +03:00
|
|
|
return NULL;
|
2011-12-23 01:24:20 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* find bus */
|
|
|
|
if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {
|
2013-07-25 20:21:28 +04:00
|
|
|
g_assert_not_reached();
|
2011-12-23 01:24:20 +04:00
|
|
|
elem[0] = len = 0;
|
|
|
|
}
|
|
|
|
pos += len;
|
|
|
|
bus = qbus_find_bus(dev, elem);
|
|
|
|
if (!bus) {
|
2015-03-11 21:16:04 +03:00
|
|
|
error_setg(errp, "Bus '%s' not found", elem);
|
2019-12-05 20:46:20 +03:00
|
|
|
qbus_error_append_bus_list_hint(dev, errp);
|
2011-12-23 01:24:20 +04:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
2015-03-11 20:39:16 +03:00
|
|
|
|
|
|
|
if (qbus_is_full(bus)) {
|
2015-03-11 21:16:04 +03:00
|
|
|
error_setg(errp, "Bus '%s' is full", path);
|
2015-03-11 20:39:16 +03:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return bus;
|
2011-12-23 01:24:20 +04:00
|
|
|
}
|
|
|
|
|
2016-11-22 09:10:57 +03: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,
|
qom: Drop parameter @errp of object_property_add() & friends
The only way object_property_add() can fail is when a property with
the same name already exists. Since our property names are all
hardcoded, failure is a programming error, and the appropriate way to
handle it is passing &error_abort.
Same for its variants, except for object_property_add_child(), which
additionally fails when the child already has a parent. Parentage is
also under program control, so this is a programming error, too.
We have a bit over 500 callers. Almost half of them pass
&error_abort, slightly fewer ignore errors, one test case handles
errors, and the remaining few callers pass them to their own callers.
The previous few commits demonstrated once again that ignoring
programming errors is a bad idea.
Of the few ones that pass on errors, several violate the Error API.
The Error ** argument must be NULL, &error_abort, &error_fatal, or a
pointer to a variable containing NULL. Passing an argument of the
latter kind twice without clearing it in between is wrong: if the
first call sets an error, it no longer points to NULL for the second
call. ich9_pm_add_properties(), sparc32_ledma_realize(),
sparc32_dma_realize(), xilinx_axidma_realize(), xilinx_enet_realize()
are wrong that way.
When the one appropriate choice of argument is &error_abort, letting
users pick the argument is a bad idea.
Drop parameter @errp and assert the preconditions instead.
There's one exception to "duplicate property name is a programming
error": the way object_property_add() implements the magic (and
undocumented) "automatic arrayification". Don't drop @errp there.
Instead, rename object_property_add() to object_property_try_add(),
and add the obvious wrapper object_property_add().
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <20200505152926.18877-15-armbru@redhat.com>
[Two semantic rebase conflicts resolved]
2020-05-05 18:29:22 +03:00
|
|
|
OBJECT(dev));
|
2016-11-22 09:10:57 +03:00
|
|
|
} else {
|
|
|
|
static int anon_count;
|
|
|
|
gchar *name = g_strdup_printf("device[%d]", anon_count++);
|
|
|
|
object_property_add_child(qdev_get_peripheral_anon(), name,
|
qom: Drop parameter @errp of object_property_add() & friends
The only way object_property_add() can fail is when a property with
the same name already exists. Since our property names are all
hardcoded, failure is a programming error, and the appropriate way to
handle it is passing &error_abort.
Same for its variants, except for object_property_add_child(), which
additionally fails when the child already has a parent. Parentage is
also under program control, so this is a programming error, too.
We have a bit over 500 callers. Almost half of them pass
&error_abort, slightly fewer ignore errors, one test case handles
errors, and the remaining few callers pass them to their own callers.
The previous few commits demonstrated once again that ignoring
programming errors is a bad idea.
Of the few ones that pass on errors, several violate the Error API.
The Error ** argument must be NULL, &error_abort, &error_fatal, or a
pointer to a variable containing NULL. Passing an argument of the
latter kind twice without clearing it in between is wrong: if the
first call sets an error, it no longer points to NULL for the second
call. ich9_pm_add_properties(), sparc32_ledma_realize(),
sparc32_dma_realize(), xilinx_axidma_realize(), xilinx_enet_realize()
are wrong that way.
When the one appropriate choice of argument is &error_abort, letting
users pick the argument is a bad idea.
Drop parameter @errp and assert the preconditions instead.
There's one exception to "duplicate property name is a programming
error": the way object_property_add() implements the magic (and
undocumented) "automatic arrayification". Don't drop @errp there.
Instead, rename object_property_add() to object_property_try_add(),
and add the obvious wrapper object_property_add().
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <20200505152926.18877-15-armbru@redhat.com>
[Two semantic rebase conflicts resolved]
2020-05-05 18:29:22 +03:00
|
|
|
OBJECT(dev));
|
2016-11-22 09:10:57 +03:00
|
|
|
g_free(name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-12 16:00:41 +03:00
|
|
|
DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
|
2011-12-23 01:24:20 +04:00
|
|
|
{
|
2013-08-24 03:21:22 +04:00
|
|
|
DeviceClass *dc;
|
2016-11-22 09:10:57 +03:00
|
|
|
const char *driver, *path;
|
2019-10-29 14:48:55 +03:00
|
|
|
DeviceState *dev = NULL;
|
2013-04-16 05:50:21 +04:00
|
|
|
BusState *bus = NULL;
|
2011-12-23 01:24:20 +04:00
|
|
|
|
|
|
|
driver = qemu_opt_get(opts, "driver");
|
|
|
|
if (!driver) {
|
2015-03-17 13:54:50 +03:00
|
|
|
error_setg(errp, QERR_MISSING_PARAMETER, "driver");
|
2011-12-23 01:24:20 +04:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* find driver */
|
2015-03-12 16:00:41 +03:00
|
|
|
dc = qdev_get_device_class(&driver, errp);
|
|
|
|
if (!dc) {
|
2013-11-28 20:27:03 +04:00
|
|
|
return NULL;
|
|
|
|
}
|
2011-12-23 01:24:20 +04:00
|
|
|
|
|
|
|
/* find bus */
|
|
|
|
path = qemu_opt_get(opts, "bus");
|
|
|
|
if (path != NULL) {
|
2015-03-12 16:00:41 +03:00
|
|
|
bus = qbus_find(path, errp);
|
2011-12-23 01:24:20 +04:00
|
|
|
if (!bus) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2013-08-24 03:21:22 +04:00
|
|
|
if (!object_dynamic_cast(OBJECT(bus), dc->bus_type)) {
|
2015-03-12 16:00:41 +03:00
|
|
|
error_setg(errp, "Device '%s' can't go on %s bus",
|
|
|
|
driver, object_get_typename(OBJECT(bus)));
|
2011-12-23 01:24:20 +04:00
|
|
|
return NULL;
|
|
|
|
}
|
2013-08-24 03:21:22 +04:00
|
|
|
} else if (dc->bus_type != NULL) {
|
|
|
|
bus = qbus_find_recursive(sysbus_get_default(), NULL, dc->bus_type);
|
2015-03-11 19:26:31 +03:00
|
|
|
if (!bus || qbus_is_full(bus)) {
|
2015-03-12 16:00:41 +03:00
|
|
|
error_setg(errp, "No '%s' bus found for device '%s'",
|
|
|
|
dc->bus_type, driver);
|
2011-12-23 01:24:20 +04:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
2019-10-29 14:48:55 +03:00
|
|
|
|
2020-11-18 11:37:41 +03:00
|
|
|
if (qemu_opt_get(opts, "failover_pair_id")) {
|
2020-11-18 11:37:42 +03:00
|
|
|
if (!opts->id) {
|
|
|
|
error_setg(errp, "Device with failover_pair_id don't have id");
|
|
|
|
return NULL;
|
|
|
|
}
|
2020-11-18 11:37:41 +03:00
|
|
|
if (qdev_should_hide_device(opts)) {
|
|
|
|
if (bus && !qbus_is_hotpluggable(bus)) {
|
|
|
|
error_setg(errp, QERR_BUS_NO_HOTPLUG, bus->name);
|
|
|
|
}
|
|
|
|
return NULL;
|
2020-11-18 11:37:40 +03:00
|
|
|
}
|
2011-12-23 01:24:20 +04:00
|
|
|
}
|
|
|
|
|
2020-11-18 11:37:40 +03:00
|
|
|
if (qdev_hotplug && bus && !qbus_is_hotpluggable(bus)) {
|
|
|
|
error_setg(errp, QERR_BUS_NO_HOTPLUG, bus->name);
|
2019-10-29 14:48:55 +03:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-03-22 19:34:27 +03:00
|
|
|
if (!migration_is_idle()) {
|
|
|
|
error_setg(errp, "device_add not allowed while migrating");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2014-03-03 11:57:55 +04:00
|
|
|
/* create device */
|
2020-06-10 08:31:54 +03:00
|
|
|
dev = qdev_new(driver);
|
2013-04-16 05:50:21 +04:00
|
|
|
|
2019-09-16 11:07:16 +03:00
|
|
|
/* Check whether the hotplug is allowed by the machine */
|
2020-07-07 19:06:04 +03:00
|
|
|
if (qdev_hotplug && !qdev_hotplug_allowed(dev, errp)) {
|
2019-09-16 11:07:16 +03:00
|
|
|
goto err_del_dev;
|
|
|
|
}
|
|
|
|
|
2020-06-10 08:32:44 +03:00
|
|
|
if (!bus && qdev_hotplug && !qdev_get_machine_hotplug_handler(dev)) {
|
2017-11-02 13:10:06 +03:00
|
|
|
/* No bus, no machine hotplug handler --> device is not hotpluggable */
|
2020-07-07 19:06:04 +03:00
|
|
|
error_setg(errp, "Device '%s' can not be hotplugged on this machine",
|
2017-11-02 13:10:06 +03:00
|
|
|
driver);
|
|
|
|
goto err_del_dev;
|
2013-04-16 05:50:21 +04:00
|
|
|
}
|
2011-12-23 01:24:20 +04:00
|
|
|
|
2016-11-22 09:10:57 +03:00
|
|
|
qdev_set_id(dev, qemu_opts_id(opts));
|
2014-02-26 21:32:40 +04:00
|
|
|
|
2014-03-03 11:57:55 +04:00
|
|
|
/* set properties */
|
2020-07-07 19:06:04 +03:00
|
|
|
if (qemu_opt_foreach(opts, set_property, dev, errp)) {
|
2017-11-02 13:10:05 +03:00
|
|
|
goto err_del_dev;
|
2014-03-03 11:57:55 +04:00
|
|
|
}
|
|
|
|
|
2014-02-26 21:32:40 +04:00
|
|
|
dev->opts = opts;
|
2020-07-07 19:06:04 +03:00
|
|
|
if (!qdev_realize(DEVICE(dev), bus, errp)) {
|
2014-02-26 21:32:40 +04:00
|
|
|
dev->opts = NULL;
|
2017-11-02 13:10:05 +03:00
|
|
|
goto err_del_dev;
|
2012-03-27 20:38:46 +04:00
|
|
|
}
|
2013-10-07 18:17:54 +04:00
|
|
|
return dev;
|
2017-11-02 13:10:05 +03:00
|
|
|
|
|
|
|
err_del_dev:
|
2019-10-29 14:48:55 +03:00
|
|
|
if (dev) {
|
|
|
|
object_unparent(OBJECT(dev));
|
|
|
|
object_unref(OBJECT(dev));
|
|
|
|
}
|
2017-11-02 13:10:05 +03:00
|
|
|
return NULL;
|
2011-12-23 01:24:20 +04: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-28 20:12:47 +04:00
|
|
|
int indent)
|
2011-12-23 01:24:20 +04:00
|
|
|
{
|
|
|
|
if (!props)
|
|
|
|
return;
|
2012-02-02 12:47:13 +04:00
|
|
|
for (; props->name; props++) {
|
|
|
|
char *value;
|
|
|
|
char *legacy_name = g_strdup_printf("legacy-%s", props->name);
|
2020-07-07 19:06:13 +03:00
|
|
|
|
2012-02-02 12:47:13 +04:00
|
|
|
if (object_property_get_type(OBJECT(dev), legacy_name, NULL)) {
|
2020-07-07 19:06:13 +03:00
|
|
|
value = object_property_get_str(OBJECT(dev), legacy_name, NULL);
|
2012-02-02 12:47:13 +04:00
|
|
|
} else {
|
2020-07-07 19:06:13 +03:00
|
|
|
value = object_property_print(OBJECT(dev), props->name, true,
|
|
|
|
NULL);
|
2012-02-02 12:47:13 +04:00
|
|
|
}
|
|
|
|
g_free(legacy_name);
|
|
|
|
|
2020-07-07 19:06:13 +03:00
|
|
|
if (!value) {
|
2012-02-02 12:47:13 +04:00
|
|
|
continue;
|
2011-12-23 01:24:20 +04:00
|
|
|
}
|
2012-03-28 20:12:47 +04:00
|
|
|
qdev_printf("%s = %s\n", props->name,
|
2020-07-07 19:06:13 +03:00
|
|
|
*value ? value : "<null>");
|
2012-02-02 12:47:13 +04:00
|
|
|
g_free(value);
|
2011-12-23 01:24:20 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-02 11:00:20 +04: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 01:24:20 +04:00
|
|
|
static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
|
|
|
|
{
|
2012-03-28 20:12:47 +04:00
|
|
|
ObjectClass *class;
|
2011-12-23 01:24:20 +04:00
|
|
|
BusState *child;
|
2014-05-20 10:30:58 +04:00
|
|
|
NamedGPIOList *ngl;
|
2020-04-06 16:52:51 +03:00
|
|
|
NamedClockList *ncl;
|
2014-05-20 10:30:58 +04:00
|
|
|
|
2011-12-23 01:24:20 +04:00
|
|
|
qdev_printf("dev: %s, id \"%s\"\n", object_get_typename(OBJECT(dev)),
|
|
|
|
dev->id ? dev->id : "");
|
|
|
|
indent += 2;
|
2014-05-20 10:30:58 +04: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 01:24:20 +04:00
|
|
|
}
|
2020-04-06 16:52:51 +03: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-28 20:12:47 +04:00
|
|
|
class = object_get_class(OBJECT(dev));
|
|
|
|
do {
|
2020-01-23 14:11:38 +03:00
|
|
|
qdev_print_props(mon, dev, DEVICE_CLASS(class)->props_, indent);
|
2012-03-28 20:12:47 +04:00
|
|
|
class = object_class_get_parent(class);
|
|
|
|
} while (class != object_class_by_name(TYPE_DEVICE));
|
2012-07-11 14:21:23 +04:00
|
|
|
bus_print_dev(dev->parent_bus, mon, dev, indent);
|
2011-12-23 01:24:20 +04: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 01:34:39 +04:00
|
|
|
BusChild *kid;
|
2011-12-23 01:24:20 +04:00
|
|
|
|
|
|
|
qdev_printf("bus: %s\n", bus->name);
|
|
|
|
indent += 2;
|
2012-05-02 11:00:20 +04:00
|
|
|
qdev_printf("type %s\n", object_get_typename(OBJECT(bus)));
|
2011-12-24 01:34:39 +04:00
|
|
|
QTAILQ_FOREACH(kid, &bus->children, sibling) {
|
|
|
|
DeviceState *dev = kid->child;
|
2011-12-23 01:24:20 +04:00
|
|
|
qdev_print(mon, dev, indent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#undef qdev_printf
|
|
|
|
|
2015-02-06 16:18:24 +03:00
|
|
|
void hmp_info_qtree(Monitor *mon, const QDict *qdict)
|
2011-12-23 01:24:20 +04:00
|
|
|
{
|
|
|
|
if (sysbus_get_default())
|
|
|
|
qbus_print(mon, sysbus_get_default(), 0);
|
|
|
|
}
|
|
|
|
|
2015-02-06 16:18:24 +03:00
|
|
|
void hmp_info_qdm(Monitor *mon, const QDict *qdict)
|
2011-12-23 01:24:20 +04:00
|
|
|
{
|
2013-10-10 17:00:21 +04:00
|
|
|
qdev_print_devinfos(true);
|
2011-12-23 01:24:20 +04: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-13 19:25:50 +03:00
|
|
|
void qmp_device_add(QDict *qdict, QObject **ret_data, Error **errp)
|
2011-12-23 01:24:20 +04:00
|
|
|
{
|
|
|
|
QemuOpts *opts;
|
2013-01-25 17:12:37 +04:00
|
|
|
DeviceState *dev;
|
2011-12-23 01:24:20 +04:00
|
|
|
|
2020-07-07 19:05:35 +03:00
|
|
|
opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict, errp);
|
|
|
|
if (!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-13 19:25:50 +03:00
|
|
|
return;
|
2011-12-23 01:24:20 +04: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-13 19:25:50 +03:00
|
|
|
return;
|
2011-12-23 01:24:20 +04:00
|
|
|
}
|
error: Eliminate error_propagate() with Coccinelle, part 1
When all we do with an Error we receive into a local variable is
propagating to somewhere else, we can just as well receive it there
right away. Convert
if (!foo(..., &err)) {
...
error_propagate(errp, err);
...
return ...
}
to
if (!foo(..., errp)) {
...
...
return ...
}
where nothing else needs @err. Coccinelle script:
@rule1 forall@
identifier fun, err, errp, lbl;
expression list args, args2;
binary operator op;
constant c1, c2;
symbol false;
@@
if (
(
- fun(args, &err, args2)
+ fun(args, errp, args2)
|
- !fun(args, &err, args2)
+ !fun(args, errp, args2)
|
- fun(args, &err, args2) op c1
+ fun(args, errp, args2) op c1
)
)
{
... when != err
when != lbl:
when strict
- error_propagate(errp, err);
... when != err
(
return;
|
return c2;
|
return false;
)
}
@rule2 forall@
identifier fun, err, errp, lbl;
expression list args, args2;
expression var;
binary operator op;
constant c1, c2;
symbol false;
@@
- var = fun(args, &err, args2);
+ var = fun(args, errp, args2);
... when != err
if (
(
var
|
!var
|
var op c1
)
)
{
... when != err
when != lbl:
when strict
- error_propagate(errp, err);
... when != err
(
return;
|
return c2;
|
return false;
|
return var;
)
}
@depends on rule1 || rule2@
identifier err;
@@
- Error *err = NULL;
... when != err
Not exactly elegant, I'm afraid.
The "when != lbl:" is necessary to avoid transforming
if (fun(args, &err)) {
goto out
}
...
out:
error_propagate(errp, err);
even though other paths to label out still need the error_propagate().
For an actual example, see sclp_realize().
Without the "when strict", Coccinelle transforms vfio_msix_setup(),
incorrectly. I don't know what exactly "when strict" does, only that
it helps here.
The match of return is narrower than what I want, but I can't figure
out how to express "return where the operand doesn't use @err". For
an example where it's too narrow, see vfio_intx_enable().
Silently fails to convert hw/arm/armsse.c, because Coccinelle gets
confused by ARMSSE being used both as typedef and function-like macro
there. Converted manually.
Line breaks tidied up manually. One nested declaration of @local_err
deleted manually. Preexisting unwanted blank line dropped in
hw/riscv/sifive_e.c.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-Id: <20200707160613.848843-35-armbru@redhat.com>
2020-07-07 19:06:02 +03:00
|
|
|
dev = qdev_device_add(opts, errp);
|
2020-10-06 15:38:58 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Drain all pending RCU callbacks. This is done because
|
|
|
|
* some bus related operations can delay a device removal
|
|
|
|
* (in this case this can happen if device is added and then
|
|
|
|
* removed due to a configuration error)
|
|
|
|
* to a RCU callback, but user might expect that this interface
|
|
|
|
* will finish its job completely once qmp command returns result
|
|
|
|
* to the user
|
|
|
|
*/
|
|
|
|
drain_call_rcu();
|
|
|
|
|
2013-01-25 17:12:37 +04:00
|
|
|
if (!dev) {
|
2011-12-23 01:24:20 +04: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-13 19:25:50 +03:00
|
|
|
return;
|
2011-12-23 01:24:20 +04:00
|
|
|
}
|
2013-01-25 17:12:37 +04:00
|
|
|
object_unref(OBJECT(dev));
|
2011-12-23 01:24:20 +04:00
|
|
|
}
|
|
|
|
|
2016-09-20 14:38:41 +03:00
|
|
|
static DeviceState *find_device_state(const char *id, Error **errp)
|
2011-12-23 01:24:20 +04:00
|
|
|
{
|
2014-10-02 14:08:45 +04:00
|
|
|
Object *obj;
|
2011-12-23 01:24:20 +04:00
|
|
|
|
2015-09-11 15:33:56 +03: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 14:08:45 +04:00
|
|
|
|
|
|
|
if (!obj) {
|
2015-03-16 10:57:47 +03:00
|
|
|
error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
|
|
|
|
"Device '%s' not found", id);
|
2016-09-20 14:38:41 +03:00
|
|
|
return NULL;
|
2012-03-15 00:37:38 +04:00
|
|
|
}
|
|
|
|
|
2015-09-11 15:33:56 +03:00
|
|
|
if (!object_dynamic_cast(obj, TYPE_DEVICE)) {
|
|
|
|
error_setg(errp, "%s is not a hotpluggable device", id);
|
2016-09-20 14:38:41 +03:00
|
|
|
return NULL;
|
2015-09-11 15:33:56 +03:00
|
|
|
}
|
|
|
|
|
2016-09-20 14:38:41 +03:00
|
|
|
return DEVICE(obj);
|
|
|
|
}
|
|
|
|
|
2017-03-28 12:22:51 +03: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 15:28:47 +03:00
|
|
|
Error *local_err = NULL;
|
2017-03-28 12:22:51 +03: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 14:49:01 +03:00
|
|
|
if (!migration_is_idle() && !dev->allow_unplug_during_migration) {
|
2017-03-22 19:34:27 +03:00
|
|
|
error_setg(errp, "device_del not allowed while migrating");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-03-28 12:22:51 +03: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 15:28:47 +03:00
|
|
|
hotplug_handler_unplug_request(hotplug_ctrl, dev, &local_err);
|
2017-03-28 12:22:51 +03: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 15:28:47 +03:00
|
|
|
hotplug_handler_unplug(hotplug_ctrl, dev, &local_err);
|
|
|
|
if (!local_err) {
|
|
|
|
object_unparent(OBJECT(dev));
|
|
|
|
}
|
2017-03-28 12:22:51 +03: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 15:28:47 +03:00
|
|
|
error_propagate(errp, local_err);
|
2017-03-28 12:22:51 +03:00
|
|
|
}
|
|
|
|
|
2016-09-20 14:38:41 +03:00
|
|
|
void qmp_device_del(const char *id, Error **errp)
|
|
|
|
{
|
|
|
|
DeviceState *dev = find_device_state(id, errp);
|
|
|
|
if (dev != NULL) {
|
2020-02-20 19:55:56 +03:00
|
|
|
if (dev->pending_deleted_event) {
|
|
|
|
error_setg(errp, "Device %s is already in the "
|
|
|
|
"process of unplug", id);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-09-20 14:38:41 +03:00
|
|
|
qdev_unplug(dev, errp);
|
|
|
|
}
|
2011-12-23 01:24:20 +04:00
|
|
|
}
|
|
|
|
|
2019-07-09 21:59:36 +03:00
|
|
|
void hmp_device_add(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
qmp_device_add((QDict *)qdict, NULL, &err);
|
2019-12-05 20:46:18 +03:00
|
|
|
hmp_handle_error(mon, err);
|
2019-07-09 21:59:36 +03: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-05 20:46:18 +03:00
|
|
|
hmp_handle_error(mon, err);
|
2019-07-09 21:59:36 +03:00
|
|
|
}
|
|
|
|
|
2016-09-20 14:38:42 +03: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;
|
|
|
|
}
|
|
|
|
|
2012-11-26 19:03:42 +04: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 15:16:19 +03: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 14:50:26 +03:00
|
|
|
opts = qemu_opts_parse_noisily(&qemu_global_opts, str, false);
|
2015-04-09 15:16:19 +03:00
|
|
|
if (!opts) {
|
2012-11-26 19:03:42 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|