mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-04 08:13:54 -06:00
Merge remote-tracking branch 'afaerber-or/qom-next-2' into staging
* afaerber-or/qom-next-2: (22 commits) qom: Push error reporting to object_property_find() qdev: Remove qdev_prop_exists() qbus: Initialize in standard way qbus: Make child devices links qdev: Connect busses with their parent devices qdev: Convert busses to QEMU Object Model qdev: Move SysBus initialization to sysbus.c qdev: Use wrapper for qdev_get_path qdev: Remove qdev_prop_set_defaults qdev: Clean up global properties qdev: Move bus properties to abstract superclasses qdev: Move bus properties to a separate global qdev: Push "type" property up to Object arm_l2x0: Rename "type" property to "cache-type" m48t59: Rename "type" property to "model" qom: Assert that public types have a non-NULL parent field qom: Drop type_register_static_alias() macro qom: Make Object a type qom: Add class_base_init qom: Add object_child_foreach() ...
This commit is contained in:
commit
8aca521512
41 changed files with 869 additions and 503 deletions
302
hw/qdev.c
302
hw/qdev.c
|
@ -34,10 +34,6 @@ int qdev_hotplug = 0;
|
|||
static bool qdev_hot_added = false;
|
||||
static bool qdev_hot_removed = false;
|
||||
|
||||
/* This is a nasty hack to allow passing a NULL bus to qdev_create. */
|
||||
static BusState *main_system_bus;
|
||||
static void main_system_bus_create(void);
|
||||
|
||||
/* Register a new device type. */
|
||||
const VMStateDescription *qdev_get_vmsd(DeviceState *dev)
|
||||
{
|
||||
|
@ -45,18 +41,6 @@ const VMStateDescription *qdev_get_vmsd(DeviceState *dev)
|
|||
return dc->vmsd;
|
||||
}
|
||||
|
||||
BusInfo *qdev_get_bus_info(DeviceState *dev)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_GET_CLASS(dev);
|
||||
return dc->bus_info;
|
||||
}
|
||||
|
||||
Property *qdev_get_props(DeviceState *dev)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_GET_CLASS(dev);
|
||||
return dc->props;
|
||||
}
|
||||
|
||||
const char *qdev_fw_name(DeviceState *dev)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_GET_CLASS(dev);
|
||||
|
@ -76,22 +60,48 @@ bool qdev_exists(const char *name)
|
|||
static void qdev_property_add_legacy(DeviceState *dev, Property *prop,
|
||||
Error **errp);
|
||||
|
||||
void qdev_set_parent_bus(DeviceState *dev, BusState *bus)
|
||||
static void bus_remove_child(BusState *bus, DeviceState *child)
|
||||
{
|
||||
Property *prop;
|
||||
BusChild *kid;
|
||||
|
||||
QTAILQ_FOREACH(kid, &bus->children, sibling) {
|
||||
if (kid->child == child) {
|
||||
char name[32];
|
||||
|
||||
snprintf(name, sizeof(name), "child[%d]", kid->index);
|
||||
QTAILQ_REMOVE(&bus->children, kid, sibling);
|
||||
object_property_del(OBJECT(bus), name, NULL);
|
||||
g_free(kid);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void bus_add_child(BusState *bus, DeviceState *child)
|
||||
{
|
||||
char name[32];
|
||||
BusChild *kid = g_malloc0(sizeof(*kid));
|
||||
|
||||
if (qdev_hotplug) {
|
||||
assert(bus->allow_hotplug);
|
||||
}
|
||||
|
||||
dev->parent_bus = bus;
|
||||
QTAILQ_INSERT_HEAD(&bus->children, dev, sibling);
|
||||
kid->index = bus->max_index++;
|
||||
kid->child = child;
|
||||
|
||||
for (prop = qdev_get_bus_info(dev)->props; prop && prop->name; prop++) {
|
||||
qdev_property_add_legacy(dev, prop, NULL);
|
||||
qdev_property_add_static(dev, prop, NULL);
|
||||
}
|
||||
qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
|
||||
QTAILQ_INSERT_HEAD(&bus->children, kid, sibling);
|
||||
|
||||
snprintf(name, sizeof(name), "child[%d]", kid->index);
|
||||
object_property_add_link(OBJECT(bus), name,
|
||||
object_get_typename(OBJECT(child)),
|
||||
(Object **)&kid->child,
|
||||
NULL);
|
||||
}
|
||||
|
||||
void qdev_set_parent_bus(DeviceState *dev, BusState *bus)
|
||||
{
|
||||
dev->parent_bus = bus;
|
||||
bus_add_child(bus, dev);
|
||||
}
|
||||
|
||||
/* Create a new device. This only initializes the device state structure
|
||||
|
@ -105,7 +115,7 @@ DeviceState *qdev_create(BusState *bus, const char *name)
|
|||
if (!dev) {
|
||||
if (bus) {
|
||||
hw_error("Unknown device '%s' for bus '%s'\n", name,
|
||||
bus->info->name);
|
||||
object_get_typename(OBJECT(bus)));
|
||||
} else {
|
||||
hw_error("Unknown device '%s' for default sysbus\n", name);
|
||||
}
|
||||
|
@ -131,7 +141,6 @@ DeviceState *qdev_try_create(BusState *bus, const char *type)
|
|||
}
|
||||
|
||||
qdev_set_parent_bus(dev, bus);
|
||||
qdev_prop_set_globals(dev);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
@ -210,18 +219,11 @@ static int qdev_reset_one(DeviceState *dev, void *opaque)
|
|||
return 0;
|
||||
}
|
||||
|
||||
BusState *sysbus_get_default(void)
|
||||
{
|
||||
if (!main_system_bus) {
|
||||
main_system_bus_create();
|
||||
}
|
||||
return main_system_bus;
|
||||
}
|
||||
|
||||
static int qbus_reset_one(BusState *bus, void *opaque)
|
||||
{
|
||||
if (bus->info->reset) {
|
||||
return bus->info->reset(bus);
|
||||
BusClass *bc = BUS_GET_CLASS(bus);
|
||||
if (bc->reset) {
|
||||
return bc->reset(bus);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -322,7 +324,7 @@ void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
|
|||
if (nd->netdev)
|
||||
qdev_prop_set_netdev(dev, "netdev", nd->netdev);
|
||||
if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED &&
|
||||
qdev_prop_exists(dev, "vectors")) {
|
||||
object_property_find(OBJECT(dev), "vectors", NULL)) {
|
||||
qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
|
||||
}
|
||||
nd->instantiated = 1;
|
||||
|
@ -343,7 +345,7 @@ BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
|
|||
int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn,
|
||||
qbus_walkerfn *busfn, void *opaque)
|
||||
{
|
||||
DeviceState *dev;
|
||||
BusChild *kid;
|
||||
int err;
|
||||
|
||||
if (busfn) {
|
||||
|
@ -353,8 +355,8 @@ int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn,
|
|||
}
|
||||
}
|
||||
|
||||
QTAILQ_FOREACH(dev, &bus->children, sibling) {
|
||||
err = qdev_walk_children(dev, devfn, busfn, opaque);
|
||||
QTAILQ_FOREACH(kid, &bus->children, sibling) {
|
||||
err = qdev_walk_children(kid->child, devfn, busfn, opaque);
|
||||
if (err < 0) {
|
||||
return err;
|
||||
}
|
||||
|
@ -388,12 +390,17 @@ int qdev_walk_children(DeviceState *dev, qdev_walkerfn *devfn,
|
|||
|
||||
DeviceState *qdev_find_recursive(BusState *bus, const char *id)
|
||||
{
|
||||
DeviceState *dev, *ret;
|
||||
BusChild *kid;
|
||||
DeviceState *ret;
|
||||
BusState *child;
|
||||
|
||||
QTAILQ_FOREACH(dev, &bus->children, sibling) {
|
||||
if (dev->id && strcmp(dev->id, id) == 0)
|
||||
QTAILQ_FOREACH(kid, &bus->children, sibling) {
|
||||
DeviceState *dev = kid->child;
|
||||
|
||||
if (dev->id && strcmp(dev->id, id) == 0) {
|
||||
return dev;
|
||||
}
|
||||
|
||||
QLIST_FOREACH(child, &dev->child_bus, sibling) {
|
||||
ret = qdev_find_recursive(child, id);
|
||||
if (ret) {
|
||||
|
@ -404,84 +411,87 @@ DeviceState *qdev_find_recursive(BusState *bus, const char *id)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
void qbus_create_inplace(BusState *bus, BusInfo *info,
|
||||
DeviceState *parent, const char *name)
|
||||
static void qbus_realize(BusState *bus)
|
||||
{
|
||||
const char *typename = object_get_typename(OBJECT(bus));
|
||||
char *buf;
|
||||
int i,len;
|
||||
|
||||
bus->info = info;
|
||||
bus->parent = parent;
|
||||
|
||||
if (name) {
|
||||
if (bus->name) {
|
||||
/* use supplied name */
|
||||
bus->name = g_strdup(name);
|
||||
} else if (parent && parent->id) {
|
||||
} else if (bus->parent && bus->parent->id) {
|
||||
/* parent device has id -> use it for bus name */
|
||||
len = strlen(parent->id) + 16;
|
||||
len = strlen(bus->parent->id) + 16;
|
||||
buf = g_malloc(len);
|
||||
snprintf(buf, len, "%s.%d", parent->id, parent->num_child_bus);
|
||||
snprintf(buf, len, "%s.%d", bus->parent->id, bus->parent->num_child_bus);
|
||||
bus->name = buf;
|
||||
} else {
|
||||
/* no id -> use lowercase bus type for bus name */
|
||||
len = strlen(info->name) + 16;
|
||||
len = strlen(typename) + 16;
|
||||
buf = g_malloc(len);
|
||||
len = snprintf(buf, len, "%s.%d", info->name,
|
||||
parent ? parent->num_child_bus : 0);
|
||||
len = snprintf(buf, len, "%s.%d", typename,
|
||||
bus->parent ? bus->parent->num_child_bus : 0);
|
||||
for (i = 0; i < len; i++)
|
||||
buf[i] = qemu_tolower(buf[i]);
|
||||
bus->name = buf;
|
||||
}
|
||||
|
||||
QTAILQ_INIT(&bus->children);
|
||||
if (parent) {
|
||||
QLIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
|
||||
parent->num_child_bus++;
|
||||
} else if (bus != main_system_bus) {
|
||||
if (bus->parent) {
|
||||
QLIST_INSERT_HEAD(&bus->parent->child_bus, bus, sibling);
|
||||
bus->parent->num_child_bus++;
|
||||
object_property_add_child(OBJECT(bus->parent), bus->name, OBJECT(bus), NULL);
|
||||
} else if (bus != sysbus_get_default()) {
|
||||
/* TODO: once all bus devices are qdevified,
|
||||
only reset handler for main_system_bus should be registered here. */
|
||||
qemu_register_reset(qbus_reset_all_fn, bus);
|
||||
}
|
||||
}
|
||||
|
||||
BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
|
||||
void qbus_create_inplace(BusState *bus, const char *typename,
|
||||
DeviceState *parent, const char *name)
|
||||
{
|
||||
object_initialize(bus, typename);
|
||||
|
||||
bus->parent = parent;
|
||||
bus->name = name ? g_strdup(name) : NULL;
|
||||
qbus_realize(bus);
|
||||
}
|
||||
|
||||
BusState *qbus_create(const char *typename, DeviceState *parent, const char *name)
|
||||
{
|
||||
BusState *bus;
|
||||
|
||||
bus = g_malloc0(info->size);
|
||||
bus->qdev_allocated = 1;
|
||||
qbus_create_inplace(bus, info, parent, name);
|
||||
return bus;
|
||||
}
|
||||
bus = BUS(object_new(typename));
|
||||
bus->qom_allocated = true;
|
||||
|
||||
static void main_system_bus_create(void)
|
||||
{
|
||||
/* assign main_system_bus before qbus_create_inplace()
|
||||
* in order to make "if (bus != main_system_bus)" work */
|
||||
main_system_bus = g_malloc0(system_bus_info.size);
|
||||
main_system_bus->qdev_allocated = 1;
|
||||
qbus_create_inplace(main_system_bus, &system_bus_info, NULL,
|
||||
"main-system-bus");
|
||||
bus->parent = parent;
|
||||
bus->name = name ? g_strdup(name) : NULL;
|
||||
qbus_realize(bus);
|
||||
|
||||
return bus;
|
||||
}
|
||||
|
||||
void qbus_free(BusState *bus)
|
||||
{
|
||||
DeviceState *dev;
|
||||
|
||||
while ((dev = QTAILQ_FIRST(&bus->children)) != NULL) {
|
||||
qdev_free(dev);
|
||||
}
|
||||
if (bus->parent) {
|
||||
QLIST_REMOVE(bus, sibling);
|
||||
bus->parent->num_child_bus--;
|
||||
if (bus->qom_allocated) {
|
||||
object_delete(OBJECT(bus));
|
||||
} else {
|
||||
assert(bus != main_system_bus); /* main_system_bus is never freed */
|
||||
qemu_unregister_reset(qbus_reset_all_fn, bus);
|
||||
object_finalize(OBJECT(bus));
|
||||
if (bus->glib_allocated) {
|
||||
g_free(bus);
|
||||
}
|
||||
}
|
||||
g_free((void*)bus->name);
|
||||
if (bus->qdev_allocated) {
|
||||
g_free(bus);
|
||||
}
|
||||
|
||||
static char *bus_get_fw_dev_path(BusState *bus, DeviceState *dev)
|
||||
{
|
||||
BusClass *bc = BUS_GET_CLASS(bus);
|
||||
|
||||
if (bc->get_fw_dev_path) {
|
||||
return bc->get_fw_dev_path(dev);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int qdev_get_fw_dev_path_helper(DeviceState *dev, char *p, int size)
|
||||
|
@ -491,8 +501,8 @@ static int qdev_get_fw_dev_path_helper(DeviceState *dev, char *p, int size)
|
|||
if (dev && dev->parent_bus) {
|
||||
char *d;
|
||||
l = qdev_get_fw_dev_path_helper(dev->parent_bus->parent, p, size);
|
||||
if (dev->parent_bus->info->get_fw_dev_path) {
|
||||
d = dev->parent_bus->info->get_fw_dev_path(dev);
|
||||
d = bus_get_fw_dev_path(dev->parent_bus, dev);
|
||||
if (d) {
|
||||
l += snprintf(p + l, size - l, "%s", d);
|
||||
g_free(d);
|
||||
} else {
|
||||
|
@ -516,9 +526,20 @@ char* qdev_get_fw_dev_path(DeviceState *dev)
|
|||
return strdup(path);
|
||||
}
|
||||
|
||||
static char *qdev_get_type(Object *obj, Error **errp)
|
||||
char *qdev_get_dev_path(DeviceState *dev)
|
||||
{
|
||||
return g_strdup(object_get_typename(obj));
|
||||
BusClass *bc;
|
||||
|
||||
if (!dev || !dev->parent_bus) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bc = BUS_GET_CLASS(dev->parent_bus);
|
||||
if (bc->get_dev_path) {
|
||||
return bc->get_dev_path(dev);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -606,6 +627,9 @@ void qdev_property_add_legacy(DeviceState *dev, Property *prop,
|
|||
void qdev_property_add_static(DeviceState *dev, Property *prop,
|
||||
Error **errp)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
Object *obj = OBJECT(dev);
|
||||
|
||||
/*
|
||||
* TODO qdev_prop_ptr does not have getters or setters. It must
|
||||
* go now that it can be replaced with links. The test should be
|
||||
|
@ -615,15 +639,34 @@ void qdev_property_add_static(DeviceState *dev, Property *prop,
|
|||
return;
|
||||
}
|
||||
|
||||
object_property_add(OBJECT(dev), prop->name, prop->info->name,
|
||||
object_property_add(obj, prop->name, prop->info->name,
|
||||
prop->info->get, prop->info->set,
|
||||
prop->info->release,
|
||||
prop, errp);
|
||||
prop, &local_err);
|
||||
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
if (prop->qtype == QTYPE_NONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (prop->qtype == QTYPE_QBOOL) {
|
||||
object_property_set_bool(obj, prop->defval, prop->name, &local_err);
|
||||
} else if (prop->info->enum_table) {
|
||||
object_property_set_str(obj, prop->info->enum_table[prop->defval],
|
||||
prop->name, &local_err);
|
||||
} else if (prop->qtype == QTYPE_QINT) {
|
||||
object_property_set_int(obj, prop->defval, prop->name, &local_err);
|
||||
}
|
||||
assert_no_error(local_err);
|
||||
}
|
||||
|
||||
static void device_initfn(Object *obj)
|
||||
{
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
ObjectClass *class;
|
||||
Property *prop;
|
||||
|
||||
if (qdev_hotplug) {
|
||||
|
@ -634,13 +677,18 @@ static void device_initfn(Object *obj)
|
|||
dev->instance_id_alias = -1;
|
||||
dev->state = DEV_STATE_CREATED;
|
||||
|
||||
for (prop = qdev_get_props(dev); prop && prop->name; prop++) {
|
||||
qdev_property_add_legacy(dev, prop, NULL);
|
||||
qdev_property_add_static(dev, prop, NULL);
|
||||
}
|
||||
class = object_get_class(OBJECT(dev));
|
||||
do {
|
||||
for (prop = DEVICE_CLASS(class)->props; prop && prop->name; prop++) {
|
||||
qdev_property_add_legacy(dev, prop, NULL);
|
||||
qdev_property_add_static(dev, prop, NULL);
|
||||
}
|
||||
class = object_class_get_parent(class);
|
||||
} while (class != object_class_by_name(TYPE_DEVICE));
|
||||
qdev_prop_set_globals(dev);
|
||||
|
||||
object_property_add_str(OBJECT(dev), "type", qdev_get_type, NULL, NULL);
|
||||
qdev_prop_set_defaults(dev, qdev_get_props(dev));
|
||||
object_property_add_link(OBJECT(dev), "parent_bus", TYPE_BUS,
|
||||
(Object **)&dev->parent_bus, NULL);
|
||||
}
|
||||
|
||||
/* Unlink device from bus and free the structure. */
|
||||
|
@ -665,7 +713,19 @@ static void device_finalize(Object *obj)
|
|||
qemu_opts_del(dev->opts);
|
||||
}
|
||||
}
|
||||
QTAILQ_REMOVE(&dev->parent_bus->children, dev, sibling);
|
||||
if (dev->parent_bus) {
|
||||
bus_remove_child(dev->parent_bus, dev);
|
||||
}
|
||||
}
|
||||
|
||||
static void device_class_base_init(ObjectClass *class, void *data)
|
||||
{
|
||||
DeviceClass *klass = DEVICE_CLASS(class);
|
||||
|
||||
/* We explicitly look up properties in the superclasses,
|
||||
* so do not propagate them to the subclasses.
|
||||
*/
|
||||
klass->props = NULL;
|
||||
}
|
||||
|
||||
void device_reset(DeviceState *dev)
|
||||
|
@ -694,12 +754,50 @@ static TypeInfo device_type_info = {
|
|||
.instance_size = sizeof(DeviceState),
|
||||
.instance_init = device_initfn,
|
||||
.instance_finalize = device_finalize,
|
||||
.class_base_init = device_class_base_init,
|
||||
.abstract = true,
|
||||
.class_size = sizeof(DeviceClass),
|
||||
};
|
||||
|
||||
static void qbus_initfn(Object *obj)
|
||||
{
|
||||
BusState *bus = BUS(obj);
|
||||
|
||||
QTAILQ_INIT(&bus->children);
|
||||
}
|
||||
|
||||
static void qbus_finalize(Object *obj)
|
||||
{
|
||||
BusState *bus = BUS(obj);
|
||||
BusChild *kid;
|
||||
|
||||
while ((kid = QTAILQ_FIRST(&bus->children)) != NULL) {
|
||||
DeviceState *dev = kid->child;
|
||||
qdev_free(dev);
|
||||
}
|
||||
if (bus->parent) {
|
||||
QLIST_REMOVE(bus, sibling);
|
||||
bus->parent->num_child_bus--;
|
||||
} else {
|
||||
assert(bus != sysbus_get_default()); /* main_system_bus is never freed */
|
||||
qemu_unregister_reset(qbus_reset_all_fn, bus);
|
||||
}
|
||||
g_free((char *)bus->name);
|
||||
}
|
||||
|
||||
static const TypeInfo bus_info = {
|
||||
.name = TYPE_BUS,
|
||||
.parent = TYPE_OBJECT,
|
||||
.instance_size = sizeof(BusState),
|
||||
.abstract = true,
|
||||
.class_size = sizeof(BusClass),
|
||||
.instance_init = qbus_initfn,
|
||||
.instance_finalize = qbus_finalize,
|
||||
};
|
||||
|
||||
static void qdev_register_types(void)
|
||||
{
|
||||
type_register_static(&bus_info);
|
||||
type_register_static(&device_type_info);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue