This is RFC because implementation depends on the upcoming class properties http://lists.nongnu.org/archive/html/qemu-devel/2015-08/msg03115.html and also because this patch does not handle all x86_64 properties.
This RFC is in response to concerns pointed in this review but with changed subject line as recommended. http://lists.nongnu.org/archive/html/qemu-devel/2016-01/msg00053.html This RFC demonstrates the way for displaying cpu properties using -cpu help option. Advantages: - It is flexible and could be extended to all targets. - With object class properties it would be possible to display cpu properties from the single place with better granularity. - displaying actual/default values for properties There are things left TODO: 1. The patch from Daniel P. Berrange should be submitted. - object properties now stored in hash table an dperhaps object class properties should be stored in hash table as well - add more functions for object class properties like getters, iterators etc. 2. The code duplication in cpu_* functions should be refactored in final patch. 3. All target-i386 cpu properties should be reviewed and set during class initialization. 4. Output formatting: - list cpu properties per CPUID - list cpu properties along with values 5. and more ... Signed-off-by: Valentin Rakush <valentin.rak...@gmail.com> --- include/qom/cpu.h | 2 + include/qom/object.h | 46 +++++++++++ qom/cpu.c | 50 ++++++++++++ qom/object.c | 220 +++++++++++++++++++++++++++++++++++++++++++++++++++ target-i386/cpu.c | 29 +++++++ vl.c | 2 + 6 files changed, 349 insertions(+) diff --git a/include/qom/cpu.h b/include/qom/cpu.h index 51a1323..4ec07ce 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -761,6 +761,8 @@ void QEMU_NORETURN cpu_abort(CPUState *cpu, const char *fmt, ...) GCC_FMT_ATTR(2, 3); void cpu_exec_exit(CPUState *cpu); +void cpu_properties_list(FILE *f, fprintf_function cpu_fprintf); + #ifdef CONFIG_SOFTMMU extern const struct VMStateDescription vmstate_cpu_common; #else diff --git a/include/qom/object.h b/include/qom/object.h index 4509166..9777565 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -344,6 +344,8 @@ typedef struct ObjectProperty ObjectPropertyResolve *resolve; ObjectPropertyRelease *release; void *opaque; + + QTAILQ_ENTRY(ObjectProperty) node; } ObjectProperty; /** @@ -381,6 +383,8 @@ struct ObjectClass const char *class_cast_cache[OBJECT_CLASS_CAST_CACHE]; ObjectUnparent *unparent; + + QTAILQ_HEAD(, ObjectProperty) properties; }; /** @@ -944,6 +948,13 @@ ObjectProperty *object_property_add(Object *obj, const char *name, void object_property_del(Object *obj, const char *name, Error **errp); +ObjectProperty *object_class_property_add(ObjectClass *klass, const char *name, + const char *type, + ObjectPropertyAccessor *get, + ObjectPropertyAccessor *set, + ObjectPropertyRelease *release, + void *opaque, Error **errp); + /** * object_property_find: * @obj: the object @@ -954,6 +965,8 @@ void object_property_del(Object *obj, const char *name, Error **errp); */ ObjectProperty *object_property_find(Object *obj, const char *name, Error **errp); +ObjectProperty *object_class_property_find(ObjectClass *klass, const char *name, + Error **errp); typedef struct ObjectPropertyIterator ObjectPropertyIterator; @@ -1371,6 +1384,12 @@ void object_property_add_str(Object *obj, const char *name, void (*set)(Object *, const char *, Error **), Error **errp); +void object_class_property_add_str(ObjectClass *klass, const char *name, + char *(*get)(Object *, Error **), + void (*set)(Object *, const char *, + Error **), + Error **errp); + /** * object_property_add_bool: * @obj: the object to add a property to @@ -1387,6 +1406,11 @@ void object_property_add_bool(Object *obj, const char *name, void (*set)(Object *, bool, Error **), Error **errp); +void object_class_property_add_bool(ObjectClass *klass, const char *name, + bool (*get)(Object *, Error **), + void (*set)(Object *, bool, Error **), + Error **errp); + /** * object_property_add_enum: * @obj: the object to add a property to @@ -1406,6 +1430,13 @@ void object_property_add_enum(Object *obj, const char *name, void (*set)(Object *, int, Error **), Error **errp); +void object_class_property_add_enum(ObjectClass *klass, const char *name, + const char *typename, + const char * const *strings, + int (*get)(Object *, Error **), + void (*set)(Object *, int, Error **), + Error **errp); + /** * object_property_add_tm: * @obj: the object to add a property to @@ -1420,6 +1451,10 @@ void object_property_add_tm(Object *obj, const char *name, void (*get)(Object *, struct tm *, Error **), Error **errp); +void object_class_property_add_tm(ObjectClass *klass, const char *name, + void (*get)(Object *, struct tm *, Error **), + Error **errp); + /** * object_property_add_uint8_ptr: * @obj: the object to add a property to @@ -1432,6 +1467,8 @@ void object_property_add_tm(Object *obj, const char *name, */ void object_property_add_uint8_ptr(Object *obj, const char *name, const uint8_t *v, Error **errp); +void object_class_property_add_uint8_ptr(ObjectClass *klass, const char *name, + const uint8_t *v, Error **errp); /** * object_property_add_uint16_ptr: @@ -1445,6 +1482,8 @@ void object_property_add_uint8_ptr(Object *obj, const char *name, */ void object_property_add_uint16_ptr(Object *obj, const char *name, const uint16_t *v, Error **errp); +void object_class_property_add_uint16_ptr(ObjectClass *klass, const char *name, + const uint16_t *v, Error **errp); /** * object_property_add_uint32_ptr: @@ -1458,6 +1497,8 @@ void object_property_add_uint16_ptr(Object *obj, const char *name, */ void object_property_add_uint32_ptr(Object *obj, const char *name, const uint32_t *v, Error **errp); +void object_class_property_add_uint32_ptr(ObjectClass *klass, const char *name, + const uint32_t *v, Error **errp); /** * object_property_add_uint64_ptr: @@ -1471,6 +1512,8 @@ void object_property_add_uint32_ptr(Object *obj, const char *name, */ void object_property_add_uint64_ptr(Object *obj, const char *name, const uint64_t *v, Error **Errp); +void object_class_property_add_uint64_ptr(ObjectClass *klass, const char *name, + const uint64_t *v, Error **Errp); /** * object_property_add_alias: @@ -1522,6 +1565,9 @@ void object_property_add_const_link(Object *obj, const char *name, */ void object_property_set_description(Object *obj, const char *name, const char *description, Error **errp); +void object_class_property_set_description(ObjectClass *klass, const char *name, + const char *description, + Error **errp); /** * object_child_foreach: diff --git a/qom/cpu.c b/qom/cpu.c index fb80d13..8951f61 100644 --- a/qom/cpu.c +++ b/qom/cpu.c @@ -25,6 +25,7 @@ #include "qemu/log.h" #include "qemu/error-report.h" #include "sysemu/sysemu.h" +#include "exec/cpu-common.h" bool cpu_exists(int64_t id) { @@ -379,4 +380,53 @@ static void cpu_register_types(void) type_register_static(&cpu_type_info); } +static void cpu_class_list_properties(ObjectClass* klass, FILE *f, fprintf_function cpu_fprintf) +{ + ObjectProperty *prop; + ObjectClass *parent_klass; + + parent_klass = object_class_get_parent(klass); + if (parent_klass) { + cpu_class_list_properties(parent_klass, f, cpu_fprintf); + } + + QTAILQ_FOREACH(prop, &klass->properties, node) { + (*cpu_fprintf)(f, "%s ", prop->name); + } +} + +static void cpu_list_entry(gpointer data, gpointer user_data) +{ + ObjectClass *oc = data; + CPUListState *s = user_data; + const char *typename; + char *name; + + typename = object_class_get_name(oc); + name = g_strndup(typename, strlen(typename) - strlen("-" TYPE_CPU)); + (*s->cpu_fprintf)(s->file, " %s : " , name); + + cpu_class_list_properties(oc, s->file, s->cpu_fprintf); + + (*s->cpu_fprintf)(s->file, "\n"); + + g_free(name); +} + +void cpu_properties_list(FILE *f, fprintf_function cpu_fprintf) +{ + CPUListState s = { + .file = f, + .cpu_fprintf = cpu_fprintf, + }; + GSList *list; + + list = object_class_get_list(TYPE_CPU, false); + g_slist_foreach(list, cpu_list_entry, &s); + g_slist_free(list); + + (*cpu_fprintf)(f, "\n"); +} + + type_init(cpu_register_types) diff --git a/qom/object.c b/qom/object.c index d751569..8a5f8bc 100644 --- a/qom/object.c +++ b/qom/object.c @@ -268,6 +268,7 @@ static void type_initialize(TypeImpl *ti) g_assert_cmpint(parent->class_size, <=, ti->class_size); memcpy(ti->class, parent->class, parent->class_size); ti->class->interfaces = NULL; + QTAILQ_INIT(&ti->class->properties); for (e = parent->class->interfaces; e; e = e->next) { InterfaceClass *iface = e->data; @@ -292,6 +293,8 @@ static void type_initialize(TypeImpl *ti) type_initialize_interface(ti, t, t); } + } else { + QTAILQ_INIT(&ti->class->properties); } ti->class->type = ti; @@ -939,10 +942,70 @@ object_property_add(Object *obj, const char *name, const char *type, return prop; } +ObjectProperty * +object_class_property_add(ObjectClass *klass, + const char *name, + const char *type, + ObjectPropertyAccessor *get, + ObjectPropertyAccessor *set, + ObjectPropertyRelease *release, + void *opaque, + Error **errp) +{ + ObjectProperty *prop; + size_t name_len = strlen(name); + + if (name_len >= 3 && !memcmp(name + name_len - 3, "[*]", 4)) { + int i; + ObjectProperty *ret; + char *name_no_array = g_strdup(name); + + name_no_array[name_len - 3] = '\0'; + for (i = 0; ; ++i) { + char *full_name = g_strdup_printf("%s[%d]", name_no_array, i); + + ret = object_class_property_add(klass, full_name, type, get, set, + release, opaque, NULL); + g_free(full_name); + if (ret) { + break; + } + } + g_free(name_no_array); + return ret; + } + + if (object_class_property_find(klass, name, NULL) != NULL) { + error_setg(errp, "attempt to add duplicate property '%s'" + " to object (type '%s')", name, + object_class_get_name(klass)); + return NULL; + } + + prop = g_malloc0(sizeof(*prop)); + + prop->name = g_strdup(name); + prop->type = g_strdup(type); + + prop->get = get; + prop->set = set; + prop->release = release; + prop->opaque = opaque; + + QTAILQ_INSERT_TAIL(&klass->properties, prop, node); + return prop; +} + ObjectProperty *object_property_find(Object *obj, const char *name, Error **errp) { ObjectProperty *prop; + ObjectClass *klass = object_get_class(obj); + + prop = object_class_property_find(klass, name, NULL); + if (prop) { + return prop; + } prop = g_hash_table_lookup(obj->properties, name); if (prop) { @@ -977,6 +1040,30 @@ ObjectProperty *object_property_iter_next(ObjectPropertyIterator *iter) return val; } +ObjectProperty *object_class_property_find(ObjectClass *klass, const char *name, + Error **errp) +{ + ObjectProperty *prop; + ObjectClass *parent_klass; + + parent_klass = object_class_get_parent(klass); + if (parent_klass) { + prop = object_class_property_find(parent_klass, name, NULL); + if (prop) { + return prop; + } + } + + QTAILQ_FOREACH(prop, &klass->properties, node) { + if (strcmp(prop->name, name) == 0) { + return prop; + } + } + + error_setg(errp, "Property '.%s' not found", name); + return NULL; +} + void object_property_del(Object *obj, const char *name, Error **errp) { ObjectProperty *prop = g_hash_table_lookup(obj->properties, name); @@ -1730,6 +1817,29 @@ void object_property_add_str(Object *obj, const char *name, } } +void object_class_property_add_str(ObjectClass *klass, const char *name, + char *(*get)(Object *, Error **), + void (*set)(Object *, const char *, + Error **), + Error **errp) +{ + Error *local_err = NULL; + StringProperty *prop = g_malloc0(sizeof(*prop)); + + prop->get = get; + prop->set = set; + + object_class_property_add(klass, name, "string", + get ? property_get_str : NULL, + set ? property_set_str : NULL, + property_release_str, + prop, &local_err); + if (local_err) { + error_propagate(errp, local_err); + g_free(prop); + } +} + typedef struct BoolProperty { bool (*get)(Object *, Error **); @@ -1797,6 +1907,28 @@ void object_property_add_bool(Object *obj, const char *name, } } +void object_class_property_add_bool(ObjectClass *klass, const char *name, + bool (*get)(Object *, Error **), + void (*set)(Object *, bool, Error **), + Error **errp) +{ + Error *local_err = NULL; + BoolProperty *prop = g_malloc0(sizeof(*prop)); + + prop->get = get; + prop->set = set; + + object_class_property_add(klass, name, "bool", + get ? property_get_bool : NULL, + set ? property_set_bool : NULL, + property_release_bool, + prop, &local_err); + if (local_err) { + error_propagate(errp, local_err); + g_free(prop); + } +} + static void property_get_enum(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { @@ -1860,6 +1992,31 @@ void object_property_add_enum(Object *obj, const char *name, } } +void object_class_property_add_enum(ObjectClass *klass, const char *name, + const char *typename, + const char * const *strings, + int (*get)(Object *, Error **), + void (*set)(Object *, int, Error **), + Error **errp) +{ + Error *local_err = NULL; + EnumProperty *prop = g_malloc(sizeof(*prop)); + + prop->strings = strings; + prop->get = get; + prop->set = set; + + object_class_property_add(klass, name, typename, + get ? property_get_enum : NULL, + set ? property_set_enum : NULL, + property_release_enum, + prop, &local_err); + if (local_err) { + error_propagate(errp, local_err); + g_free(prop); + } +} + typedef struct TMProperty { void (*get)(Object *, struct tm *, Error **); } TMProperty; @@ -1939,6 +2096,25 @@ void object_property_add_tm(Object *obj, const char *name, } } +void object_class_property_add_tm(ObjectClass *klass, const char *name, + void (*get)(Object *, struct tm *, Error **), + Error **errp) +{ + Error *local_err = NULL; + TMProperty *prop = g_malloc0(sizeof(*prop)); + + prop->get = get; + + object_class_property_add(klass, name, "struct tm", + get ? property_get_tm : NULL, NULL, + property_release_tm, + prop, &local_err); + if (local_err) { + error_propagate(errp, local_err); + g_free(prop); + } +} + static char *qdev_get_type(Object *obj, Error **errp) { return g_strdup(object_get_typename(obj)); @@ -1983,6 +2159,13 @@ void object_property_add_uint8_ptr(Object *obj, const char *name, NULL, NULL, (void *)v, errp); } +void object_class_property_add_uint8_ptr(ObjectClass *klass, const char *name, + const uint8_t *v, Error **errp) +{ + object_class_property_add(klass, name, "uint8", property_get_uint8_ptr, + NULL, NULL, (void *)v, errp); +} + void object_property_add_uint16_ptr(Object *obj, const char *name, const uint16_t *v, Error **errp) { @@ -1990,6 +2173,13 @@ void object_property_add_uint16_ptr(Object *obj, const char *name, NULL, NULL, (void *)v, errp); } +void object_class_property_add_uint16_ptr(ObjectClass *klass, const char *name, + const uint16_t *v, Error **errp) +{ + object_class_property_add(klass, name, "uint16", property_get_uint16_ptr, + NULL, NULL, (void *)v, errp); +} + void object_property_add_uint32_ptr(Object *obj, const char *name, const uint32_t *v, Error **errp) { @@ -1997,6 +2187,13 @@ void object_property_add_uint32_ptr(Object *obj, const char *name, NULL, NULL, (void *)v, errp); } +void object_class_property_add_uint32_ptr(ObjectClass *klass, const char *name, + const uint32_t *v, Error **errp) +{ + object_class_property_add(klass, name, "uint32", property_get_uint32_ptr, + NULL, NULL, (void *)v, errp); +} + void object_property_add_uint64_ptr(Object *obj, const char *name, const uint64_t *v, Error **errp) { @@ -2004,6 +2201,13 @@ void object_property_add_uint64_ptr(Object *obj, const char *name, NULL, NULL, (void *)v, errp); } +void object_class_property_add_uint64_ptr(ObjectClass *klass, const char *name, + const uint64_t *v, Error **errp) +{ + object_class_property_add(klass, name, "uint64", property_get_uint64_ptr, + NULL, NULL, (void *)v, errp); +} + typedef struct { Object *target_obj; char *target_name; @@ -2101,6 +2305,22 @@ void object_property_set_description(Object *obj, const char *name, op->description = g_strdup(description); } +void object_class_property_set_description(ObjectClass *klass, + const char *name, + const char *description, + Error **errp) +{ + ObjectProperty *op; + + op = object_class_property_find(klass, name, errp); + if (!op) { + return; + } + + g_free(op->description); + op->description = g_strdup(description); +} + static void object_instance_init(Object *obj) { object_property_add_str(obj, "type", qdev_get_type, NULL, NULL); diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 0d447b5..13c36a9 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -3202,6 +3202,35 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data) cc->cpu_exec_enter = x86_cpu_exec_enter; cc->cpu_exec_exit = x86_cpu_exec_exit; + + object_class_property_add(oc, "family", "int", + x86_cpuid_version_get_family, + x86_cpuid_version_set_family, NULL, NULL, NULL); + object_class_property_add(oc, "model", "int", + x86_cpuid_version_get_model, + x86_cpuid_version_set_model, NULL, NULL, NULL); + object_class_property_add(oc, "stepping", "int", + x86_cpuid_version_get_stepping, + x86_cpuid_version_set_stepping, NULL, NULL, NULL); + object_class_property_add_str(oc, "vendor", + x86_cpuid_get_vendor, + x86_cpuid_set_vendor, NULL); + object_class_property_add_str(oc, "model-id", + x86_cpuid_get_model_id, + x86_cpuid_set_model_id, NULL); + object_class_property_add(oc, "tsc-frequency", "int", + x86_cpuid_get_tsc_freq, + x86_cpuid_set_tsc_freq, NULL, NULL, NULL); + object_class_property_add(oc, "apic-id", "int", + x86_cpuid_get_apic_id, + x86_cpuid_set_apic_id, NULL, NULL, NULL); + object_class_property_add(oc, "feature-words", "X86CPUFeatureWordInfo", + x86_cpu_get_feature_words, + NULL, NULL, NULL, NULL); + object_class_property_add(oc, "filtered-features", "X86CPUFeatureWordInfo", + x86_cpu_get_feature_words, + NULL, NULL, NULL, NULL); + /* * Reason: x86_cpu_initfn() calls cpu_exec_init(), which saves the * object in cpus -> dangling pointer after final object_unref(). diff --git a/vl.c b/vl.c index 5aaea77..ebe4552 100644 --- a/vl.c +++ b/vl.c @@ -4092,6 +4092,8 @@ int main(int argc, char **argv, char **envp) if (cpu_model && is_help_option(cpu_model)) { list_cpus(stdout, &fprintf, cpu_model); + printf("\nRecognized CPUID properties:\n"); + cpu_properties_list(stdout, &fprintf); exit(0); } -- 1.8.3.1