Add element_info and element_size fields to PropertyInfo, and extend
qdev_prop_qapi_type() to derive QAPI types for array properties via
element_info->qapi_type->list.
Add typed list PropertyInfo definitions that replace the generic
qdev_prop_array. Each typed list PropertyInfo knows its element type
at compile time through the element_info and element_size fields,
which allows the QAPI type to be derived automatically.
Infrastructure changes:
- Add prop_array_info() and prop_array_elem_size() helpers that
prefer the new element_info/element_size fields with fallback to
the old arrayinfo/arrayfieldsize fields for compatibility
- Make get_prop_array, set_prop_array, release_prop_array, and
default_prop_array non-static so they can be used by
DEFINE_PROP_ARRAY_INFO in other translation units
- Add DEFINE_PROP_ARRAY_INFO macro in qdev-prop-internal.h
The array of links needs special care for its "full type name" to follow
the "link<TYPE>List" pattern used by link properties ("link<TYPE>").
The old qdev_prop_array and DEFINE_PROP_ARRAY macro are preserved
for compatibility; they will be replaced in the next patch.
Signed-off-by: Marc-André Lureau <[email protected]>
---
hw/core/qdev-prop-internal.h | 18 ++++++
include/hw/core/qdev-properties-system.h | 2 +
include/hw/core/qdev-properties.h | 8 +++
hw/core/qdev-properties-system.c | 5 ++
hw/core/qdev-properties.c | 103 ++++++++++++++++++++++++-------
5 files changed, 115 insertions(+), 21 deletions(-)
diff --git a/hw/core/qdev-prop-internal.h b/hw/core/qdev-prop-internal.h
index c190b7b88cf..b9d9812346d 100644
--- a/hw/core/qdev-prop-internal.h
+++ b/hw/core/qdev-prop-internal.h
@@ -27,4 +27,22 @@ void qdev_propinfo_get_int32(Object *obj, Visitor *v, const
char *name,
void qdev_propinfo_get_size32(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp);
+void get_prop_array(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp);
+void set_prop_array(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp);
+void release_prop_array(Object *obj, const char *name, void *opaque);
+void default_prop_array(ObjectProperty *op, const Property *prop);
+
+/* .qapi_type is derived from element_info->qapi_type->list by
qdev_prop_qapi_type() */
+#define DEFINE_PROP_ARRAY_INFO(_elem_prop_info, _elem_type) \
+ { \
+ .element_info = &(_elem_prop_info), \
+ .element_size = sizeof(_elem_type), \
+ .get = get_prop_array, \
+ .set = set_prop_array, \
+ .release = release_prop_array, \
+ .set_default_value = default_prop_array, \
+ }
+
#endif
diff --git a/include/hw/core/qdev-properties-system.h
b/include/hw/core/qdev-properties-system.h
index 2cbea16d615..819dce7d5e5 100644
--- a/include/hw/core/qdev-properties-system.h
+++ b/include/hw/core/qdev-properties-system.h
@@ -23,6 +23,8 @@ extern const PropertyInfo qdev_prop_fdc_drive_type;
extern const PropertyInfo qdev_prop_drive;
extern const PropertyInfo qdev_prop_drive_iothread;
extern const PropertyInfo qdev_prop_netdev;
+extern const PropertyInfo qdev_prop_netdev_list;
+extern const PropertyInfo qdev_prop_reserved_region_list;
extern const PropertyInfo qdev_prop_pci_devfn;
extern const PropertyInfo qdev_prop_blocksize;
extern const PropertyInfo qdev_prop_pci_host_devaddr;
diff --git a/include/hw/core/qdev-properties.h
b/include/hw/core/qdev-properties.h
index 1ea2ba66bb3..0c067170079 100644
--- a/include/hw/core/qdev-properties.h
+++ b/include/hw/core/qdev-properties.h
@@ -35,6 +35,8 @@ struct PropertyInfo {
const char *description;
const QEnumLookup *enum_table;
const QAPITypeInfo *qapi_type;
+ const struct PropertyInfo *element_info;
+ int element_size;
bool realized_set_allowed; /* allow setting property on realized device */
char *(*print)(Object *obj, const Property *prop);
void (*set_default_value)(ObjectProperty *op, const Property *prop);
@@ -75,7 +77,13 @@ extern const PropertyInfo qdev_prop_string;
extern const PropertyInfo qdev_prop_on_off_auto;
extern const PropertyInfo qdev_prop_size32;
extern const PropertyInfo qdev_prop_array;
+extern const PropertyInfo qdev_prop_uint8_list;
+extern const PropertyInfo qdev_prop_uint16_list;
+extern const PropertyInfo qdev_prop_uint32_list;
+extern const PropertyInfo qdev_prop_uint64_list;
+extern const PropertyInfo qdev_prop_string_list;
extern const PropertyInfo qdev_prop_link;
+extern const PropertyInfo qdev_prop_link_list;
#define DEFINE_PROP(_name, _state, _field, _prop, _type, ...) { \
.name = (_name), \
diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
index 12be7b80a59..81f37ec44b2 100644
--- a/hw/core/qdev-properties-system.c
+++ b/hw/core/qdev-properties-system.c
@@ -484,6 +484,8 @@ const PropertyInfo qdev_prop_netdev = {
.set = set_netdev,
};
+const PropertyInfo qdev_prop_netdev_list =
+ DEFINE_PROP_ARRAY_INFO(qdev_prop_netdev, NICPeers);
/* --- audiodev --- */
static void get_audiodev(Object *obj, Visitor *v, const char* name,
@@ -822,6 +824,9 @@ const PropertyInfo qdev_prop_reserved_region = {
.set = set_reserved_region,
};
+const PropertyInfo qdev_prop_reserved_region_list =
+ DEFINE_PROP_ARRAY_INFO(qdev_prop_reserved_region, ReservedRegion);
+
/* --- pci address --- */
/*
diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c
index c2980c36afa..a9ca8e4a03d 100644
--- a/hw/core/qdev-properties.c
+++ b/hw/core/qdev-properties.c
@@ -665,6 +665,22 @@ struct ArrayElementList {
void *value;
};
+static const PropertyInfo *prop_array_info(const Property *prop)
+{
+ if (prop->info->element_info) {
+ return prop->info->element_info;
+ }
+ return prop->arrayinfo;
+}
+
+static int prop_array_elem_size(const Property *prop)
+{
+ if (prop->info->element_size) {
+ return prop->info->element_size;
+ }
+ return prop->arrayfieldsize;
+}
+
/*
* Given an array property @parent_prop in @obj, return a Property for a
* specific element of the array. Arrays are backed by an uint32_t length field
@@ -674,7 +690,7 @@ static Property array_elem_prop(Object *obj, const Property
*parent_prop,
const char *name, char *elem)
{
return (Property) {
- .info = parent_prop->arrayinfo,
+ .info = prop_array_info(parent_prop),
.name = name,
/*
* This ugly piece of pointer arithmetic sets up the offset so
@@ -692,19 +708,21 @@ static Property array_elem_prop(Object *obj, const
Property *parent_prop,
* underlying element's property release hook for each element and free the
* property array.
*/
-static void release_prop_array(Object *obj, const char *name, void *opaque)
+void release_prop_array(Object *obj, const char *name, void *opaque)
{
const Property *prop = opaque;
uint32_t *alenptr = object_field_prop_ptr(obj, prop);
void **arrayptr = (void *)obj + prop->arrayoffset;
char *elem = *arrayptr;
int i;
+ const PropertyInfo *elem_info = prop_array_info(prop);
+ int elem_size = prop_array_elem_size(prop);
- if (prop->arrayinfo->release) {
+ if (elem_info->release) {
for (i = 0; i < *alenptr; i++) {
Property elem_prop = array_elem_prop(obj, prop, name, elem);
- prop->arrayinfo->release(obj, NULL, &elem_prop);
- elem += prop->arrayfieldsize;
+ elem_info->release(obj, NULL, &elem_prop);
+ elem += elem_size;
}
}
@@ -718,8 +736,8 @@ static void release_prop_array(Object *obj, const char
*name, void *opaque)
* (a pointer to which is stored in the additional field described by
* prop->arrayoffset).
*/
-static void set_prop_array(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
+void set_prop_array(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
{
ERRP_GUARD();
const Property *prop = opaque;
@@ -727,6 +745,8 @@ static void set_prop_array(Object *obj, Visitor *v, const
char *name,
void **arrayptr = (void *)obj + prop->arrayoffset;
ArrayElementList *list, *elem, *next;
const size_t size = sizeof(*list);
+ const PropertyInfo *elem_info = prop_array_info(prop);
+ int elem_size = prop_array_elem_size(prop);
char *elemptr;
bool ok = true;
@@ -745,9 +765,9 @@ static void set_prop_array(Object *obj, Visitor *v, const
char *name,
while (elem) {
Property elem_prop;
- elem->value = g_malloc0(prop->arrayfieldsize);
+ elem->value = g_malloc0(elem_size);
elem_prop = array_elem_prop(obj, prop, name, elem->value);
- prop->arrayinfo->set(obj, v, NULL, &elem_prop, errp);
+ elem_info->set(obj, v, NULL, &elem_prop, errp);
if (*errp) {
ok = false;
goto out_obj;
@@ -769,8 +789,8 @@ out_obj:
for (elem = list; elem; elem = next) {
Property elem_prop = array_elem_prop(obj, prop, name,
elem->value);
- if (prop->arrayinfo->release) {
- prop->arrayinfo->release(obj, NULL, &elem_prop);
+ if (elem_info->release) {
+ elem_info->release(obj, NULL, &elem_prop);
}
next = elem->next;
g_free(elem->value);
@@ -783,19 +803,19 @@ out_obj:
* Now that we know how big the array has to be, move the data over to a
* linear array and free the temporary list.
*/
- *arrayptr = g_malloc_n(*alenptr, prop->arrayfieldsize);
+ *arrayptr = g_malloc_n(*alenptr, elem_size);
elemptr = *arrayptr;
for (elem = list; elem; elem = next) {
- memcpy(elemptr, elem->value, prop->arrayfieldsize);
- elemptr += prop->arrayfieldsize;
+ memcpy(elemptr, elem->value, elem_size);
+ elemptr += elem_size;
next = elem->next;
g_free(elem->value);
g_free(elem);
}
}
-static void get_prop_array(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
+void get_prop_array(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
{
ERRP_GUARD();
const Property *prop = opaque;
@@ -805,6 +825,8 @@ static void get_prop_array(Object *obj, Visitor *v, const
char *name,
ArrayElementList *list = NULL, *elem;
ArrayElementList **tail = &list;
const size_t size = sizeof(*list);
+ const PropertyInfo *elem_info = prop_array_info(prop);
+ int elem_size = prop_array_elem_size(prop);
int i;
bool ok;
@@ -812,7 +834,7 @@ static void get_prop_array(Object *obj, Visitor *v, const
char *name,
for (i = 0; i < *alenptr; i++) {
elem = g_new0(ArrayElementList, 1);
elem->value = elemptr;
- elemptr += prop->arrayfieldsize;
+ elemptr += elem_size;
*tail = elem;
tail = &elem->next;
@@ -825,7 +847,7 @@ static void get_prop_array(Object *obj, Visitor *v, const
char *name,
elem = list;
while (elem) {
Property elem_prop = array_elem_prop(obj, prop, name, elem->value);
- prop->arrayinfo->get(obj, v, NULL, &elem_prop, errp);
+ elem_info->get(obj, v, NULL, &elem_prop, errp);
if (*errp) {
goto out_obj;
}
@@ -847,7 +869,7 @@ out_obj:
}
}
-static void default_prop_array(ObjectProperty *op, const Property *prop)
+void default_prop_array(ObjectProperty *op, const Property *prop)
{
object_property_set_default_list(op);
}
@@ -860,6 +882,38 @@ const PropertyInfo qdev_prop_array = {
.set_default_value = default_prop_array,
};
+const PropertyInfo qdev_prop_uint8_list =
+ DEFINE_PROP_ARRAY_INFO(qdev_prop_uint8, uint8_t);
+const PropertyInfo qdev_prop_uint16_list =
+ DEFINE_PROP_ARRAY_INFO(qdev_prop_uint16, uint16_t);
+const PropertyInfo qdev_prop_uint32_list =
+ DEFINE_PROP_ARRAY_INFO(qdev_prop_uint32, uint32_t);
+const PropertyInfo qdev_prop_uint64_list =
+ DEFINE_PROP_ARRAY_INFO(qdev_prop_uint64, uint64_t);
+const PropertyInfo qdev_prop_string_list =
+ DEFINE_PROP_ARRAY_INFO(qdev_prop_string, char *);
+
+static ObjectProperty *create_link_list_property(ObjectClass *oc,
+ const char *name,
+ const Property *prop)
+{
+ g_autofree char *full_type = g_strdup_printf("link<%s>List",
prop->link_type);
+
+ return object_class_property_add(oc, name, full_type,
+ get_prop_array, set_prop_array,
+ release_prop_array, (Property *)prop);
+}
+
+const PropertyInfo qdev_prop_link_list = {
+ .element_info = &qdev_prop_link,
+ .element_size = sizeof(void *),
+ .create = create_link_list_property,
+ .get = get_prop_array,
+ .set = set_prop_array,
+ .release = release_prop_array,
+ .set_default_value = default_prop_array,
+};
+
/* --- public helpers --- */
static const Property *qdev_prop_walk(DeviceClass *cls, const char *name)
@@ -1158,8 +1212,15 @@ const PropertyInfo qdev_prop_link = {
static const QAPITypeInfo *qdev_prop_qapi_type(const Property *prop)
{
- /* this will be later extended to cope with QAPI array properties */
- return prop->info->qapi_type;
+ if (prop->info->qapi_type) {
+ return prop->info->qapi_type;
+ }
+ if (prop->info->element_info) {
+ assert(prop->info->element_info->qapi_type);
+ assert(prop->info->element_info->qapi_type->list);
+ return prop->info->element_info->qapi_type->list;
+ }
+ return NULL;
}
void qdev_property_add_static(DeviceState *dev, const Property *prop)
--
2.54.0