From nobody Tue Feb 10 20:14:22 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=linaro.org ARC-Seal: i=1; a=rsa-sha256; t=1672769913; cv=none; d=zohomail.com; s=zohoarc; b=GdaO/Qj1YydCqDZMZ2IKEdzINyi4LPVA9cU2OnAwkT/hy1jNjrQpC7StQxlzbnI5zZHZybd/apm6g56G54vpYKIEE3x3jybQnMt9zq25IkT4gDnn7xJtF0XIWAa1bZwe5TrRjMeBT5dXc2q88LbrzWLYpFRy2cuykSSFrUogQWQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1672769913; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=poMxRDPn366GZBea/9dCLSAffdWXTadkp9C7Z8GBPIw=; b=DfzOAroM+YD5afEmPvnMhzP2erN7ks1lxXvh5cJbAjfgcKNMji286SI3ml4qMuwCVNRxFYDvGNR95Ij0x3yaJhyc9Z8DoElWASKMdf58u9VF/HDaCE+5IcDiS9/Bkz9SMLU//vE3ZHJF/ZnEcGTHVN7cnHBDUjWFrHT1hCmlM5w= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1672769913319996.7855141766532; Tue, 3 Jan 2023 10:18:33 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pClrF-0008Lt-DO; Tue, 03 Jan 2023 13:17:53 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pClqT-0008Fu-Eg for qemu-devel@nongnu.org; Tue, 03 Jan 2023 13:17:20 -0500 Received: from mail-vk1-xa2a.google.com ([2607:f8b0:4864:20::a2a]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1pClqQ-00057h-2K for qemu-devel@nongnu.org; Tue, 03 Jan 2023 13:17:04 -0500 Received: by mail-vk1-xa2a.google.com with SMTP id bk19so4768833vkb.11 for ; Tue, 03 Jan 2023 10:17:01 -0800 (PST) Received: from stoup.. ([2607:fb90:8060:51a2:184b:6e49:c396:be2]) by smtp.gmail.com with ESMTPSA id v2-20020a05620a440200b006fed2788751sm23042354qkp.76.2023.01.03.10.16.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 03 Jan 2023 10:17:00 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=poMxRDPn366GZBea/9dCLSAffdWXTadkp9C7Z8GBPIw=; b=EhHns2BUCjMTPif02/2HFPX0/2nXbqiCJvTl9wtnSGwYvXjrzQimjlvliJWSLMmPvv 6E7BMMEI1KK5uWZ00an6oh95H8+wbUEk/wE2kXxFkSqRb18FFN8OzfcyZOmoX4XPlCWI o/CXLl8+Wf0tgNMKx01hrEWbxrdeajpOgHmkzwXb0JWds0xe7kGl8og5Oi0NZDySukiG qtR13mAASgzmUKqLx/2XASjoAkBL8728vEGoH//xnTZik9vjKYd803EeCMegnyQf5k36 yYNtQGBAEk2Peim2ARjSpHfoBFVzI5uUIIhh8jAa/gpn20nPd6t4dlNFw4DwbtN6AqR7 lRSQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=poMxRDPn366GZBea/9dCLSAffdWXTadkp9C7Z8GBPIw=; b=2tAh8wJX4CIMfcvO9QycPGX+tG0oSKGZsj8ZFTiUaWdzpTJXpMr8+Ttzo7qVSjHF0e frYZxli8KlyIcth+bkpx7AliQcJ07WekHOLQ3RuWr4O7r0Zqx9F4EoXJf7bIpQxPhepk /t3TlqZXH5K3RVr2+VmyU6RugDDc5XC6PRMdHxMNsSQBIwKnAl2lBTDH6LsY2sJAlKYs r+hOtI1CHBTjMMFojBodDdB9v05hjhhlMg3mBuCcV/tkH+cijMlSaCEpfv3hqZ2d3Mq2 NvVsF0fxb0X7uREjdiOXJsc9kMBgUCGAerRPNrk17ohw6w6/7GUBUuTSSCJDkdHOWTbo SACg== X-Gm-Message-State: AFqh2krM4mKG2U8H0v5xHCj2KRM6NMpU/KthB2mPks+ZbjUy2pdDzh3+ dYW1KlnSMzzgKEVO7PQSES4HMB4RRNgpffkf8Vg= X-Google-Smtp-Source: AMrXdXtHUMzmtvsM5YbzCrdLPmwf3TsLDbFoyKichdhHRwGXyHxwT/dkeSPDP3gNesplAq6rerhv3A== X-Received: by 2002:a1f:bdcf:0:b0:3d5:6850:70ac with SMTP id n198-20020a1fbdcf000000b003d5685070acmr13190791vkf.13.1672769820779; Tue, 03 Jan 2023 10:17:00 -0800 (PST) From: Richard Henderson To: qemu-devel@nongnu.org Cc: pbonzini@redhat.com, berrange@redhat.com, eduardo@habkost.net, armbru@redhat.com, ajones@ventanamicro.com, alex.bennee@linaro.org Subject: [RFC PATCH 03/40] qom: Create class properties Date: Tue, 3 Jan 2023 10:16:09 -0800 Message-Id: <20230103181646.55711-4-richard.henderson@linaro.org> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230103181646.55711-1-richard.henderson@linaro.org> References: <20230103181646.55711-1-richard.henderson@linaro.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::a2a; envelope-from=richard.henderson@linaro.org; helo=mail-vk1-xa2a.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @linaro.org) X-ZM-MESSAGEID: 1672769914538100003 Content-Type: text/plain; charset="utf-8" These properties apply to the class itself, as opposed to object_class_property_* in which the property is attached to the class but applies to each object instance. Apply global properties via a class_late_init on DeviceClass. Signed-off-by: Richard Henderson --- hw/core/qdev-prop-internal.h | 2 + include/qom/object.h | 63 ++++++++++++ include/qom/qom-qobject.h | 28 +++++ hw/core/cpu-common.c | 61 ++++++++--- hw/core/qdev-properties.c | 36 +++++++ hw/core/qdev.c | 2 + qom/object.c | 194 +++++++++++++++++++++++++++++++++++ qom/object_interfaces.c | 13 +++ qom/qom-qmp-cmds.c | 37 +++++++ 9 files changed, 419 insertions(+), 17 deletions(-) diff --git a/hw/core/qdev-prop-internal.h b/hw/core/qdev-prop-internal.h index d7b77844fe..21cd3bca27 100644 --- a/hw/core/qdev-prop-internal.h +++ b/hw/core/qdev-prop-internal.h @@ -25,4 +25,6 @@ void qdev_propinfo_get_int32(Object *obj, Visitor *v, con= st char *name, void qdev_propinfo_get_size32(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp); =20 +bool device_class_late_init(ObjectClass *class, Error **errp); + #endif diff --git a/include/qom/object.h b/include/qom/object.h index 86958abe15..caa4774f80 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -27,8 +27,25 @@ typedef struct InterfaceInfo InterfaceInfo; =20 #define TYPE_OBJECT "object" =20 +typedef struct ClassProperty ClassProperty; typedef struct ObjectProperty ObjectProperty; =20 +/** + * typedef ClassPropertyAccessor: + * @klass: the class that owns the property + * @v: the visitor that contains the property data + * @name: the name of the property + * @opaque: the class property opaque + * @errp: a pointer to an Error that is filled if getting/setting fails. + * + * Called when trying to get/set a property. + */ +typedef bool (ClassPropertyAccessor)(ObjectClass *klass, + Visitor *v, + const char *name, + void *opaque, + Error **errp); + /** * typedef ObjectPropertyAccessor: * @obj: the object that owns the property @@ -85,6 +102,16 @@ typedef void (ObjectPropertyRelease)(Object *obj, */ typedef void (ObjectPropertyInit)(Object *obj, ObjectProperty *prop); =20 +struct ClassProperty +{ + char *name; + char *type; + char *description; + ClassPropertyAccessor *get; + ClassPropertyAccessor *set; + void *opaque; +}; + struct ObjectProperty { char *name; @@ -135,6 +162,7 @@ struct ObjectClass =20 ObjectUnparent *unparent; =20 + GHashTable *class_properties; GHashTable *properties; }; =20 @@ -1072,6 +1100,11 @@ ObjectProperty *object_property_add(Object *obj, con= st char *name, =20 void object_property_del(Object *obj, const char *name); =20 +/** + * object_class_property_add: + * + * Add a property to the class, as if added to each object instance. + */ ObjectProperty *object_class_property_add(ObjectClass *klass, const char *= name, const char *type, ObjectPropertyAccessor *get, @@ -1079,6 +1112,33 @@ ObjectProperty *object_class_property_add(ObjectClas= s *klass, const char *name, ObjectPropertyRelease *release, void *opaque); =20 +/** + * class_property_add: + * + * Add a property to the class, affecting the class as a whole + * rather than each instance. All such properties are resolved + * before the first object instance is created. + */ +void class_property_add(ObjectClass *klass, const char *name, + const char *type, const char *desc, + ClassPropertyAccessor *get, + ClassPropertyAccessor *set, + void *opaque); + +ClassProperty *class_property_find(ObjectClass *klass, const char *name); + +bool class_property_set(ObjectClass *klass, ClassProperty *cp, + Visitor *v, Error **errp); +bool class_property_set_bool(ObjectClass *klass, const char *name, + bool value, Error **errp); +bool class_property_set_uint(ObjectClass *klass, const char *name, + uint64_t value, Error **errp); + +bool class_property_get(ObjectClass *klass, ClassProperty *cp, + Visitor *v, Error **errp); +bool class_property_get_bool(ObjectClass *klass, const char *name, + Error **errp); + /** * object_property_set_default_bool: * @prop: the property to set @@ -1229,6 +1289,9 @@ void object_class_property_iter_init(ObjectPropertyIt= erator *iter, */ ObjectProperty *object_property_iter_next(ObjectPropertyIterator *iter); =20 +void class_property_iter_init(ObjectPropertyIterator *iter, ObjectClass *k= lass); +ClassProperty *class_property_iter_next(ObjectPropertyIterator *iter); + void object_unparent(Object *obj); =20 /** diff --git a/include/qom/qom-qobject.h b/include/qom/qom-qobject.h index 73e4e0e474..4026fe6964 100644 --- a/include/qom/qom-qobject.h +++ b/include/qom/qom-qobject.h @@ -40,4 +40,32 @@ bool object_property_set_qobject(Object *obj, const char *name, struct QObject *value, struct Error **errp); =20 +/* + * class_property_get_qobject: + * @cls: the class object + * @name: the name of the property + * @errp: returns an error if this function fails + * + * Returns: the value of the property, converted to QObject, or NULL if + * an error occurs. + */ +struct QObject *class_property_get_qobject(ObjectClass *cls, + const char *name, + struct Error **errp); + +/** + * class_property_set_qobject: + * @cls: the class object + * @name: the name of the property + * @value: The value that will be written to the property. + * @errp: returns an error if this function fails + * + * Writes a property to a class object. + * + * Returns: %true on success, %false on failure. + */ +bool class_property_set_qobject(ObjectClass *cls, + const char *name, struct QObject *value, + struct Error **errp); + #endif diff --git a/hw/core/cpu-common.c b/hw/core/cpu-common.c index 78b5f350a0..34cab4ef31 100644 --- a/hw/core/cpu-common.c +++ b/hw/core/cpu-common.c @@ -34,6 +34,7 @@ #include "hw/qdev-properties.h" #include "trace/trace-root.h" #include "qemu/plugin.h" +#include "qapi/string-input-visitor.h" =20 CPUState *cpu_by_arch_id(int64_t id) { @@ -158,31 +159,57 @@ ObjectClass *cpu_class_by_name(const char *typename, = const char *cpu_model) static void cpu_common_parse_features(const char *typename, char *features, Error **errp) { - char *val; static bool cpu_globals_initialized; - /* Single "key=3Dvalue" string being parsed */ - char *featurestr =3D features ? strtok(features, ",") : NULL; + ObjectClass *klass; + char *f; =20 /* should be called only once, catch invalid users */ assert(!cpu_globals_initialized); cpu_globals_initialized =3D true; =20 - while (featurestr) { - val =3D strchr(featurestr, '=3D'); - if (val) { - GlobalProperty *prop =3D g_new0(typeof(*prop), 1); - *val =3D 0; - val++; - prop->driver =3D typename; - prop->property =3D g_strdup(featurestr); - prop->value =3D g_strdup(val); - qdev_prop_register_global(prop); - } else { - error_setg(errp, "Expected key=3Dvalue format, found %s.", - featurestr); + if (!features) { + return; + } + + /* + * If typename is invalid, we'll register the global properties anyway + * and report a warning in qdev_prop_check_globals. + * TODO: Report an error early if -cpu typename is invalid; all classes + * will have been registered by now, whether or not the target is using + * class properties or object properties. + */ + klass =3D object_class_by_name(typename); + + /* Single "key=3Dvalue" string being parsed */ + for (f =3D strtok(features, ","); f !=3D NULL; f =3D strtok(NULL, ",")= ) { + char *val =3D strchr(f, '=3D'); + GlobalProperty *prop; + + if (!val) { + error_setg(errp, "Expected key=3Dvalue format, found %s.", f); return; } - featurestr =3D strtok(NULL, ","); + *val++ =3D 0; + + if (klass) { + ClassProperty *cp =3D class_property_find(klass, f); + if (cp) { + Visitor *v =3D string_input_visitor_new(val); + bool ok =3D class_property_set(klass, cp, v, errp); + + visit_free(v); + if (!ok) { + return; + } + continue; + } + } + + prop =3D g_new0(typeof(*prop), 1); + prop->driver =3D typename; + prop->property =3D g_strdup(f); + prop->value =3D g_strdup(val); + qdev_prop_register_global(prop); } } =20 diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c index f7775d0ea4..30037ddfb2 100644 --- a/hw/core/qdev-properties.c +++ b/hw/core/qdev-properties.c @@ -6,6 +6,7 @@ #include "qemu/ctype.h" #include "qemu/error-report.h" #include "qapi/visitor.h" +#include "qapi/string-input-visitor.h" #include "qemu/units.h" #include "qemu/cutils.h" #include "qdev-prop-internal.h" @@ -821,6 +822,41 @@ void qdev_prop_set_globals(DeviceState *dev) } } =20 +bool device_class_late_init(ObjectClass *class, Error **errp) +{ + GPtrArray *props =3D global_properties; + int i, len =3D props ? props->len : 0; + + for (i =3D 0; i < len; i++) { + GlobalProperty *p =3D g_ptr_array_index(props, i); + ClassProperty *cp; + Visitor *v; + bool ok; + + if (object_class_dynamic_cast(class, p->driver) =3D=3D NULL) { + continue; + } + + cp =3D class_property_find(class, p->property); + if (!cp) { + /* The property may be on the object. */ + continue; + } + p->used =3D true; + + v =3D string_input_visitor_new(p->value); + ok =3D class_property_set(class, cp, v, errp); + visit_free(v); + + if (!ok) { + error_prepend(errp, "can't apply global %s.%s=3D%s: ", + p->driver, p->property, p->value); + return false; + } + } + return true; +} + /* --- 64bit unsigned int 'size' type --- */ =20 static void get_size(Object *obj, Visitor *v, const char *name, void *opaq= ue, diff --git a/hw/core/qdev.c b/hw/core/qdev.c index d759c4602c..772aedc914 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -40,6 +40,7 @@ #include "hw/qdev-clock.h" #include "migration/vmstate.h" #include "trace.h" +#include "qdev-prop-internal.h" =20 static bool qdev_hot_added =3D false; bool qdev_hot_removed =3D false; @@ -901,6 +902,7 @@ static const TypeInfo device_type_info =3D { .instance_finalize =3D device_finalize, .class_base_init =3D device_class_base_init, .class_init =3D device_class_init, + .class_late_init =3D device_class_late_init, .abstract =3D true, .class_size =3D sizeof(DeviceClass), .interfaces =3D (InterfaceInfo[]) { diff --git a/qom/object.c b/qom/object.c index 82a5c7d36e..344ca03877 100644 --- a/qom/object.c +++ b/qom/object.c @@ -21,6 +21,7 @@ #include "qapi/string-input-visitor.h" #include "qapi/string-output-visitor.h" #include "qapi/qobject-input-visitor.h" +#include "qapi/qobject-output-visitor.h" #include "qapi/forward-visitor.h" #include "qapi/qapi-builtin-visit.h" #include "qapi/qmp/qerror.h" @@ -34,6 +35,7 @@ #include "qapi/qmp/qnum.h" #include "qapi/qmp/qstring.h" #include "qemu/error-report.h" +#include "sysemu/qtest.h" =20 #define MAX_INTERFACES 32 =20 @@ -76,6 +78,190 @@ struct TypeImpl InterfaceImpl interfaces[MAX_INTERFACES]; }; =20 +ClassProperty *class_property_find(ObjectClass *klass, const char *name) +{ + ObjectClass *parent_klass; + + if (klass->class_properties) { + ClassProperty *p =3D g_hash_table_lookup(klass->class_properties, = name); + if (p) { + return p; + } + } + + parent_klass =3D object_class_get_parent(klass); + if (parent_klass) { + return class_property_find(parent_klass, name); + } + return NULL; +} + +static ClassProperty *class_property_find_err(ObjectClass *klass, + const char *name, + Error **errp) +{ + ClassProperty *cp =3D class_property_find(klass, name); + if (!cp) { + error_setg(errp, "Property '%s.%s' not found", + klass->type->name, name); + } + return cp; +} + +void class_property_add(ObjectClass *klass, const char *name, + const char *type, const char *desc, + ClassPropertyAccessor *get, + ClassPropertyAccessor *set, + void *opaque) +{ + ClassProperty *prop; + + assert(!class_property_find(klass, name)); + + prop =3D g_new0(ClassProperty, 1); + + prop->name =3D g_strdup(name); + prop->type =3D g_strdup(type); + prop->description =3D g_strdup(desc); + + prop->get =3D get; + prop->set =3D set; + prop->opaque =3D opaque; + + if (!klass->class_properties) { + klass->class_properties =3D g_hash_table_new(g_str_hash, g_str_equ= al); + } + g_hash_table_insert(klass->class_properties, prop->name, prop); +} + +bool class_property_set(ObjectClass *klass, ClassProperty *cp, + Visitor *v, Error **errp) +{ + /* + * FIXME: qtest/device-introspect-test creates one of each board, + * inside the same qemu instance. The class properties for the + * cpus may well be adjusted for each board. This cannot happen + * during normal usage. + */ + if (!qtest_enabled() && klass->type->object_created) { + error_setg(errp, "Property '%s.%s' set after object creation", + klass->type->name, cp->name); + return false; + } + return cp->set(klass, v, cp->name, cp->opaque, errp); +} + +static bool class_property_set_lookup(ObjectClass *klass, const char *name, + Visitor *v, Error **errp) +{ + ClassProperty *cp =3D class_property_find_err(klass, name, errp); + if (!cp) { + return false; + } + return class_property_set(klass, cp, v, errp); +} + +bool class_property_set_qobject(ObjectClass *klass, const char *name, + QObject *value, Error **errp) +{ + Visitor *v =3D qobject_input_visitor_new(value); + bool ok; + + ok =3D class_property_set_lookup(klass, name, v, errp); + visit_free(v); + return ok; +} + +bool class_property_set_bool(ObjectClass *klass, const char *name, + bool value, Error **errp) +{ + QBool *qbool =3D qbool_from_bool(value); + bool ok; + + ok =3D class_property_set_qobject(klass, name, QOBJECT(qbool), errp); + qobject_unref(qbool); + return ok; +} + +bool class_property_set_uint(ObjectClass *klass, const char *name, + uint64_t value, Error **errp) +{ + QNum *qnum =3D qnum_from_uint(value); + bool ok; + + ok =3D class_property_set_qobject(klass, name, QOBJECT(qnum), errp); + qobject_unref(qnum); + return ok; +} + +bool class_property_get(ObjectClass *klass, ClassProperty *cp, + Visitor *v, Error **errp) +{ + return cp->get(klass, v, cp->name, cp->opaque, errp); +} + +static bool class_property_get_lookup(ObjectClass *klass, const char *name, + Visitor *v, Error **errp) +{ + ClassProperty *cp =3D class_property_find_err(klass, name, errp); + if (!cp) { + return false; + } + return class_property_get(klass, cp, v, errp); +} + + +QObject *class_property_get_qobject(ObjectClass *klass, const char *name, + Error **errp) +{ + QObject *ret =3D NULL; + Visitor *v =3D qobject_output_visitor_new(&ret); + + if (class_property_get_lookup(klass, name, v, errp)) { + visit_complete(v, &ret); + } + visit_free(v); + return ret; +} + +bool class_property_get_bool(ObjectClass *klass, const char *name, + Error **errp) +{ + QObject *qobj =3D class_property_get_qobject(klass, name, errp); + bool ret =3D false; + + if (qobj) { + QBool *qbool =3D qobject_to(QBool, qobj); + if (!qbool) { + error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name, "boolean"); + } else { + ret =3D qbool_get_bool(qbool); + } + qobject_unref(qobj); + } + return ret; +} + +void class_property_iter_init(ObjectPropertyIterator *iter, + ObjectClass *klass) +{ + g_hash_table_iter_init(&iter->iter, klass->class_properties); + iter->nextclass =3D object_class_get_parent(klass); +} + +ClassProperty *class_property_iter_next(ObjectPropertyIterator *iter) +{ + gpointer key, val; + while (!g_hash_table_iter_next(&iter->iter, &key, &val)) { + if (!iter->nextclass) { + return NULL; + } + g_hash_table_iter_init(&iter->iter, iter->nextclass->class_propert= ies); + iter->nextclass =3D object_class_get_parent(iter->nextclass); + } + return val; +} + static Type type_interface; =20 static GHashTable *type_table_get(void) @@ -322,6 +508,7 @@ static void type_initialize(TypeImpl *ti) g_assert(parent->instance_size <=3D ti->instance_size); memcpy(ti->class, parent->class, parent->class_size); ti->class->interfaces =3D NULL; + ti->class->class_properties =3D NULL; =20 for (e =3D parent->class->interfaces; e; e =3D e->next) { InterfaceClass *iface =3D e->data; @@ -415,12 +602,15 @@ static void object_post_init_with_type(Object *obj, T= ypeImpl *ti) bool object_apply_global_props(Object *obj, const GPtrArray *props, Error **errp) { + ObjectClass *klass; int i; =20 if (!props) { return true; } =20 + klass =3D object_get_class(obj); + for (i =3D 0; i < props->len; i++) { GlobalProperty *p =3D g_ptr_array_index(props, i); Error *err =3D NULL; @@ -428,6 +618,10 @@ bool object_apply_global_props(Object *obj, const GPtr= Array *props, if (object_dynamic_cast(obj, p->driver) =3D=3D NULL) { continue; } + if (class_property_find(klass, p->property)) { + /* This was handled in device_class_late_init. */ + continue; + } if (p->optional && !object_property_find(obj, p->property)) { continue; } diff --git a/qom/object_interfaces.c b/qom/object_interfaces.c index f94b6c3193..aee86eb708 100644 --- a/qom/object_interfaces.c +++ b/qom/object_interfaces.c @@ -203,6 +203,7 @@ bool type_print_class_properties(const char *type) ObjectClass *klass; ObjectPropertyIterator iter; ObjectProperty *prop; + ClassProperty *cprop; GPtrArray *array; int i; =20 @@ -212,6 +213,7 @@ bool type_print_class_properties(const char *type) } =20 array =3D g_ptr_array_new(); + object_class_property_iter_init(&iter, klass); while ((prop =3D object_property_iter_next(&iter))) { if (!prop->set) { @@ -222,6 +224,17 @@ bool type_print_class_properties(const char *type) object_property_help(prop->name, prop->type, prop->defval, prop->descripti= on)); } + + class_property_iter_init(&iter, klass); + while ((cprop =3D class_property_iter_next(&iter))) { + if (!cprop->set) { + continue; + } + g_ptr_array_add(array, + object_property_help(cprop->name, cprop->type, + NULL, cprop->description)); + } + g_ptr_array_sort(array, (GCompareFunc)qemu_pstrcmp0); if (array->len > 0) { qemu_printf("%s options:\n", type); diff --git a/qom/qom-qmp-cmds.c b/qom/qom-qmp-cmds.c index 7c087299de..ea3f542a1d 100644 --- a/qom/qom-qmp-cmds.c +++ b/qom/qom-qmp-cmds.c @@ -34,6 +34,7 @@ ObjectPropertyInfoList *qmp_qom_list(const char *path, Er= ror **errp) bool ambiguous =3D false; ObjectPropertyInfoList *props =3D NULL; ObjectProperty *prop; + ClassProperty *cprop; ObjectPropertyIterator iter; =20 obj =3D object_resolve_path(path, &ambiguous); @@ -57,6 +58,16 @@ ObjectPropertyInfoList *qmp_qom_list(const char *path, E= rror **errp) value->type =3D g_strdup(prop->type); } =20 + class_property_iter_init(&iter, object_get_class(obj)); + while ((cprop =3D class_property_iter_next(&iter))) { + ObjectPropertyInfo *value =3D g_new0(ObjectPropertyInfo, 1); + + QAPI_LIST_PREPEND(props, value); + + value->name =3D g_strdup(cprop->name); + value->type =3D g_strdup(cprop->type); + } + return props; } =20 @@ -124,6 +135,7 @@ ObjectPropertyInfoList *qmp_device_list_properties(cons= t char *typename, ObjectClass *klass; Object *obj; ObjectProperty *prop; + ClassProperty *cprop; ObjectPropertyIterator iter; ObjectPropertyInfoList *prop_list =3D NULL; =20 @@ -172,6 +184,18 @@ ObjectPropertyInfoList *qmp_device_list_properties(con= st char *typename, QAPI_LIST_PREPEND(prop_list, info); } =20 + class_property_iter_init(&iter, klass); + while ((cprop =3D class_property_iter_next(&iter))) { + ObjectPropertyInfo *info; + + info =3D g_new0(ObjectPropertyInfo, 1); + info->name =3D g_strdup(cprop->name); + info->type =3D g_strdup(cprop->type); + info->description =3D g_strdup(cprop->description); + + QAPI_LIST_PREPEND(prop_list, info); + } + object_unref(obj); =20 return prop_list; @@ -183,6 +207,7 @@ ObjectPropertyInfoList *qmp_qom_list_properties(const c= har *typename, ObjectClass *klass; Object *obj =3D NULL; ObjectProperty *prop; + ClassProperty *cprop; ObjectPropertyIterator iter; ObjectPropertyInfoList *prop_list =3D NULL; =20 @@ -216,6 +241,18 @@ ObjectPropertyInfoList *qmp_qom_list_properties(const = char *typename, QAPI_LIST_PREPEND(prop_list, info); } =20 + class_property_iter_init(&iter, klass); + while ((cprop =3D class_property_iter_next(&iter))) { + ObjectPropertyInfo *info; + + info =3D g_malloc0(sizeof(*info)); + info->name =3D g_strdup(cprop->name); + info->type =3D g_strdup(cprop->type); + info->description =3D g_strdup(cprop->description); + + QAPI_LIST_PREPEND(prop_list, info); + } + object_unref(obj); =20 return prop_list; --=20 2.34.1