aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Hajnoczi <stefanha@redhat.com>2023-11-11 11:23:25 +0800
committerStefan Hajnoczi <stefanha@redhat.com>2023-11-11 11:23:25 +0800
commit69680740eafa1838527c90155a7432d51b8ff203 (patch)
tree7e57b28a47c33f73a7cfa8a8f12f406955480419
parentea10c3817814b8be75be22c78ea91d633b0d2532 (diff)
parentb06f8b500da2a5a73dfb15de17cd96ad2385fdc7 (diff)
Merge tag 'qdev-array-prop' of https://repo.or.cz/qemu/kevin into staging
qdev: Make array properties user accessible again # -----BEGIN PGP SIGNATURE----- # # iQJFBAABCAAvFiEE3D3rFZqa+V09dFb+fwmycsiPL9YFAmVOZicRHGt3b2xmQHJl # ZGhhdC5jb20ACgkQfwmycsiPL9arpw/+NKGRhSMrSq9Az+z5+ANUfw5SNLJYf1hH # jm5ITA1Gr9htqHtBfEOdkms2wef6m7onF72rHVUlBKdqCPNMGLme5B0oQ8PZ1X1t # OxAZ8KYwlO98QvOYl617SA/8wxc0U4/zi192kJpbRkKF6KdbbMGtLKjHyEitA/Yv # izx1vkKOgQyMFGF1JgIyG4R3WmsKQW1XLqb3emVNRzCqmJpkvMJZQG8tnyEAXlIS # gkY69cTpaKVaM1OxdB45gjlKTGzLWC/3tTGH+u8q356fvgm/QIgrokCirCZFPIl0 # C8hvzPm/L8hkvWtUb3EZx0DLiunWcAGvoLgBNODHojKRtQ6X9TRTrjJ41ZCLXVqv # tVJm+XGKC0CZ/WW5yqVOmnzfPH4z8ubzSoRv5ryz3xDb5B/Zr10+ScE+/Ee24wJ2 # HIehxc1LgVGGpikP88/Ns/nAlIVUQxxYvSJ23R5D1+UpP6FCy6Y1pKyRtZGzPCIe # N4Y+52GtelBR8gOjay5INn/Yf8Fh6sFxX556BW0XKYcbQgvl2bxASe/KVnAVZ1NB # 8DsaAWlK+hPGopwyp2lDRuGd4kusNbzQvIUZ0mr1g9HQ/iSnT/9RFdExsj+K6QTr # pX42QCe4mWHPAKx38cez+Bhx4TEOw+GmHuTp/oLdBRuY8DPu/I0Ny364uiW+At/R # 8jF+jt5uVZc= # =MV6O # -----END PGP SIGNATURE----- # gpg: Signature made Sat 11 Nov 2023 01:19:35 HKT # gpg: using RSA key DC3DEB159A9AF95D3D7456FE7F09B272C88F2FD6 # gpg: issuer "kwolf@redhat.com" # gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>" [full] # Primary key fingerprint: DC3D EB15 9A9A F95D 3D74 56FE 7F09 B272 C88F 2FD6 * tag 'qdev-array-prop' of https://repo.or.cz/qemu/kevin: qdev: Rework array properties based on list visitor qdev: Make netdev properties work as list elements qom: Add object_property_set_default_list() hw/rx/rx62n: Use qdev_prop_set_array() hw/arm/xlnx-versal: Use qdev_prop_set_array() hw/arm/virt: Use qdev_prop_set_array() hw/arm/vexpress: Use qdev_prop_set_array() hw/arm/sbsa-ref: Use qdev_prop_set_array() hw/arm/mps2: Use qdev_prop_set_array() hw/arm/mps2-tz: Use qdev_prop_set_array() hw/i386/pc: Use qdev_prop_set_array() Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
-rw-r--r--hw/arm/mps2-tz.c10
-rw-r--r--hw/arm/mps2.c12
-rw-r--r--hw/arm/sbsa-ref.c7
-rw-r--r--hw/arm/vexpress.c21
-rw-r--r--hw/arm/virt.c31
-rw-r--r--hw/arm/xlnx-versal.c9
-rw-r--r--hw/core/qdev-properties-system.c2
-rw-r--r--hw/core/qdev-properties.c237
-rw-r--r--hw/i386/pc.c8
-rw-r--r--hw/rx/rx62n.c19
-rw-r--r--include/hw/qdev-properties.h35
-rw-r--r--include/qom/object.h8
-rw-r--r--qom/object.c6
13 files changed, 257 insertions, 148 deletions
diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c
index eae3639da2..668db5ed61 100644
--- a/hw/arm/mps2-tz.c
+++ b/hw/arm/mps2-tz.c
@@ -48,6 +48,7 @@
#include "qemu/units.h"
#include "qemu/cutils.h"
#include "qapi/error.h"
+#include "qapi/qmp/qlist.h"
#include "qemu/error-report.h"
#include "hw/arm/boot.h"
#include "hw/arm/armv7m.h"
@@ -461,6 +462,7 @@ static MemoryRegion *make_scc(MPS2TZMachineState *mms, void *opaque,
MPS2SCC *scc = opaque;
DeviceState *sccdev;
MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_GET_CLASS(mms);
+ QList *oscclk;
uint32_t i;
object_initialize_child(OBJECT(mms), "scc", scc, TYPE_MPS2_SCC);
@@ -469,11 +471,13 @@ static MemoryRegion *make_scc(MPS2TZMachineState *mms, void *opaque,
qdev_prop_set_uint32(sccdev, "scc-cfg4", 0x2);
qdev_prop_set_uint32(sccdev, "scc-aid", 0x00200008);
qdev_prop_set_uint32(sccdev, "scc-id", mmc->scc_id);
- qdev_prop_set_uint32(sccdev, "len-oscclk", mmc->len_oscclk);
+
+ oscclk = qlist_new();
for (i = 0; i < mmc->len_oscclk; i++) {
- g_autofree char *propname = g_strdup_printf("oscclk[%u]", i);
- qdev_prop_set_uint32(sccdev, propname, mmc->oscclk[i]);
+ qlist_append_int(oscclk, mmc->oscclk[i]);
}
+ qdev_prop_set_array(sccdev, "oscclk", oscclk);
+
sysbus_realize(SYS_BUS_DEVICE(scc), &error_fatal);
return sysbus_mmio_get_region(SYS_BUS_DEVICE(sccdev), 0);
}
diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c
index d92fd60684..292a180ad2 100644
--- a/hw/arm/mps2.c
+++ b/hw/arm/mps2.c
@@ -48,6 +48,7 @@
#include "net/net.h"
#include "hw/watchdog/cmsdk-apb-watchdog.h"
#include "hw/qdev-clock.h"
+#include "qapi/qmp/qlist.h"
#include "qom/object.h"
typedef enum MPS2FPGAType {
@@ -138,6 +139,7 @@ static void mps2_common_init(MachineState *machine)
MemoryRegion *system_memory = get_system_memory();
MachineClass *mc = MACHINE_GET_CLASS(machine);
DeviceState *armv7m, *sccdev;
+ QList *oscclk;
int i;
if (strcmp(machine->cpu_type, mc->default_cpu_type) != 0) {
@@ -402,10 +404,12 @@ static void mps2_common_init(MachineState *machine)
qdev_prop_set_uint32(sccdev, "scc-aid", 0x00200008);
qdev_prop_set_uint32(sccdev, "scc-id", mmc->scc_id);
/* All these FPGA images have the same OSCCLK configuration */
- qdev_prop_set_uint32(sccdev, "len-oscclk", 3);
- qdev_prop_set_uint32(sccdev, "oscclk[0]", 50000000);
- qdev_prop_set_uint32(sccdev, "oscclk[1]", 24576000);
- qdev_prop_set_uint32(sccdev, "oscclk[2]", 25000000);
+ oscclk = qlist_new();
+ qlist_append_int(oscclk, 50000000);
+ qlist_append_int(oscclk, 24576000);
+ qlist_append_int(oscclk, 25000000);
+ qdev_prop_set_array(sccdev, "oscclk", oscclk);
+
sysbus_realize(SYS_BUS_DEVICE(&mms->scc), &error_fatal);
sysbus_mmio_map(SYS_BUS_DEVICE(sccdev), 0, 0x4002f000);
object_initialize_child(OBJECT(mms), "fpgaio",
diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c
index bce44690e5..f3c9704693 100644
--- a/hw/arm/sbsa-ref.c
+++ b/hw/arm/sbsa-ref.c
@@ -48,6 +48,7 @@
#include "hw/char/pl011.h"
#include "hw/watchdog/sbsa_gwdt.h"
#include "net/net.h"
+#include "qapi/qmp/qlist.h"
#include "qom/object.h"
#define RAMLIMIT_GB 8192
@@ -437,6 +438,7 @@ static void create_gic(SBSAMachineState *sms, MemoryRegion *mem)
SysBusDevice *gicbusdev;
const char *gictype;
uint32_t redist0_capacity, redist0_count;
+ QList *redist_region_count;
int i;
gictype = gicv3_class_name();
@@ -455,8 +457,9 @@ static void create_gic(SBSAMachineState *sms, MemoryRegion *mem)
sbsa_ref_memmap[SBSA_GIC_REDIST].size / GICV3_REDIST_SIZE;
redist0_count = MIN(smp_cpus, redist0_capacity);
- qdev_prop_set_uint32(sms->gic, "len-redist-region-count", 1);
- qdev_prop_set_uint32(sms->gic, "redist-region-count[0]", redist0_count);
+ redist_region_count = qlist_new();
+ qlist_append_int(redist_region_count, redist0_count);
+ qdev_prop_set_array(sms->gic, "redist-region-count", redist_region_count);
object_property_set_link(OBJECT(sms->gic), "sysmem",
OBJECT(mem), &error_fatal);
diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c
index c08ea34e92..fd981f4c33 100644
--- a/hw/arm/vexpress.c
+++ b/hw/arm/vexpress.c
@@ -43,6 +43,7 @@
#include "hw/cpu/a15mpcore.h"
#include "hw/i2c/arm_sbcon_i2c.h"
#include "hw/sd/sd.h"
+#include "qapi/qmp/qlist.h"
#include "qom/object.h"
#include "audio/audio.h"
@@ -544,6 +545,7 @@ static void vexpress_common_init(MachineState *machine)
ram_addr_t vram_size, sram_size;
MemoryRegion *sysmem = get_system_memory();
const hwaddr *map = daughterboard->motherboard_map;
+ QList *db_voltage, *db_clock;
int i;
daughterboard->init(vms, machine->ram_size, machine->cpu_type, pic);
@@ -584,20 +586,19 @@ static void vexpress_common_init(MachineState *machine)
sysctl = qdev_new("realview_sysctl");
qdev_prop_set_uint32(sysctl, "sys_id", sys_id);
qdev_prop_set_uint32(sysctl, "proc_id", daughterboard->proc_id);
- qdev_prop_set_uint32(sysctl, "len-db-voltage",
- daughterboard->num_voltage_sensors);
+
+ db_voltage = qlist_new();
for (i = 0; i < daughterboard->num_voltage_sensors; i++) {
- char *propname = g_strdup_printf("db-voltage[%d]", i);
- qdev_prop_set_uint32(sysctl, propname, daughterboard->voltages[i]);
- g_free(propname);
+ qlist_append_int(db_voltage, daughterboard->voltages[i]);
}
- qdev_prop_set_uint32(sysctl, "len-db-clock",
- daughterboard->num_clocks);
+ qdev_prop_set_array(sysctl, "db-voltage", db_voltage);
+
+ db_clock = qlist_new();
for (i = 0; i < daughterboard->num_clocks; i++) {
- char *propname = g_strdup_printf("db-clock[%d]", i);
- qdev_prop_set_uint32(sysctl, propname, daughterboard->clocks[i]);
- g_free(propname);
+ qlist_append_int(db_clock, daughterboard->clocks[i]);
}
+ qdev_prop_set_array(sysctl, "db-clock", db_clock);
+
sysbus_realize_and_unref(SYS_BUS_DEVICE(sysctl), &error_fatal);
sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, map[VE_SYSREGS]);
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 0a16ab3095..85e3c5ba9d 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -69,6 +69,7 @@
#include "hw/firmware/smbios.h"
#include "qapi/visitor.h"
#include "qapi/qapi-visit-common.h"
+#include "qapi/qmp/qlist.h"
#include "standard-headers/linux/input.h"
#include "hw/arm/smmuv3.h"
#include "hw/acpi/acpi.h"
@@ -752,14 +753,23 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem)
}
if (vms->gic_version != VIRT_GIC_VERSION_2) {
+ QList *redist_region_count;
uint32_t redist0_capacity = virt_redist_capacity(vms, VIRT_GIC_REDIST);
uint32_t redist0_count = MIN(smp_cpus, redist0_capacity);
nb_redist_regions = virt_gicv3_redist_region_count(vms);
- qdev_prop_set_uint32(vms->gic, "len-redist-region-count",
- nb_redist_regions);
- qdev_prop_set_uint32(vms->gic, "redist-region-count[0]", redist0_count);
+ redist_region_count = qlist_new();
+ qlist_append_int(redist_region_count, redist0_count);
+ if (nb_redist_regions == 2) {
+ uint32_t redist1_capacity =
+ virt_redist_capacity(vms, VIRT_HIGH_GIC_REDIST2);
+
+ qlist_append_int(redist_region_count,
+ MIN(smp_cpus - redist0_count, redist1_capacity));
+ }
+ qdev_prop_set_array(vms->gic, "redist-region-count",
+ redist_region_count);
if (!kvm_irqchip_in_kernel()) {
if (vms->tcg_its) {
@@ -768,14 +778,6 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem)
qdev_prop_set_bit(vms->gic, "has-lpi", true);
}
}
-
- if (nb_redist_regions == 2) {
- uint32_t redist1_capacity =
- virt_redist_capacity(vms, VIRT_HIGH_GIC_REDIST2);
-
- qdev_prop_set_uint32(vms->gic, "redist-region-count[1]",
- MIN(smp_cpus - redist0_count, redist1_capacity));
- }
} else {
if (!kvm_irqchip_in_kernel()) {
qdev_prop_set_bit(vms->gic, "has-virtualization-extensions",
@@ -2748,6 +2750,7 @@ static void virt_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev,
virtio_md_pci_pre_plug(VIRTIO_MD_PCI(dev), MACHINE(hotplug_dev), errp);
} else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_IOMMU_PCI)) {
hwaddr db_start = 0, db_end = 0;
+ QList *reserved_regions;
char *resv_prop_str;
if (vms->iommu != VIRT_IOMMU_NONE) {
@@ -2774,9 +2777,9 @@ static void virt_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev,
db_start, db_end,
VIRTIO_IOMMU_RESV_MEM_T_MSI);
- object_property_set_uint(OBJECT(dev), "len-reserved-regions", 1, errp);
- object_property_set_str(OBJECT(dev), "reserved-regions[0]",
- resv_prop_str, errp);
+ reserved_regions = qlist_new();
+ qlist_append_str(reserved_regions, resv_prop_str);
+ qdev_prop_set_array(dev, "reserved-regions", reserved_regions);
g_free(resv_prop_str);
}
}
diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c
index 4f74a64a0d..9600551c44 100644
--- a/hw/arm/xlnx-versal.c
+++ b/hw/arm/xlnx-versal.c
@@ -12,6 +12,7 @@
#include "qemu/osdep.h"
#include "qemu/units.h"
#include "qapi/error.h"
+#include "qapi/qmp/qlist.h"
#include "qemu/module.h"
#include "hw/sysbus.h"
#include "net/net.h"
@@ -69,6 +70,7 @@ static void versal_create_apu_gic(Versal *s, qemu_irq *pic)
};
SysBusDevice *gicbusdev;
DeviceState *gicdev;
+ QList *redist_region_count;
int nr_apu_cpus = ARRAY_SIZE(s->fpd.apu.cpu);
int i;
@@ -79,8 +81,11 @@ static void versal_create_apu_gic(Versal *s, qemu_irq *pic)
qdev_prop_set_uint32(gicdev, "revision", 3);
qdev_prop_set_uint32(gicdev, "num-cpu", nr_apu_cpus);
qdev_prop_set_uint32(gicdev, "num-irq", XLNX_VERSAL_NR_IRQS + 32);
- qdev_prop_set_uint32(gicdev, "len-redist-region-count", 1);
- qdev_prop_set_uint32(gicdev, "redist-region-count[0]", nr_apu_cpus);
+
+ redist_region_count = qlist_new();
+ qlist_append_int(redist_region_count, nr_apu_cpus);
+ qdev_prop_set_array(gicdev, "redist-region-count", redist_region_count);
+
qdev_prop_set_bit(gicdev, "has-security-extensions", true);
sysbus_realize(SYS_BUS_DEVICE(&s->fpd.apu.gic), &error_fatal);
diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
index b46d16cd2c..1473ab3d5e 100644
--- a/hw/core/qdev-properties-system.c
+++ b/hw/core/qdev-properties-system.c
@@ -450,7 +450,7 @@ static void set_netdev(Object *obj, Visitor *v, const char *name,
peers_ptr->queues = queues;
out:
- error_set_from_qdev_prop_error(errp, err, obj, name, str);
+ error_set_from_qdev_prop_error(errp, err, obj, prop->name, str);
g_free(str);
}
diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c
index 950ef48e01..91632f7be9 100644
--- a/hw/core/qdev-properties.c
+++ b/hw/core/qdev-properties.c
@@ -546,98 +546,187 @@ const PropertyInfo qdev_prop_size32 = {
/* --- support for array properties --- */
-/* Used as an opaque for the object properties we add for each
- * array element. Note that the struct Property must be first
- * in the struct so that a pointer to this works as the opaque
- * for the underlying element's property hooks as well as for
- * our own release callback.
+typedef struct ArrayElementList ArrayElementList;
+
+struct ArrayElementList {
+ ArrayElementList *next;
+ void *value;
+};
+
+/*
+ * 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
+ * and an element array. @elem points at an element in this element array.
*/
-typedef struct {
- struct Property prop;
- char *propname;
- ObjectPropertyRelease *release;
-} ArrayElementProperty;
-
-/* object property release callback for array element properties:
- * we call the underlying element's property release hook, and
- * then free the memory we allocated when we added the property.
+static Property array_elem_prop(Object *obj, Property *parent_prop,
+ const char *name, char *elem)
+{
+ return (Property) {
+ .info = parent_prop->arrayinfo,
+ .name = name,
+ /*
+ * This ugly piece of pointer arithmetic sets up the offset so
+ * that when the underlying release hook calls qdev_get_prop_ptr
+ * they get the right answer despite the array element not actually
+ * being inside the device struct.
+ */
+ .offset = (uintptr_t)elem - (uintptr_t)obj,
+ };
+}
+
+/*
+ * Object property release callback for array properties: We call the
+ * underlying element's property release hook for each element.
+ *
+ * Note that it is the responsibility of the individual device's deinit
+ * to free the array proper.
*/
-static void array_element_release(Object *obj, const char *name, void *opaque)
+static void release_prop_array(Object *obj, const char *name, void *opaque)
{
- ArrayElementProperty *p = opaque;
- if (p->release) {
- p->release(obj, name, opaque);
+ Property *prop = opaque;
+ uint32_t *alenptr = object_field_prop_ptr(obj, prop);
+ void **arrayptr = (void *)obj + prop->arrayoffset;
+ char *elem = *arrayptr;
+ int i;
+
+ if (!prop->arrayinfo->release) {
+ return;
+ }
+
+ 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;
}
- g_free(p->propname);
- g_free(p);
}
-static void set_prop_arraylen(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
+/*
+ * Setter for an array property. This sets both the array length (which
+ * is technically the property field in the object) and the array itself
+ * (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)
{
- /* Setter for the property which defines the length of a
- * variable-sized property array. As well as actually setting the
- * array-length field in the device struct, we have to create the
- * array itself and dynamically add the corresponding properties.
- */
+ ERRP_GUARD();
Property *prop = opaque;
uint32_t *alenptr = object_field_prop_ptr(obj, prop);
void **arrayptr = (void *)obj + prop->arrayoffset;
- void *eltptr;
- const char *arrayname;
- int i;
+ ArrayElementList *list, *elem, *next;
+ const size_t size = sizeof(*list);
+ char *elemptr;
+ bool ok = true;
if (*alenptr) {
error_setg(errp, "array size property %s may not be set more than once",
name);
return;
}
- if (!visit_type_uint32(v, name, alenptr, errp)) {
+
+ if (!visit_start_list(v, name, (GenericList **) &list, size, errp)) {
return;
}
- if (!*alenptr) {
+
+ /* Read the whole input into a temporary list */
+ elem = list;
+ while (elem) {
+ Property elem_prop;
+
+ elem->value = g_malloc0(prop->arrayfieldsize);
+ elem_prop = array_elem_prop(obj, prop, name, elem->value);
+ prop->arrayinfo->set(obj, v, NULL, &elem_prop, errp);
+ if (*errp) {
+ ok = false;
+ goto out_obj;
+ }
+ if (*alenptr == INT_MAX) {
+ error_setg(errp, "array is too big");
+ return;
+ }
+ (*alenptr)++;
+ elem = (ArrayElementList *) visit_next_list(v, (GenericList*) elem,
+ size);
+ }
+
+ ok = visit_check_list(v, errp);
+out_obj:
+ visit_end_list(v, (void**) &list);
+
+ if (!ok) {
+ 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);
+ }
+ next = elem->next;
+ g_free(elem->value);
+ g_free(elem);
+ }
return;
}
- /* DEFINE_PROP_ARRAY guarantees that name should start with this prefix;
- * strip it off so we can get the name of the array itself.
+ /*
+ * Now that we know how big the array has to be, move the data over to a
+ * linear array and free the temporary list.
*/
- assert(strncmp(name, PROP_ARRAY_LEN_PREFIX,
- strlen(PROP_ARRAY_LEN_PREFIX)) == 0);
- arrayname = name + strlen(PROP_ARRAY_LEN_PREFIX);
+ *arrayptr = g_malloc_n(*alenptr, prop->arrayfieldsize);
+ elemptr = *arrayptr;
+ for (elem = list; elem; elem = next) {
+ memcpy(elemptr, elem->value, prop->arrayfieldsize);
+ elemptr += prop->arrayfieldsize;
+ next = elem->next;
+ g_free(elem->value);
+ g_free(elem);
+ }
+}
- /* Note that it is the responsibility of the individual device's deinit
- * to free the array proper.
- */
- *arrayptr = eltptr = g_malloc0(*alenptr * prop->arrayfieldsize);
- for (i = 0; i < *alenptr; i++, eltptr += prop->arrayfieldsize) {
- char *propname = g_strdup_printf("%s[%d]", arrayname, i);
- ArrayElementProperty *arrayprop = g_new0(ArrayElementProperty, 1);
- arrayprop->release = prop->arrayinfo->release;
- arrayprop->propname = propname;
- arrayprop->prop.info = prop->arrayinfo;
- arrayprop->prop.name = propname;
- /* This ugly piece of pointer arithmetic sets up the offset so
- * that when the underlying get/set hooks call qdev_get_prop_ptr
- * they get the right answer despite the array element not actually
- * being inside the device struct.
- */
- arrayprop->prop.offset = eltptr - (void *)obj;
- assert(object_field_prop_ptr(obj, &arrayprop->prop) == eltptr);
- object_property_add(obj, propname,
- arrayprop->prop.info->name,
- field_prop_getter(arrayprop->prop.info),
- field_prop_setter(arrayprop->prop.info),
- array_element_release,
- arrayprop);
+static void get_prop_array(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ ERRP_GUARD();
+ Property *prop = opaque;
+ uint32_t *alenptr = object_field_prop_ptr(obj, prop);
+ void **arrayptr = (void *)obj + prop->arrayoffset;
+ char *elem = *arrayptr;
+ GenericList *list;
+ const size_t list_elem_size = sizeof(*list) + prop->arrayfieldsize;
+ int i;
+ bool ok;
+
+ if (!visit_start_list(v, name, &list, list_elem_size, errp)) {
+ return;
}
+
+ for (i = 0; i < *alenptr; i++) {
+ Property elem_prop = array_elem_prop(obj, prop, name, elem);
+ prop->arrayinfo->get(obj, v, NULL, &elem_prop, errp);
+ if (*errp) {
+ goto out_obj;
+ }
+ elem += prop->arrayfieldsize;
+ }
+
+ /* visit_check_list() can only fail for input visitors */
+ ok = visit_check_list(v, errp);
+ assert(ok);
+
+out_obj:
+ visit_end_list(v, (void**) &list);
}
-const PropertyInfo qdev_prop_arraylen = {
- .name = "uint32",
- .get = get_uint32,
- .set = set_prop_arraylen,
- .set_default_value = qdev_propinfo_set_default_value_uint,
+static void default_prop_array(ObjectProperty *op, const Property *prop)
+{
+ object_property_set_default_list(op);
+}
+
+const PropertyInfo qdev_prop_array = {
+ .name = "list",
+ .get = get_prop_array,
+ .set = set_prop_array,
+ .release = release_prop_array,
+ .set_default_value = default_prop_array,
};
/* --- public helpers --- */
@@ -743,20 +832,8 @@ void qdev_prop_set_enum(DeviceState *dev, const char *name, int value)
void qdev_prop_set_array(DeviceState *dev, const char *name, QList *values)
{
- const QListEntry *entry;
- g_autofree char *prop_len = g_strdup_printf("len-%s", name);
- uint32_t i = 0;
-
- object_property_set_int(OBJECT(dev), prop_len, qlist_size(values),
- &error_abort);
-
- QLIST_FOREACH_ENTRY(values, entry) {
- g_autofree char *prop_idx = g_strdup_printf("%s[%u]", name, i);
- object_property_set_qobject(OBJECT(dev), prop_idx, entry->value,
- &error_abort);
- i++;
- }
-
+ object_property_set_qobject(OBJECT(dev), name, QOBJECT(values),
+ &error_abort);
qobject_unref(values);
}
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 188bc9d0f8..29b9964733 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -44,6 +44,7 @@
#include "sysemu/reset.h"
#include "kvm/kvm_i386.h"
#include "hw/xen/xen.h"
+#include "qapi/qmp/qlist.h"
#include "qemu/error-report.h"
#include "hw/acpi/cpu_hotplug.h"
#include "acpi-build.h"
@@ -1457,10 +1458,11 @@ static void pc_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev,
/* Declare the APIC range as the reserved MSI region */
char *resv_prop_str = g_strdup_printf("0xfee00000:0xfeefffff:%d",
VIRTIO_IOMMU_RESV_MEM_T_MSI);
+ QList *reserved_regions = qlist_new();
+
+ qlist_append_str(reserved_regions, resv_prop_str);
+ qdev_prop_set_array(dev, "reserved-regions", reserved_regions);
- object_property_set_uint(OBJECT(dev), "len-reserved-regions", 1, errp);
- object_property_set_str(OBJECT(dev), "reserved-regions[0]",
- resv_prop_str, errp);
g_free(resv_prop_str);
}
diff --git a/hw/rx/rx62n.c b/hw/rx/rx62n.c
index d00fcb0ef0..4dc44afd9d 100644
--- a/hw/rx/rx62n.c
+++ b/hw/rx/rx62n.c
@@ -28,6 +28,7 @@
#include "hw/sysbus.h"
#include "hw/qdev-properties.h"
#include "sysemu/sysemu.h"
+#include "qapi/qmp/qlist.h"
#include "qom/object.h"
/*
@@ -130,22 +131,22 @@ static void register_icu(RX62NState *s)
{
int i;
SysBusDevice *icu;
+ QList *ipr_map, *trigger_level;
object_initialize_child(OBJECT(s), "icu", &s->icu, TYPE_RX_ICU);
icu = SYS_BUS_DEVICE(&s->icu);
- qdev_prop_set_uint32(DEVICE(icu), "len-ipr-map", NR_IRQS);
+
+ ipr_map = qlist_new();
for (i = 0; i < NR_IRQS; i++) {
- char propname[32];
- snprintf(propname, sizeof(propname), "ipr-map[%d]", i);
- qdev_prop_set_uint32(DEVICE(icu), propname, ipr_table[i]);
+ qlist_append_int(ipr_map, ipr_table[i]);
}
- qdev_prop_set_uint32(DEVICE(icu), "len-trigger-level",
- ARRAY_SIZE(levelirq));
+ qdev_prop_set_array(DEVICE(icu), "ipr-map", ipr_map);
+
+ trigger_level = qlist_new();
for (i = 0; i < ARRAY_SIZE(levelirq); i++) {
- char propname[32];
- snprintf(propname, sizeof(propname), "trigger-level[%d]", i);
- qdev_prop_set_uint32(DEVICE(icu), propname, levelirq[i]);
+ qlist_append_int(trigger_level, levelirq[i]);
}
+ qdev_prop_set_array(DEVICE(icu), "trigger-level", trigger_level);
for (i = 0; i < NR_IRQS; i++) {
s->irq[i] = qdev_get_gpio_in(DEVICE(icu), i);
diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h
index 7fa2fdb7c9..25743a29a0 100644
--- a/include/hw/qdev-properties.h
+++ b/include/hw/qdev-properties.h
@@ -61,7 +61,7 @@ extern const PropertyInfo qdev_prop_size;
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_arraylen;
+extern const PropertyInfo qdev_prop_array;
extern const PropertyInfo qdev_prop_link;
#define DEFINE_PROP(_name, _state, _field, _prop, _type, ...) { \
@@ -115,8 +115,6 @@ extern const PropertyInfo qdev_prop_link;
.bitmask = (_bitmask), \
.set_default = false)
-#define PROP_ARRAY_LEN_PREFIX "len-"
-
/**
* DEFINE_PROP_ARRAY:
* @_name: name of the array
@@ -127,28 +125,25 @@ extern const PropertyInfo qdev_prop_link;
* @_arrayprop: PropertyInfo defining what property the array elements have
* @_arraytype: C type of the array elements
*
- * Define device properties for a variable-length array _name. A
- * static property "len-arrayname" is defined. When the device creator
- * sets this property to the desired length of array, further dynamic
- * properties "arrayname[0]", "arrayname[1]", ... are defined so the
- * device creator can set the array element values. Setting the
- * "len-arrayname" property more than once is an error.
+ * Define device properties for a variable-length array _name. The array is
+ * represented as a list in the visitor interface.
+ *
+ * @_arraytype is required to be movable with memcpy().
*
- * When the array length is set, the @_field member of the device
+ * When the array property is set, the @_field member of the device
* struct is set to the array length, and @_arrayfield is set to point
- * to (zero-initialised) memory allocated for the array. For a zero
- * length array, @_field will be set to 0 and @_arrayfield to NULL.
+ * to the memory allocated for the array.
+ *
* It is the responsibility of the device deinit code to free the
* @_arrayfield memory.
*/
-#define DEFINE_PROP_ARRAY(_name, _state, _field, \
- _arrayfield, _arrayprop, _arraytype) \
- DEFINE_PROP((PROP_ARRAY_LEN_PREFIX _name), \
- _state, _field, qdev_prop_arraylen, uint32_t, \
- .set_default = true, \
- .defval.u = 0, \
- .arrayinfo = &(_arrayprop), \
- .arrayfieldsize = sizeof(_arraytype), \
+#define DEFINE_PROP_ARRAY(_name, _state, _field, \
+ _arrayfield, _arrayprop, _arraytype) \
+ DEFINE_PROP(_name, _state, _field, qdev_prop_array, uint32_t, \
+ .set_default = true, \
+ .defval.u = 0, \
+ .arrayinfo = &(_arrayprop), \
+ .arrayfieldsize = sizeof(_arraytype), \
.arrayoffset = offsetof(_state, _arrayfield))
#define DEFINE_PROP_LINK(_name, _state, _field, _type, _ptr_type) \
diff --git a/include/qom/object.h b/include/qom/object.h
index ef7258a5e1..afccd24ca7 100644
--- a/include/qom/object.h
+++ b/include/qom/object.h
@@ -1094,6 +1094,14 @@ void object_property_set_default_bool(ObjectProperty *prop, bool value);
void object_property_set_default_str(ObjectProperty *prop, const char *value);
/**
+ * object_property_set_default_list:
+ * @prop: the property to set
+ *
+ * Set the property default value to be an empty list.
+ */
+void object_property_set_default_list(ObjectProperty *prop);
+
+/**
* object_property_set_default_int:
* @prop: the property to set
* @value: the value to be written to the property
diff --git a/qom/object.c b/qom/object.c
index 8557fe8e4e..95c0dc8285 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -31,6 +31,7 @@
* of the QOM core on QObject? */
#include "qom/qom-qobject.h"
#include "qapi/qmp/qbool.h"
+#include "qapi/qmp/qlist.h"
#include "qapi/qmp/qnum.h"
#include "qapi/qmp/qstring.h"
#include "qemu/error-report.h"
@@ -1588,6 +1589,11 @@ void object_property_set_default_str(ObjectProperty *prop, const char *value)
object_property_set_default(prop, QOBJECT(qstring_from_str(value)));
}
+void object_property_set_default_list(ObjectProperty *prop)
+{
+ object_property_set_default(prop, QOBJECT(qlist_new()));
+}
+
void object_property_set_default_int(ObjectProperty *prop, int64_t value)
{
object_property_set_default(prop, QOBJECT(qnum_from_int(value)));