diff options
| author | fishsoupisgood <github@madingley.org> | 2019-04-29 01:17:54 +0100 | 
|---|---|---|
| committer | fishsoupisgood <github@madingley.org> | 2019-05-27 03:43:43 +0100 | 
| commit | 3f2546b2ef55b661fd8dd69682b38992225e86f6 (patch) | |
| tree | 65ca85f13617aee1dce474596800950f266a456c /qom | |
| download | qemu-master.tar.gz qemu-master.tar.bz2 qemu-master.zip  | |
Diffstat (limited to 'qom')
| -rw-r--r-- | qom/Makefile.objs | 3 | ||||
| -rw-r--r-- | qom/container.c | 52 | ||||
| -rw-r--r-- | qom/cpu.c | 378 | ||||
| -rw-r--r-- | qom/object.c | 2049 | ||||
| -rw-r--r-- | qom/object_interfaces.c | 44 | ||||
| -rw-r--r-- | qom/qom-qobject.c | 44 | 
6 files changed, 2570 insertions, 0 deletions
diff --git a/qom/Makefile.objs b/qom/Makefile.objs new file mode 100644 index 00000000..985003bd --- /dev/null +++ b/qom/Makefile.objs @@ -0,0 +1,3 @@ +common-obj-y = object.o container.o qom-qobject.o +common-obj-y += cpu.o +common-obj-y += object_interfaces.o diff --git a/qom/container.c b/qom/container.c new file mode 100644 index 00000000..62b1648a --- /dev/null +++ b/qom/container.c @@ -0,0 +1,52 @@ +/* + * Device Container + * + * Copyright IBM, Corp. 2012 + * + * Authors: + *  Anthony Liguori   <aliguori@us.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qom/object.h" +#include "qemu/module.h" +#include <assert.h> + +static const TypeInfo container_info = { +    .name          = "container", +    .instance_size = sizeof(Object), +    .parent        = TYPE_OBJECT, +}; + +static void container_register_types(void) +{ +    type_register_static(&container_info); +} + +Object *container_get(Object *root, const char *path) +{ +    Object *obj, *child; +    gchar **parts; +    int i; + +    parts = g_strsplit(path, "/", 0); +    assert(parts != NULL && parts[0] != NULL && !parts[0][0]); +    obj = root; + +    for (i = 1; parts[i] != NULL; i++, obj = child) { +        child = object_resolve_path_component(obj, parts[i]); +        if (!child) { +            child = object_new("container"); +            object_property_add_child(obj, parts[i], child, NULL); +        } +    } + +    g_strfreev(parts); + +    return obj; +} + + +type_init(container_register_types) diff --git a/qom/cpu.c b/qom/cpu.c new file mode 100644 index 00000000..eb9cfeca --- /dev/null +++ b/qom/cpu.c @@ -0,0 +1,378 @@ +/* + * QEMU CPU model + * + * Copyright (c) 2012-2014 SUSE LINUX Products GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see + * <http://www.gnu.org/licenses/gpl-2.0.html> + */ + +#include "qemu-common.h" +#include "qom/cpu.h" +#include "sysemu/kvm.h" +#include "qemu/notify.h" +#include "qemu/log.h" +#include "qemu/error-report.h" +#include "sysemu/sysemu.h" + +bool cpu_exists(int64_t id) +{ +    CPUState *cpu; + +    CPU_FOREACH(cpu) { +        CPUClass *cc = CPU_GET_CLASS(cpu); + +        if (cc->get_arch_id(cpu) == id) { +            return true; +        } +    } +    return false; +} + +CPUState *cpu_generic_init(const char *typename, const char *cpu_model) +{ +    char *str, *name, *featurestr; +    CPUState *cpu; +    ObjectClass *oc; +    CPUClass *cc; +    Error *err = NULL; + +    str = g_strdup(cpu_model); +    name = strtok(str, ","); + +    oc = cpu_class_by_name(typename, name); +    if (oc == NULL) { +        g_free(str); +        return NULL; +    } + +    cpu = CPU(object_new(object_class_get_name(oc))); +    cc = CPU_GET_CLASS(cpu); + +    featurestr = strtok(NULL, ","); +    cc->parse_features(cpu, featurestr, &err); +    g_free(str); +    if (err != NULL) { +        goto out; +    } + +    object_property_set_bool(OBJECT(cpu), true, "realized", &err); + +out: +    if (err != NULL) { +        error_report_err(err); +        object_unref(OBJECT(cpu)); +        return NULL; +    } + +    return cpu; +} + +bool cpu_paging_enabled(const CPUState *cpu) +{ +    CPUClass *cc = CPU_GET_CLASS(cpu); + +    return cc->get_paging_enabled(cpu); +} + +static bool cpu_common_get_paging_enabled(const CPUState *cpu) +{ +    return false; +} + +void cpu_get_memory_mapping(CPUState *cpu, MemoryMappingList *list, +                            Error **errp) +{ +    CPUClass *cc = CPU_GET_CLASS(cpu); + +    cc->get_memory_mapping(cpu, list, errp); +} + +static void cpu_common_get_memory_mapping(CPUState *cpu, +                                          MemoryMappingList *list, +                                          Error **errp) +{ +    error_setg(errp, "Obtaining memory mappings is unsupported on this CPU."); +} + +void cpu_reset_interrupt(CPUState *cpu, int mask) +{ +    cpu->interrupt_request &= ~mask; +} + +void cpu_exit(CPUState *cpu) +{ +    cpu->exit_request = 1; +    cpu->tcg_exit_req = 1; +} + +int cpu_write_elf32_qemunote(WriteCoreDumpFunction f, CPUState *cpu, +                             void *opaque) +{ +    CPUClass *cc = CPU_GET_CLASS(cpu); + +    return (*cc->write_elf32_qemunote)(f, cpu, opaque); +} + +static int cpu_common_write_elf32_qemunote(WriteCoreDumpFunction f, +                                           CPUState *cpu, void *opaque) +{ +    return -1; +} + +int cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cpu, +                         int cpuid, void *opaque) +{ +    CPUClass *cc = CPU_GET_CLASS(cpu); + +    return (*cc->write_elf32_note)(f, cpu, cpuid, opaque); +} + +static int cpu_common_write_elf32_note(WriteCoreDumpFunction f, +                                       CPUState *cpu, int cpuid, +                                       void *opaque) +{ +    return -1; +} + +int cpu_write_elf64_qemunote(WriteCoreDumpFunction f, CPUState *cpu, +                             void *opaque) +{ +    CPUClass *cc = CPU_GET_CLASS(cpu); + +    return (*cc->write_elf64_qemunote)(f, cpu, opaque); +} + +static int cpu_common_write_elf64_qemunote(WriteCoreDumpFunction f, +                                           CPUState *cpu, void *opaque) +{ +    return -1; +} + +int cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cpu, +                         int cpuid, void *opaque) +{ +    CPUClass *cc = CPU_GET_CLASS(cpu); + +    return (*cc->write_elf64_note)(f, cpu, cpuid, opaque); +} + +static int cpu_common_write_elf64_note(WriteCoreDumpFunction f, +                                       CPUState *cpu, int cpuid, +                                       void *opaque) +{ +    return -1; +} + + +static int cpu_common_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg) +{ +    return 0; +} + +static int cpu_common_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg) +{ +    return 0; +} + +bool target_words_bigendian(void); +static bool cpu_common_virtio_is_big_endian(CPUState *cpu) +{ +    return target_words_bigendian(); +} + +static void cpu_common_noop(CPUState *cpu) +{ +} + +static bool cpu_common_exec_interrupt(CPUState *cpu, int int_req) +{ +    return false; +} + +void cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf, +                    int flags) +{ +    CPUClass *cc = CPU_GET_CLASS(cpu); + +    if (cc->dump_state) { +        cpu_synchronize_state(cpu); +        cc->dump_state(cpu, f, cpu_fprintf, flags); +    } +} + +void cpu_dump_statistics(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf, +                         int flags) +{ +    CPUClass *cc = CPU_GET_CLASS(cpu); + +    if (cc->dump_statistics) { +        cc->dump_statistics(cpu, f, cpu_fprintf, flags); +    } +} + +void cpu_reset(CPUState *cpu) +{ +    CPUClass *klass = CPU_GET_CLASS(cpu); + +    if (klass->reset != NULL) { +        (*klass->reset)(cpu); +    } +} + +static void cpu_common_reset(CPUState *cpu) +{ +    CPUClass *cc = CPU_GET_CLASS(cpu); + +    if (qemu_loglevel_mask(CPU_LOG_RESET)) { +        qemu_log("CPU Reset (CPU %d)\n", cpu->cpu_index); +        log_cpu_state(cpu, cc->reset_dump_flags); +    } + +    cpu->interrupt_request = 0; +    cpu->current_tb = NULL; +    cpu->halted = 0; +    cpu->mem_io_pc = 0; +    cpu->mem_io_vaddr = 0; +    cpu->icount_extra = 0; +    cpu->icount_decr.u32 = 0; +    cpu->can_do_io = 0; +    cpu->exception_index = -1; +    memset(cpu->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof(void *)); +} + +static bool cpu_common_has_work(CPUState *cs) +{ +    return false; +} + +ObjectClass *cpu_class_by_name(const char *typename, const char *cpu_model) +{ +    CPUClass *cc = CPU_CLASS(object_class_by_name(typename)); + +    return cc->class_by_name(cpu_model); +} + +static ObjectClass *cpu_common_class_by_name(const char *cpu_model) +{ +    return NULL; +} + +static void cpu_common_parse_features(CPUState *cpu, char *features, +                                      Error **errp) +{ +    char *featurestr; /* Single "key=value" string being parsed */ +    char *val; +    Error *err = NULL; + +    featurestr = features ? strtok(features, ",") : NULL; + +    while (featurestr) { +        val = strchr(featurestr, '='); +        if (val) { +            *val = 0; +            val++; +            object_property_parse(OBJECT(cpu), val, featurestr, &err); +            if (err) { +                error_propagate(errp, err); +                return; +            } +        } else { +            error_setg(errp, "Expected key=value format, found %s.", +                       featurestr); +            return; +        } +        featurestr = strtok(NULL, ","); +    } +} + +static void cpu_common_realizefn(DeviceState *dev, Error **errp) +{ +    CPUState *cpu = CPU(dev); + +    if (dev->hotplugged) { +        cpu_synchronize_post_init(cpu); +        cpu_resume(cpu); +    } +} + +static void cpu_common_initfn(Object *obj) +{ +    CPUState *cpu = CPU(obj); +    CPUClass *cc = CPU_GET_CLASS(obj); + +    cpu->cpu_index = -1; +    cpu->gdb_num_regs = cpu->gdb_num_g_regs = cc->gdb_num_core_regs; +    QTAILQ_INIT(&cpu->breakpoints); +    QTAILQ_INIT(&cpu->watchpoints); +} + +static void cpu_common_finalize(Object *obj) +{ +    cpu_exec_exit(CPU(obj)); +} + +static int64_t cpu_common_get_arch_id(CPUState *cpu) +{ +    return cpu->cpu_index; +} + +static void cpu_class_init(ObjectClass *klass, void *data) +{ +    DeviceClass *dc = DEVICE_CLASS(klass); +    CPUClass *k = CPU_CLASS(klass); + +    k->class_by_name = cpu_common_class_by_name; +    k->parse_features = cpu_common_parse_features; +    k->reset = cpu_common_reset; +    k->get_arch_id = cpu_common_get_arch_id; +    k->has_work = cpu_common_has_work; +    k->get_paging_enabled = cpu_common_get_paging_enabled; +    k->get_memory_mapping = cpu_common_get_memory_mapping; +    k->write_elf32_qemunote = cpu_common_write_elf32_qemunote; +    k->write_elf32_note = cpu_common_write_elf32_note; +    k->write_elf64_qemunote = cpu_common_write_elf64_qemunote; +    k->write_elf64_note = cpu_common_write_elf64_note; +    k->gdb_read_register = cpu_common_gdb_read_register; +    k->gdb_write_register = cpu_common_gdb_write_register; +    k->virtio_is_big_endian = cpu_common_virtio_is_big_endian; +    k->debug_excp_handler = cpu_common_noop; +    k->cpu_exec_enter = cpu_common_noop; +    k->cpu_exec_exit = cpu_common_noop; +    k->cpu_exec_interrupt = cpu_common_exec_interrupt; +    dc->realize = cpu_common_realizefn; +    /* +     * Reason: CPUs still need special care by board code: wiring up +     * IRQs, adding reset handlers, halting non-first CPUs, ... +     */ +    dc->cannot_instantiate_with_device_add_yet = true; +} + +static const TypeInfo cpu_type_info = { +    .name = TYPE_CPU, +    .parent = TYPE_DEVICE, +    .instance_size = sizeof(CPUState), +    .instance_init = cpu_common_initfn, +    .instance_finalize = cpu_common_finalize, +    .abstract = true, +    .class_size = sizeof(CPUClass), +    .class_init = cpu_class_init, +}; + +static void cpu_register_types(void) +{ +    type_register_static(&cpu_type_info); +} + +type_init(cpu_register_types) diff --git a/qom/object.c b/qom/object.c new file mode 100644 index 00000000..e14b9d86 --- /dev/null +++ b/qom/object.c @@ -0,0 +1,2049 @@ +/* + * QEMU Object Model + * + * Copyright IBM, Corp. 2011 + * + * Authors: + *  Anthony Liguori   <aliguori@us.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qom/object.h" +#include "qom/object_interfaces.h" +#include "qemu-common.h" +#include "qapi/visitor.h" +#include "qapi-visit.h" +#include "qapi/string-input-visitor.h" +#include "qapi/string-output-visitor.h" +#include "qapi/qmp/qerror.h" +#include "trace.h" + +/* TODO: replace QObject with a simpler visitor to avoid a dependency + * of the QOM core on QObject?  */ +#include "qom/qom-qobject.h" +#include "qapi/qmp/qobject.h" +#include "qapi/qmp/qbool.h" +#include "qapi/qmp/qint.h" +#include "qapi/qmp/qstring.h" + +#define MAX_INTERFACES 32 + +typedef struct InterfaceImpl InterfaceImpl; +typedef struct TypeImpl TypeImpl; + +struct InterfaceImpl +{ +    const char *typename; +}; + +struct TypeImpl +{ +    const char *name; + +    size_t class_size; + +    size_t instance_size; + +    void (*class_init)(ObjectClass *klass, void *data); +    void (*class_base_init)(ObjectClass *klass, void *data); +    void (*class_finalize)(ObjectClass *klass, void *data); + +    void *class_data; + +    void (*instance_init)(Object *obj); +    void (*instance_post_init)(Object *obj); +    void (*instance_finalize)(Object *obj); + +    bool abstract; + +    const char *parent; +    TypeImpl *parent_type; + +    ObjectClass *class; + +    int num_interfaces; +    InterfaceImpl interfaces[MAX_INTERFACES]; +}; + +static Type type_interface; + +static GHashTable *type_table_get(void) +{ +    static GHashTable *type_table; + +    if (type_table == NULL) { +        type_table = g_hash_table_new(g_str_hash, g_str_equal); +    } + +    return type_table; +} + +static bool enumerating_types; + +static void type_table_add(TypeImpl *ti) +{ +    assert(!enumerating_types); +    g_hash_table_insert(type_table_get(), (void *)ti->name, ti); +} + +static TypeImpl *type_table_lookup(const char *name) +{ +    return g_hash_table_lookup(type_table_get(), name); +} + +static TypeImpl *type_new(const TypeInfo *info) +{ +    TypeImpl *ti = g_malloc0(sizeof(*ti)); +    int i; + +    g_assert(info->name != NULL); + +    if (type_table_lookup(info->name) != NULL) { +        fprintf(stderr, "Registering `%s' which already exists\n", info->name); +        abort(); +    } + +    ti->name = g_strdup(info->name); +    ti->parent = g_strdup(info->parent); + +    ti->class_size = info->class_size; +    ti->instance_size = info->instance_size; + +    ti->class_init = info->class_init; +    ti->class_base_init = info->class_base_init; +    ti->class_finalize = info->class_finalize; +    ti->class_data = info->class_data; + +    ti->instance_init = info->instance_init; +    ti->instance_post_init = info->instance_post_init; +    ti->instance_finalize = info->instance_finalize; + +    ti->abstract = info->abstract; + +    for (i = 0; info->interfaces && info->interfaces[i].type; i++) { +        ti->interfaces[i].typename = g_strdup(info->interfaces[i].type); +    } +    ti->num_interfaces = i; + +    return ti; +} + +static TypeImpl *type_register_internal(const TypeInfo *info) +{ +    TypeImpl *ti; +    ti = type_new(info); + +    type_table_add(ti); +    return ti; +} + +TypeImpl *type_register(const TypeInfo *info) +{ +    assert(info->parent); +    return type_register_internal(info); +} + +TypeImpl *type_register_static(const TypeInfo *info) +{ +    return type_register(info); +} + +static TypeImpl *type_get_by_name(const char *name) +{ +    if (name == NULL) { +        return NULL; +    } + +    return type_table_lookup(name); +} + +static TypeImpl *type_get_parent(TypeImpl *type) +{ +    if (!type->parent_type && type->parent) { +        type->parent_type = type_get_by_name(type->parent); +        g_assert(type->parent_type != NULL); +    } + +    return type->parent_type; +} + +static bool type_has_parent(TypeImpl *type) +{ +    return (type->parent != NULL); +} + +static size_t type_class_get_size(TypeImpl *ti) +{ +    if (ti->class_size) { +        return ti->class_size; +    } + +    if (type_has_parent(ti)) { +        return type_class_get_size(type_get_parent(ti)); +    } + +    return sizeof(ObjectClass); +} + +static size_t type_object_get_size(TypeImpl *ti) +{ +    if (ti->instance_size) { +        return ti->instance_size; +    } + +    if (type_has_parent(ti)) { +        return type_object_get_size(type_get_parent(ti)); +    } + +    return 0; +} + +static bool type_is_ancestor(TypeImpl *type, TypeImpl *target_type) +{ +    assert(target_type); + +    /* Check if typename is a direct ancestor of type */ +    while (type) { +        if (type == target_type) { +            return true; +        } + +        type = type_get_parent(type); +    } + +    return false; +} + +static void type_initialize(TypeImpl *ti); + +static void type_initialize_interface(TypeImpl *ti, TypeImpl *interface_type, +                                      TypeImpl *parent_type) +{ +    InterfaceClass *new_iface; +    TypeInfo info = { }; +    TypeImpl *iface_impl; + +    info.parent = parent_type->name; +    info.name = g_strdup_printf("%s::%s", ti->name, interface_type->name); +    info.abstract = true; + +    iface_impl = type_new(&info); +    iface_impl->parent_type = parent_type; +    type_initialize(iface_impl); +    g_free((char *)info.name); + +    new_iface = (InterfaceClass *)iface_impl->class; +    new_iface->concrete_class = ti->class; +    new_iface->interface_type = interface_type; + +    ti->class->interfaces = g_slist_append(ti->class->interfaces, +                                           iface_impl->class); +} + +static void type_initialize(TypeImpl *ti) +{ +    TypeImpl *parent; + +    if (ti->class) { +        return; +    } + +    ti->class_size = type_class_get_size(ti); +    ti->instance_size = type_object_get_size(ti); + +    ti->class = g_malloc0(ti->class_size); + +    parent = type_get_parent(ti); +    if (parent) { +        type_initialize(parent); +        GSList *e; +        int i; + +        g_assert(parent->class_size <= ti->class_size); +        memcpy(ti->class, parent->class, parent->class_size); +        ti->class->interfaces = NULL; + +        for (e = parent->class->interfaces; e; e = e->next) { +            InterfaceClass *iface = e->data; +            ObjectClass *klass = OBJECT_CLASS(iface); + +            type_initialize_interface(ti, iface->interface_type, klass->type); +        } + +        for (i = 0; i < ti->num_interfaces; i++) { +            TypeImpl *t = type_get_by_name(ti->interfaces[i].typename); +            for (e = ti->class->interfaces; e; e = e->next) { +                TypeImpl *target_type = OBJECT_CLASS(e->data)->type; + +                if (type_is_ancestor(target_type, t)) { +                    break; +                } +            } + +            if (e) { +                continue; +            } + +            type_initialize_interface(ti, t, t); +        } +    } + +    ti->class->type = ti; + +    while (parent) { +        if (parent->class_base_init) { +            parent->class_base_init(ti->class, ti->class_data); +        } +        parent = type_get_parent(parent); +    } + +    if (ti->class_init) { +        ti->class_init(ti->class, ti->class_data); +    } +} + +static void object_init_with_type(Object *obj, TypeImpl *ti) +{ +    if (type_has_parent(ti)) { +        object_init_with_type(obj, type_get_parent(ti)); +    } + +    if (ti->instance_init) { +        ti->instance_init(obj); +    } +} + +static void object_post_init_with_type(Object *obj, TypeImpl *ti) +{ +    if (ti->instance_post_init) { +        ti->instance_post_init(obj); +    } + +    if (type_has_parent(ti)) { +        object_post_init_with_type(obj, type_get_parent(ti)); +    } +} + +void object_initialize_with_type(void *data, size_t size, TypeImpl *type) +{ +    Object *obj = data; + +    g_assert(type != NULL); +    type_initialize(type); + +    g_assert(type->instance_size >= sizeof(Object)); +    g_assert(type->abstract == false); +    g_assert(size >= type->instance_size); + +    memset(obj, 0, type->instance_size); +    obj->class = type->class; +    object_ref(obj); +    QTAILQ_INIT(&obj->properties); +    object_init_with_type(obj, type); +    object_post_init_with_type(obj, type); +} + +void object_initialize(void *data, size_t size, const char *typename) +{ +    TypeImpl *type = type_get_by_name(typename); + +    object_initialize_with_type(data, size, type); +} + +static inline bool object_property_is_child(ObjectProperty *prop) +{ +    return strstart(prop->type, "child<", NULL); +} + +static void object_property_del_all(Object *obj) +{ +    while (!QTAILQ_EMPTY(&obj->properties)) { +        ObjectProperty *prop = QTAILQ_FIRST(&obj->properties); + +        QTAILQ_REMOVE(&obj->properties, prop, node); + +        if (prop->release) { +            prop->release(obj, prop->name, prop->opaque); +        } + +        g_free(prop->name); +        g_free(prop->type); +        g_free(prop->description); +        g_free(prop); +    } +} + +static void object_property_del_child(Object *obj, Object *child, Error **errp) +{ +    ObjectProperty *prop; + +    QTAILQ_FOREACH(prop, &obj->properties, node) { +        if (object_property_is_child(prop) && prop->opaque == child) { +            object_property_del(obj, prop->name, errp); +            break; +        } +    } +} + +void object_unparent(Object *obj) +{ +    if (obj->parent) { +        object_property_del_child(obj->parent, obj, NULL); +    } +} + +static void object_deinit(Object *obj, TypeImpl *type) +{ +    if (type->instance_finalize) { +        type->instance_finalize(obj); +    } + +    if (type_has_parent(type)) { +        object_deinit(obj, type_get_parent(type)); +    } +} + +static void object_finalize(void *data) +{ +    Object *obj = data; +    TypeImpl *ti = obj->class->type; + +    object_property_del_all(obj); +    object_deinit(obj, ti); + +    g_assert(obj->ref == 0); +    if (obj->free) { +        obj->free(obj); +    } +} + +Object *object_new_with_type(Type type) +{ +    Object *obj; + +    g_assert(type != NULL); +    type_initialize(type); + +    obj = g_malloc(type->instance_size); +    object_initialize_with_type(obj, type->instance_size, type); +    obj->free = g_free; + +    return obj; +} + +Object *object_new(const char *typename) +{ +    TypeImpl *ti = type_get_by_name(typename); + +    return object_new_with_type(ti); +} + + +Object *object_new_with_props(const char *typename, +                              Object *parent, +                              const char *id, +                              Error **errp, +                              ...) +{ +    va_list vargs; +    Object *obj; + +    va_start(vargs, errp); +    obj = object_new_with_propv(typename, parent, id, errp, vargs); +    va_end(vargs); + +    return obj; +} + + +Object *object_new_with_propv(const char *typename, +                              Object *parent, +                              const char *id, +                              Error **errp, +                              va_list vargs) +{ +    Object *obj; +    ObjectClass *klass; +    Error *local_err = NULL; + +    klass = object_class_by_name(typename); +    if (!klass) { +        error_setg(errp, "invalid object type: %s", typename); +        return NULL; +    } + +    if (object_class_is_abstract(klass)) { +        error_setg(errp, "object type '%s' is abstract", typename); +        return NULL; +    } +    obj = object_new(typename); + +    if (object_set_propv(obj, &local_err, vargs) < 0) { +        goto error; +    } + +    object_property_add_child(parent, id, obj, &local_err); +    if (local_err) { +        goto error; +    } + +    if (object_dynamic_cast(obj, TYPE_USER_CREATABLE)) { +        user_creatable_complete(obj, &local_err); +        if (local_err) { +            object_unparent(obj); +            goto error; +        } +    } + +    object_unref(OBJECT(obj)); +    return obj; + + error: +    if (local_err) { +        error_propagate(errp, local_err); +    } +    object_unref(obj); +    return NULL; +} + + +int object_set_props(Object *obj, +                     Error **errp, +                     ...) +{ +    va_list vargs; +    int ret; + +    va_start(vargs, errp); +    ret = object_set_propv(obj, errp, vargs); +    va_end(vargs); + +    return ret; +} + + +int object_set_propv(Object *obj, +                     Error **errp, +                     va_list vargs) +{ +    const char *propname; +    Error *local_err = NULL; + +    propname = va_arg(vargs, char *); +    while (propname != NULL) { +        const char *value = va_arg(vargs, char *); + +        g_assert(value != NULL); +        object_property_parse(obj, value, propname, &local_err); +        if (local_err) { +            error_propagate(errp, local_err); +            return -1; +        } +        propname = va_arg(vargs, char *); +    } + +    return 0; +} + + +Object *object_dynamic_cast(Object *obj, const char *typename) +{ +    if (obj && object_class_dynamic_cast(object_get_class(obj), typename)) { +        return obj; +    } + +    return NULL; +} + +Object *object_dynamic_cast_assert(Object *obj, const char *typename, +                                   const char *file, int line, const char *func) +{ +    trace_object_dynamic_cast_assert(obj ? obj->class->type->name : "(null)", +                                     typename, file, line, func); + +#ifdef CONFIG_QOM_CAST_DEBUG +    int i; +    Object *inst; + +    for (i = 0; obj && i < OBJECT_CLASS_CAST_CACHE; i++) { +        if (obj->class->object_cast_cache[i] == typename) { +            goto out; +        } +    } + +    inst = object_dynamic_cast(obj, typename); + +    if (!inst && obj) { +        fprintf(stderr, "%s:%d:%s: Object %p is not an instance of type %s\n", +                file, line, func, obj, typename); +        abort(); +    } + +    assert(obj == inst); + +    if (obj && obj == inst) { +        for (i = 1; i < OBJECT_CLASS_CAST_CACHE; i++) { +            obj->class->object_cast_cache[i - 1] = +                    obj->class->object_cast_cache[i]; +        } +        obj->class->object_cast_cache[i - 1] = typename; +    } + +out: +#endif +    return obj; +} + +ObjectClass *object_class_dynamic_cast(ObjectClass *class, +                                       const char *typename) +{ +    ObjectClass *ret = NULL; +    TypeImpl *target_type; +    TypeImpl *type; + +    if (!class) { +        return NULL; +    } + +    /* A simple fast path that can trigger a lot for leaf classes.  */ +    type = class->type; +    if (type->name == typename) { +        return class; +    } + +    target_type = type_get_by_name(typename); +    if (!target_type) { +        /* target class type unknown, so fail the cast */ +        return NULL; +    } + +    if (type->class->interfaces && +            type_is_ancestor(target_type, type_interface)) { +        int found = 0; +        GSList *i; + +        for (i = class->interfaces; i; i = i->next) { +            ObjectClass *target_class = i->data; + +            if (type_is_ancestor(target_class->type, target_type)) { +                ret = target_class; +                found++; +            } +         } + +        /* The match was ambiguous, don't allow a cast */ +        if (found > 1) { +            ret = NULL; +        } +    } else if (type_is_ancestor(type, target_type)) { +        ret = class; +    } + +    return ret; +} + +ObjectClass *object_class_dynamic_cast_assert(ObjectClass *class, +                                              const char *typename, +                                              const char *file, int line, +                                              const char *func) +{ +    ObjectClass *ret; + +    trace_object_class_dynamic_cast_assert(class ? class->type->name : "(null)", +                                           typename, file, line, func); + +#ifdef CONFIG_QOM_CAST_DEBUG +    int i; + +    for (i = 0; class && i < OBJECT_CLASS_CAST_CACHE; i++) { +        if (class->class_cast_cache[i] == typename) { +            ret = class; +            goto out; +        } +    } +#else +    if (!class || !class->interfaces) { +        return class; +    } +#endif + +    ret = object_class_dynamic_cast(class, typename); +    if (!ret && class) { +        fprintf(stderr, "%s:%d:%s: Object %p is not an instance of type %s\n", +                file, line, func, class, typename); +        abort(); +    } + +#ifdef CONFIG_QOM_CAST_DEBUG +    if (class && ret == class) { +        for (i = 1; i < OBJECT_CLASS_CAST_CACHE; i++) { +            class->class_cast_cache[i - 1] = class->class_cast_cache[i]; +        } +        class->class_cast_cache[i - 1] = typename; +    } +out: +#endif +    return ret; +} + +const char *object_get_typename(Object *obj) +{ +    return obj->class->type->name; +} + +ObjectClass *object_get_class(Object *obj) +{ +    return obj->class; +} + +bool object_class_is_abstract(ObjectClass *klass) +{ +    return klass->type->abstract; +} + +const char *object_class_get_name(ObjectClass *klass) +{ +    return klass->type->name; +} + +ObjectClass *object_class_by_name(const char *typename) +{ +    TypeImpl *type = type_get_by_name(typename); + +    if (!type) { +        return NULL; +    } + +    type_initialize(type); + +    return type->class; +} + +ObjectClass *object_class_get_parent(ObjectClass *class) +{ +    TypeImpl *type = type_get_parent(class->type); + +    if (!type) { +        return NULL; +    } + +    type_initialize(type); + +    return type->class; +} + +typedef struct OCFData +{ +    void (*fn)(ObjectClass *klass, void *opaque); +    const char *implements_type; +    bool include_abstract; +    void *opaque; +} OCFData; + +static void object_class_foreach_tramp(gpointer key, gpointer value, +                                       gpointer opaque) +{ +    OCFData *data = opaque; +    TypeImpl *type = value; +    ObjectClass *k; + +    type_initialize(type); +    k = type->class; + +    if (!data->include_abstract && type->abstract) { +        return; +    } + +    if (data->implements_type &&  +        !object_class_dynamic_cast(k, data->implements_type)) { +        return; +    } + +    data->fn(k, data->opaque); +} + +void object_class_foreach(void (*fn)(ObjectClass *klass, void *opaque), +                          const char *implements_type, bool include_abstract, +                          void *opaque) +{ +    OCFData data = { fn, implements_type, include_abstract, opaque }; + +    enumerating_types = true; +    g_hash_table_foreach(type_table_get(), object_class_foreach_tramp, &data); +    enumerating_types = false; +} + +int object_child_foreach(Object *obj, int (*fn)(Object *child, void *opaque), +                         void *opaque) +{ +    ObjectProperty *prop, *next; +    int ret = 0; + +    QTAILQ_FOREACH_SAFE(prop, &obj->properties, node, next) { +        if (object_property_is_child(prop)) { +            ret = fn(prop->opaque, opaque); +            if (ret != 0) { +                break; +            } +        } +    } +    return ret; +} + +static void object_class_get_list_tramp(ObjectClass *klass, void *opaque) +{ +    GSList **list = opaque; + +    *list = g_slist_prepend(*list, klass); +} + +GSList *object_class_get_list(const char *implements_type, +                              bool include_abstract) +{ +    GSList *list = NULL; + +    object_class_foreach(object_class_get_list_tramp, +                         implements_type, include_abstract, &list); +    return list; +} + +void object_ref(Object *obj) +{ +    if (!obj) { +        return; +    } +     atomic_inc(&obj->ref); +} + +void object_unref(Object *obj) +{ +    if (!obj) { +        return; +    } +    g_assert(obj->ref > 0); + +    /* parent always holds a reference to its children */ +    if (atomic_fetch_dec(&obj->ref) == 1) { +        object_finalize(obj); +    } +} + +ObjectProperty * +object_property_add(Object *obj, 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_property_add(obj, full_name, type, get, set, +                                      release, opaque, NULL); +            g_free(full_name); +            if (ret) { +                break; +            } +        } +        g_free(name_no_array); +        return ret; +    } + +    QTAILQ_FOREACH(prop, &obj->properties, node) { +        if (strcmp(prop->name, name) == 0) { +            error_setg(errp, "attempt to add duplicate property '%s'" +                       " to object (type '%s')", name, +                       object_get_typename(obj)); +            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(&obj->properties, prop, node); +    return prop; +} + +ObjectProperty *object_property_find(Object *obj, const char *name, +                                     Error **errp) +{ +    ObjectProperty *prop; + +    QTAILQ_FOREACH(prop, &obj->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 = object_property_find(obj, name, errp); +    if (prop == NULL) { +        return; +    } + +    if (prop->release) { +        prop->release(obj, name, prop->opaque); +    } + +    QTAILQ_REMOVE(&obj->properties, prop, node); + +    g_free(prop->name); +    g_free(prop->type); +    g_free(prop->description); +    g_free(prop); +} + +void object_property_get(Object *obj, Visitor *v, const char *name, +                         Error **errp) +{ +    ObjectProperty *prop = object_property_find(obj, name, errp); +    if (prop == NULL) { +        return; +    } + +    if (!prop->get) { +        error_setg(errp, QERR_PERMISSION_DENIED); +    } else { +        prop->get(obj, v, prop->opaque, name, errp); +    } +} + +void object_property_set(Object *obj, Visitor *v, const char *name, +                         Error **errp) +{ +    ObjectProperty *prop = object_property_find(obj, name, errp); +    if (prop == NULL) { +        return; +    } + +    if (!prop->set) { +        error_setg(errp, QERR_PERMISSION_DENIED); +    } else { +        prop->set(obj, v, prop->opaque, name, errp); +    } +} + +void object_property_set_str(Object *obj, const char *value, +                             const char *name, Error **errp) +{ +    QString *qstr = qstring_from_str(value); +    object_property_set_qobject(obj, QOBJECT(qstr), name, errp); + +    QDECREF(qstr); +} + +char *object_property_get_str(Object *obj, const char *name, +                              Error **errp) +{ +    QObject *ret = object_property_get_qobject(obj, name, errp); +    QString *qstring; +    char *retval; + +    if (!ret) { +        return NULL; +    } +    qstring = qobject_to_qstring(ret); +    if (!qstring) { +        error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name, "string"); +        retval = NULL; +    } else { +        retval = g_strdup(qstring_get_str(qstring)); +    } + +    QDECREF(qstring); +    return retval; +} + +void object_property_set_link(Object *obj, Object *value, +                              const char *name, Error **errp) +{ +    if (value) { +        gchar *path = object_get_canonical_path(value); +        object_property_set_str(obj, path, name, errp); +        g_free(path); +    } else { +        object_property_set_str(obj, "", name, errp); +    } +} + +Object *object_property_get_link(Object *obj, const char *name, +                                 Error **errp) +{ +    char *str = object_property_get_str(obj, name, errp); +    Object *target = NULL; + +    if (str && *str) { +        target = object_resolve_path(str, NULL); +        if (!target) { +            error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, +                      "Device '%s' not found", str); +        } +    } + +    g_free(str); +    return target; +} + +void object_property_set_bool(Object *obj, bool value, +                              const char *name, Error **errp) +{ +    QBool *qbool = qbool_from_bool(value); +    object_property_set_qobject(obj, QOBJECT(qbool), name, errp); + +    QDECREF(qbool); +} + +bool object_property_get_bool(Object *obj, const char *name, +                              Error **errp) +{ +    QObject *ret = object_property_get_qobject(obj, name, errp); +    QBool *qbool; +    bool retval; + +    if (!ret) { +        return false; +    } +    qbool = qobject_to_qbool(ret); +    if (!qbool) { +        error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name, "boolean"); +        retval = false; +    } else { +        retval = qbool_get_bool(qbool); +    } + +    QDECREF(qbool); +    return retval; +} + +void object_property_set_int(Object *obj, int64_t value, +                             const char *name, Error **errp) +{ +    QInt *qint = qint_from_int(value); +    object_property_set_qobject(obj, QOBJECT(qint), name, errp); + +    QDECREF(qint); +} + +int64_t object_property_get_int(Object *obj, const char *name, +                                Error **errp) +{ +    QObject *ret = object_property_get_qobject(obj, name, errp); +    QInt *qint; +    int64_t retval; + +    if (!ret) { +        return -1; +    } +    qint = qobject_to_qint(ret); +    if (!qint) { +        error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name, "int"); +        retval = -1; +    } else { +        retval = qint_get_int(qint); +    } + +    QDECREF(qint); +    return retval; +} + +typedef struct EnumProperty { +    const char * const *strings; +    int (*get)(Object *, Error **); +    void (*set)(Object *, int, Error **); +} EnumProperty; + +int object_property_get_enum(Object *obj, const char *name, +                             const char *typename, Error **errp) +{ +    Error *err = NULL; +    StringOutputVisitor *sov; +    StringInputVisitor *siv; +    char *str; +    int ret; +    ObjectProperty *prop = object_property_find(obj, name, errp); +    EnumProperty *enumprop; + +    if (prop == NULL) { +        return 0; +    } + +    if (!g_str_equal(prop->type, typename)) { +        error_setg(errp, "Property %s on %s is not '%s' enum type", +                   name, object_class_get_name( +                       object_get_class(obj)), typename); +        return 0; +    } + +    enumprop = prop->opaque; + +    sov = string_output_visitor_new(false); +    object_property_get(obj, string_output_get_visitor(sov), name, &err); +    if (err) { +        error_propagate(errp, err); +        string_output_visitor_cleanup(sov); +        return 0; +    } +    str = string_output_get_string(sov); +    siv = string_input_visitor_new(str); +    string_output_visitor_cleanup(sov); +    visit_type_enum(string_input_get_visitor(siv), +                    &ret, enumprop->strings, NULL, name, errp); + +    g_free(str); +    string_input_visitor_cleanup(siv); + +    return ret; +} + +void object_property_get_uint16List(Object *obj, const char *name, +                                    uint16List **list, Error **errp) +{ +    Error *err = NULL; +    StringOutputVisitor *ov; +    StringInputVisitor *iv; +    char *str; + +    ov = string_output_visitor_new(false); +    object_property_get(obj, string_output_get_visitor(ov), +                        name, &err); +    if (err) { +        error_propagate(errp, err); +        goto out; +    } +    str = string_output_get_string(ov); +    iv = string_input_visitor_new(str); +    visit_type_uint16List(string_input_get_visitor(iv), +                          list, NULL, errp); + +    g_free(str); +    string_input_visitor_cleanup(iv); +out: +    string_output_visitor_cleanup(ov); +} + +void object_property_parse(Object *obj, const char *string, +                           const char *name, Error **errp) +{ +    StringInputVisitor *mi; +    mi = string_input_visitor_new(string); +    object_property_set(obj, string_input_get_visitor(mi), name, errp); + +    string_input_visitor_cleanup(mi); +} + +char *object_property_print(Object *obj, const char *name, bool human, +                            Error **errp) +{ +    StringOutputVisitor *mo; +    char *string = NULL; +    Error *local_err = NULL; + +    mo = string_output_visitor_new(human); +    object_property_get(obj, string_output_get_visitor(mo), name, &local_err); +    if (local_err) { +        error_propagate(errp, local_err); +        goto out; +    } + +    string = string_output_get_string(mo); + +out: +    string_output_visitor_cleanup(mo); +    return string; +} + +const char *object_property_get_type(Object *obj, const char *name, Error **errp) +{ +    ObjectProperty *prop = object_property_find(obj, name, errp); +    if (prop == NULL) { +        return NULL; +    } + +    return prop->type; +} + +Object *object_get_root(void) +{ +    static Object *root; + +    if (!root) { +        root = object_new("container"); +    } + +    return root; +} + +Object *object_get_objects_root(void) +{ +    return container_get(object_get_root(), "/objects"); +} + +static void object_get_child_property(Object *obj, Visitor *v, void *opaque, +                                      const char *name, Error **errp) +{ +    Object *child = opaque; +    gchar *path; + +    path = object_get_canonical_path(child); +    visit_type_str(v, &path, name, errp); +    g_free(path); +} + +static Object *object_resolve_child_property(Object *parent, void *opaque, const gchar *part) +{ +    return opaque; +} + +static void object_finalize_child_property(Object *obj, const char *name, +                                           void *opaque) +{ +    Object *child = opaque; + +    if (child->class->unparent) { +        (child->class->unparent)(child); +    } +    child->parent = NULL; +    object_unref(child); +} + +void object_property_add_child(Object *obj, const char *name, +                               Object *child, Error **errp) +{ +    Error *local_err = NULL; +    gchar *type; +    ObjectProperty *op; + +    if (child->parent != NULL) { +        error_setg(errp, "child object is already parented"); +        return; +    } + +    type = g_strdup_printf("child<%s>", object_get_typename(OBJECT(child))); + +    op = object_property_add(obj, name, type, object_get_child_property, NULL, +                             object_finalize_child_property, child, &local_err); +    if (local_err) { +        error_propagate(errp, local_err); +        goto out; +    } + +    op->resolve = object_resolve_child_property; +    object_ref(child); +    child->parent = obj; + +out: +    g_free(type); +} + +void object_property_allow_set_link(Object *obj, const char *name, +                                    Object *val, Error **errp) +{ +    /* Allow the link to be set, always */ +} + +typedef struct { +    Object **child; +    void (*check)(Object *, const char *, Object *, Error **); +    ObjectPropertyLinkFlags flags; +} LinkProperty; + +static void object_get_link_property(Object *obj, Visitor *v, void *opaque, +                                     const char *name, Error **errp) +{ +    LinkProperty *lprop = opaque; +    Object **child = lprop->child; +    gchar *path; + +    if (*child) { +        path = object_get_canonical_path(*child); +        visit_type_str(v, &path, name, errp); +        g_free(path); +    } else { +        path = (gchar *)""; +        visit_type_str(v, &path, name, errp); +    } +} + +/* + * object_resolve_link: + * + * Lookup an object and ensure its type matches the link property type.  This + * is similar to object_resolve_path() except type verification against the + * link property is performed. + * + * Returns: The matched object or NULL on path lookup failures. + */ +static Object *object_resolve_link(Object *obj, const char *name, +                                   const char *path, Error **errp) +{ +    const char *type; +    gchar *target_type; +    bool ambiguous = false; +    Object *target; + +    /* Go from link<FOO> to FOO.  */ +    type = object_property_get_type(obj, name, NULL); +    target_type = g_strndup(&type[5], strlen(type) - 6); +    target = object_resolve_path_type(path, target_type, &ambiguous); + +    if (ambiguous) { +        error_set(errp, ERROR_CLASS_GENERIC_ERROR, +                  "Path '%s' does not uniquely identify an object", path); +    } else if (!target) { +        target = object_resolve_path(path, &ambiguous); +        if (target || ambiguous) { +            error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name, target_type); +        } else { +            error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, +                      "Device '%s' not found", path); +        } +        target = NULL; +    } +    g_free(target_type); + +    return target; +} + +static void object_set_link_property(Object *obj, Visitor *v, void *opaque, +                                     const char *name, Error **errp) +{ +    Error *local_err = NULL; +    LinkProperty *prop = opaque; +    Object **child = prop->child; +    Object *old_target = *child; +    Object *new_target = NULL; +    char *path = NULL; + +    visit_type_str(v, &path, name, &local_err); + +    if (!local_err && strcmp(path, "") != 0) { +        new_target = object_resolve_link(obj, name, path, &local_err); +    } + +    g_free(path); +    if (local_err) { +        error_propagate(errp, local_err); +        return; +    } + +    prop->check(obj, name, new_target, &local_err); +    if (local_err) { +        error_propagate(errp, local_err); +        return; +    } + +    object_ref(new_target); +    *child = new_target; +    object_unref(old_target); +} + +static Object *object_resolve_link_property(Object *parent, void *opaque, const gchar *part) +{ +    LinkProperty *lprop = opaque; + +    return *lprop->child; +} + +static void object_release_link_property(Object *obj, const char *name, +                                         void *opaque) +{ +    LinkProperty *prop = opaque; + +    if ((prop->flags & OBJ_PROP_LINK_UNREF_ON_RELEASE) && *prop->child) { +        object_unref(*prop->child); +    } +    g_free(prop); +} + +void object_property_add_link(Object *obj, const char *name, +                              const char *type, Object **child, +                              void (*check)(Object *, const char *, +                                            Object *, Error **), +                              ObjectPropertyLinkFlags flags, +                              Error **errp) +{ +    Error *local_err = NULL; +    LinkProperty *prop = g_malloc(sizeof(*prop)); +    gchar *full_type; +    ObjectProperty *op; + +    prop->child = child; +    prop->check = check; +    prop->flags = flags; + +    full_type = g_strdup_printf("link<%s>", type); + +    op = object_property_add(obj, name, full_type, +                             object_get_link_property, +                             check ? object_set_link_property : NULL, +                             object_release_link_property, +                             prop, +                             &local_err); +    if (local_err) { +        error_propagate(errp, local_err); +        g_free(prop); +        goto out; +    } + +    op->resolve = object_resolve_link_property; + +out: +    g_free(full_type); +} + +void object_property_add_const_link(Object *obj, const char *name, +                                    Object *target, Error **errp) +{ +    char *link_type; +    ObjectProperty *op; + +    link_type = g_strdup_printf("link<%s>", object_get_typename(target)); +    op = object_property_add(obj, name, link_type, +                             object_get_child_property, NULL, +                             NULL, target, errp); +    if (op != NULL) { +        op->resolve = object_resolve_child_property; +    } +    g_free(link_type); +} + +gchar *object_get_canonical_path_component(Object *obj) +{ +    ObjectProperty *prop = NULL; + +    g_assert(obj); +    g_assert(obj->parent != NULL); + +    QTAILQ_FOREACH(prop, &obj->parent->properties, node) { +        if (!object_property_is_child(prop)) { +            continue; +        } + +        if (prop->opaque == obj) { +            return g_strdup(prop->name); +        } +    } + +    /* obj had a parent but was not a child, should never happen */ +    g_assert_not_reached(); +    return NULL; +} + +gchar *object_get_canonical_path(Object *obj) +{ +    Object *root = object_get_root(); +    char *newpath, *path = NULL; + +    while (obj != root) { +        char *component = object_get_canonical_path_component(obj); + +        if (path) { +            newpath = g_strdup_printf("%s/%s", component, path); +            g_free(component); +            g_free(path); +            path = newpath; +        } else { +            path = component; +        } + +        obj = obj->parent; +    } + +    newpath = g_strdup_printf("/%s", path ? path : ""); +    g_free(path); + +    return newpath; +} + +Object *object_resolve_path_component(Object *parent, const gchar *part) +{ +    ObjectProperty *prop = object_property_find(parent, part, NULL); +    if (prop == NULL) { +        return NULL; +    } + +    if (prop->resolve) { +        return prop->resolve(parent, prop->opaque, part); +    } else { +        return NULL; +    } +} + +static Object *object_resolve_abs_path(Object *parent, +                                          gchar **parts, +                                          const char *typename, +                                          int index) +{ +    Object *child; + +    if (parts[index] == NULL) { +        return object_dynamic_cast(parent, typename); +    } + +    if (strcmp(parts[index], "") == 0) { +        return object_resolve_abs_path(parent, parts, typename, index + 1); +    } + +    child = object_resolve_path_component(parent, parts[index]); +    if (!child) { +        return NULL; +    } + +    return object_resolve_abs_path(child, parts, typename, index + 1); +} + +static Object *object_resolve_partial_path(Object *parent, +                                              gchar **parts, +                                              const char *typename, +                                              bool *ambiguous) +{ +    Object *obj; +    ObjectProperty *prop; + +    obj = object_resolve_abs_path(parent, parts, typename, 0); + +    QTAILQ_FOREACH(prop, &parent->properties, node) { +        Object *found; + +        if (!object_property_is_child(prop)) { +            continue; +        } + +        found = object_resolve_partial_path(prop->opaque, parts, +                                            typename, ambiguous); +        if (found) { +            if (obj) { +                if (ambiguous) { +                    *ambiguous = true; +                } +                return NULL; +            } +            obj = found; +        } + +        if (ambiguous && *ambiguous) { +            return NULL; +        } +    } + +    return obj; +} + +Object *object_resolve_path_type(const char *path, const char *typename, +                                 bool *ambiguous) +{ +    Object *obj; +    gchar **parts; + +    parts = g_strsplit(path, "/", 0); +    assert(parts); + +    if (parts[0] == NULL || strcmp(parts[0], "") != 0) { +        if (ambiguous) { +            *ambiguous = false; +        } +        obj = object_resolve_partial_path(object_get_root(), parts, +                                          typename, ambiguous); +    } else { +        obj = object_resolve_abs_path(object_get_root(), parts, typename, 1); +    } + +    g_strfreev(parts); + +    return obj; +} + +Object *object_resolve_path(const char *path, bool *ambiguous) +{ +    return object_resolve_path_type(path, TYPE_OBJECT, ambiguous); +} + +typedef struct StringProperty +{ +    char *(*get)(Object *, Error **); +    void (*set)(Object *, const char *, Error **); +} StringProperty; + +static void property_get_str(Object *obj, Visitor *v, void *opaque, +                             const char *name, Error **errp) +{ +    StringProperty *prop = opaque; +    char *value; +    Error *err = NULL; + +    value = prop->get(obj, &err); +    if (err) { +        error_propagate(errp, err); +        return; +    } + +    visit_type_str(v, &value, name, errp); +    g_free(value); +} + +static void property_set_str(Object *obj, Visitor *v, void *opaque, +                             const char *name, Error **errp) +{ +    StringProperty *prop = opaque; +    char *value; +    Error *local_err = NULL; + +    visit_type_str(v, &value, name, &local_err); +    if (local_err) { +        error_propagate(errp, local_err); +        return; +    } + +    prop->set(obj, value, errp); +    g_free(value); +} + +static void property_release_str(Object *obj, const char *name, +                                 void *opaque) +{ +    StringProperty *prop = opaque; +    g_free(prop); +} + +void object_property_add_str(Object *obj, 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_property_add(obj, 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 **); +    void (*set)(Object *, bool, Error **); +} BoolProperty; + +static void property_get_bool(Object *obj, Visitor *v, void *opaque, +                              const char *name, Error **errp) +{ +    BoolProperty *prop = opaque; +    bool value; +    Error *err = NULL; + +    value = prop->get(obj, &err); +    if (err) { +        error_propagate(errp, err); +        return; +    } + +    visit_type_bool(v, &value, name, errp); +} + +static void property_set_bool(Object *obj, Visitor *v, void *opaque, +                              const char *name, Error **errp) +{ +    BoolProperty *prop = opaque; +    bool value; +    Error *local_err = NULL; + +    visit_type_bool(v, &value, name, &local_err); +    if (local_err) { +        error_propagate(errp, local_err); +        return; +    } + +    prop->set(obj, value, errp); +} + +static void property_release_bool(Object *obj, const char *name, +                                  void *opaque) +{ +    BoolProperty *prop = opaque; +    g_free(prop); +} + +void object_property_add_bool(Object *obj, 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_property_add(obj, 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) +{ +    EnumProperty *prop = opaque; +    int value; +    Error *err = NULL; + +    value = prop->get(obj, &err); +    if (err) { +        error_propagate(errp, err); +        return; +    } + +    visit_type_enum(v, &value, prop->strings, NULL, name, errp); +} + +static void property_set_enum(Object *obj, Visitor *v, void *opaque, +                              const char *name, Error **errp) +{ +    EnumProperty *prop = opaque; +    int value; +    Error *err = NULL; + +    visit_type_enum(v, &value, prop->strings, NULL, name, &err); +    if (err) { +        error_propagate(errp, err); +        return; +    } +    prop->set(obj, value, errp); +} + +static void property_release_enum(Object *obj, const char *name, +                                  void *opaque) +{ +    EnumProperty *prop = opaque; +    g_free(prop); +} + +void object_property_add_enum(Object *obj, 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_property_add(obj, 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; + +static void property_get_tm(Object *obj, Visitor *v, void *opaque, +                            const char *name, Error **errp) +{ +    TMProperty *prop = opaque; +    Error *err = NULL; +    struct tm value; + +    prop->get(obj, &value, &err); +    if (err) { +        goto out; +    } + +    visit_start_struct(v, NULL, "struct tm", name, 0, &err); +    if (err) { +        goto out; +    } +    visit_type_int32(v, &value.tm_year, "tm_year", &err); +    if (err) { +        goto out_end; +    } +    visit_type_int32(v, &value.tm_mon, "tm_mon", &err); +    if (err) { +        goto out_end; +    } +    visit_type_int32(v, &value.tm_mday, "tm_mday", &err); +    if (err) { +        goto out_end; +    } +    visit_type_int32(v, &value.tm_hour, "tm_hour", &err); +    if (err) { +        goto out_end; +    } +    visit_type_int32(v, &value.tm_min, "tm_min", &err); +    if (err) { +        goto out_end; +    } +    visit_type_int32(v, &value.tm_sec, "tm_sec", &err); +    if (err) { +        goto out_end; +    } +out_end: +    error_propagate(errp, err); +    err = NULL; +    visit_end_struct(v, errp); +out: +    error_propagate(errp, err); + +} + +static void property_release_tm(Object *obj, const char *name, +                                void *opaque) +{ +    TMProperty *prop = opaque; +    g_free(prop); +} + +void object_property_add_tm(Object *obj, 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_property_add(obj, 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)); +} + +static void property_get_uint8_ptr(Object *obj, Visitor *v, +                                   void *opaque, const char *name, +                                   Error **errp) +{ +    uint8_t value = *(uint8_t *)opaque; +    visit_type_uint8(v, &value, name, errp); +} + +static void property_get_uint16_ptr(Object *obj, Visitor *v, +                                   void *opaque, const char *name, +                                   Error **errp) +{ +    uint16_t value = *(uint16_t *)opaque; +    visit_type_uint16(v, &value, name, errp); +} + +static void property_get_uint32_ptr(Object *obj, Visitor *v, +                                   void *opaque, const char *name, +                                   Error **errp) +{ +    uint32_t value = *(uint32_t *)opaque; +    visit_type_uint32(v, &value, name, errp); +} + +static void property_get_uint64_ptr(Object *obj, Visitor *v, +                                   void *opaque, const char *name, +                                   Error **errp) +{ +    uint64_t value = *(uint64_t *)opaque; +    visit_type_uint64(v, &value, name, errp); +} + +void object_property_add_uint8_ptr(Object *obj, const char *name, +                                   const uint8_t *v, Error **errp) +{ +    object_property_add(obj, 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) +{ +    object_property_add(obj, 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) +{ +    object_property_add(obj, 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) +{ +    object_property_add(obj, name, "uint64", property_get_uint64_ptr, +                        NULL, NULL, (void *)v, errp); +} + +typedef struct { +    Object *target_obj; +    char *target_name; +} AliasProperty; + +static void property_get_alias(Object *obj, struct Visitor *v, void *opaque, +                               const char *name, Error **errp) +{ +    AliasProperty *prop = opaque; + +    object_property_get(prop->target_obj, v, prop->target_name, errp); +} + +static void property_set_alias(Object *obj, struct Visitor *v, void *opaque, +                               const char *name, Error **errp) +{ +    AliasProperty *prop = opaque; + +    object_property_set(prop->target_obj, v, prop->target_name, errp); +} + +static Object *property_resolve_alias(Object *obj, void *opaque, +                                      const gchar *part) +{ +    AliasProperty *prop = opaque; + +    return object_resolve_path_component(prop->target_obj, prop->target_name); +} + +static void property_release_alias(Object *obj, const char *name, void *opaque) +{ +    AliasProperty *prop = opaque; + +    g_free(prop->target_name); +    g_free(prop); +} + +void object_property_add_alias(Object *obj, const char *name, +                               Object *target_obj, const char *target_name, +                               Error **errp) +{ +    AliasProperty *prop; +    ObjectProperty *op; +    ObjectProperty *target_prop; +    gchar *prop_type; +    Error *local_err = NULL; + +    target_prop = object_property_find(target_obj, target_name, errp); +    if (!target_prop) { +        return; +    } + +    if (object_property_is_child(target_prop)) { +        prop_type = g_strdup_printf("link%s", +                                    target_prop->type + strlen("child")); +    } else { +        prop_type = g_strdup(target_prop->type); +    } + +    prop = g_malloc(sizeof(*prop)); +    prop->target_obj = target_obj; +    prop->target_name = g_strdup(target_name); + +    op = object_property_add(obj, name, prop_type, +                             property_get_alias, +                             property_set_alias, +                             property_release_alias, +                             prop, &local_err); +    if (local_err) { +        error_propagate(errp, local_err); +        g_free(prop); +        goto out; +    } +    op->resolve = property_resolve_alias; + +    object_property_set_description(obj, op->name, +                                    target_prop->description, +                                    &error_abort); + +out: +    g_free(prop_type); +} + +void object_property_set_description(Object *obj, const char *name, +                                     const char *description, Error **errp) +{ +    ObjectProperty *op; + +    op = object_property_find(obj, 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); +} + +static void register_types(void) +{ +    static TypeInfo interface_info = { +        .name = TYPE_INTERFACE, +        .class_size = sizeof(InterfaceClass), +        .abstract = true, +    }; + +    static TypeInfo object_info = { +        .name = TYPE_OBJECT, +        .instance_size = sizeof(Object), +        .instance_init = object_instance_init, +        .abstract = true, +    }; + +    type_interface = type_register_internal(&interface_info); +    type_register_internal(&object_info); +} + +type_init(register_types) diff --git a/qom/object_interfaces.c b/qom/object_interfaces.c new file mode 100644 index 00000000..a66cd602 --- /dev/null +++ b/qom/object_interfaces.c @@ -0,0 +1,44 @@ +#include "qom/object_interfaces.h" +#include "qemu/module.h" + +void user_creatable_complete(Object *obj, Error **errp) +{ + +    UserCreatableClass *ucc; +    UserCreatable *uc = +        (UserCreatable *)object_dynamic_cast(obj, TYPE_USER_CREATABLE); + +    if (!uc) { +        return; +    } + +    ucc = USER_CREATABLE_GET_CLASS(uc); +    if (ucc->complete) { +        ucc->complete(uc, errp); +    } +} + +bool user_creatable_can_be_deleted(UserCreatable *uc, Error **errp) +{ + +    UserCreatableClass *ucc = USER_CREATABLE_GET_CLASS(uc); + +    if (ucc->can_be_deleted) { +        return ucc->can_be_deleted(uc, errp); +    } else { +        return true; +    } +} + +static void register_types(void) +{ +    static const TypeInfo uc_interface_info = { +        .name          = TYPE_USER_CREATABLE, +        .parent        = TYPE_INTERFACE, +        .class_size = sizeof(UserCreatableClass), +    }; + +    type_register_static(&uc_interface_info); +} + +type_init(register_types) diff --git a/qom/qom-qobject.c b/qom/qom-qobject.c new file mode 100644 index 00000000..6384b8e9 --- /dev/null +++ b/qom/qom-qobject.c @@ -0,0 +1,44 @@ +/* + * QEMU Object Model - QObject wrappers + * + * Copyright (C) 2012 Red Hat, Inc. + * + * Author: Paolo Bonzini <pbonzini@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu-common.h" +#include "qom/object.h" +#include "qom/qom-qobject.h" +#include "qapi/visitor.h" +#include "qapi/qmp-input-visitor.h" +#include "qapi/qmp-output-visitor.h" + +void object_property_set_qobject(Object *obj, QObject *value, +                                 const char *name, Error **errp) +{ +    QmpInputVisitor *mi; +    mi = qmp_input_visitor_new(value); +    object_property_set(obj, qmp_input_get_visitor(mi), name, errp); + +    qmp_input_visitor_cleanup(mi); +} + +QObject *object_property_get_qobject(Object *obj, const char *name, +                                     Error **errp) +{ +    QObject *ret = NULL; +    Error *local_err = NULL; +    QmpOutputVisitor *mo; + +    mo = qmp_output_visitor_new(); +    object_property_get(obj, qmp_output_get_visitor(mo), name, &local_err); +    if (!local_err) { +        ret = qmp_output_get_qobject(mo); +    } +    error_propagate(errp, local_err); +    qmp_output_visitor_cleanup(mo); +    return ret; +}  | 
