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 New typed list PropertyInfos: - qdev_prop_uint8_list, qdev_prop_uint16_list, qdev_prop_uint32_list, qdev_prop_uint64_list, qdev_prop_string_list (in qdev-properties.c) - qdev_prop_netdev_list, qdev_prop_reserved_region_list (in qdev-properties-system.c) 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 | 7 +++ hw/core/qdev-properties-system.c | 5 ++ hw/core/qdev-properties.c | 82 ++++++++++++++++++++++++-------- 5 files changed, 93 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 441f77a501d..14db07cf9f4 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,6 +77,11 @@ 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; #define DEFINE_PROP(_name, _state, _field, _prop, _type, ...) { \ 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 5edcca42056..2860de1d010 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 @@ -691,19 +707,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; } } @@ -717,8 +735,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; @@ -726,6 +744,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; @@ -744,9 +764,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; @@ -768,8 +788,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); @@ -782,19 +802,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; @@ -804,6 +824,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; @@ -811,7 +833,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; @@ -824,7 +846,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; } @@ -846,7 +868,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); } @@ -859,6 +881,17 @@ 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 *); + /* --- public helpers --- */ static const Property *qdev_prop_walk(DeviceClass *cls, const char *name) @@ -1080,8 +1113,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
