From: Zhi Yong Wu <wu...@linux.vnet.ibm.com> Signed-off-by: Zhi Yong Wu <wu...@linux.vnet.ibm.com> --- include/qemu/hostdev.h | 128 ++++++++++++++++++ qom/Makefile | 2 +- qom/hostdev.c | 333 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 462 insertions(+), 1 deletions(-) create mode 100644 include/qemu/hostdev.h create mode 100644 qom/hostdev.c
diff --git a/include/qemu/hostdev.h b/include/qemu/hostdev.h new file mode 100644 index 0000000..a291761 --- /dev/null +++ b/include/qemu/hostdev.h @@ -0,0 +1,128 @@ +/* + * QEMU host device model + * + * Copyright IBM, Corp. 2012 + * + * Authors: + * Zhi Yong Wu <wu...@linux.vnet.ibm.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#ifndef QEMU_HOSTDEV_H +#define QEMU_HOSTDEV_H + +#include "qemu-queue.h" +#include "qemu-char.h" +#include "qemu-option.h" +#include "qapi/qapi-visit-core.h" +#include "qemu/object.h" + +typedef struct hostdevProperty hostdevProperty; +typedef struct hostdevPropertyInfo hostdevPropertyInfo; + +/** + * SECTION: hostdev + * @section_id: QEMU-hostdev + * @title: hostdev Class + * @short_description: Base class for all host devices + */ + +typedef struct HOSTDevice HOSTDevice; + +#define TYPE_HOSTDEV "host-dev" +#define HOST_DEVICE(obj) \ + OBJECT_CHECK(HOSTDevice, (obj), TYPE_HOSTDEV) +#define HOSTDEV_CLASS(klass) \ + OBJECT_CLASS_CHECK(HOSTDeviceClass, (klass), TYPE_HOSTDEV) +#define HOSTDEV_GET_CLASS(obj) \ + OBJECT_GET_CLASS(HOSTDeviceClass, (obj), TYPE_HOSTDEV) + +/** + * HOSTDeviceClass: + * + * Represents a host device model. + */ +typedef struct HOSTDeviceClass { + ObjectClass parent_class; + hostdevProperty *props; + + int (*init)(HOSTDevice *host_dv); +} HOSTDeviceClass; + +/** + * HOSTDevice: + * + * State of one host device. + */ +struct HOSTDevice { + /*< private >*/ + Object parent_obj; + + /*< public >*/ +}; + +struct hostdevProperty { + const char *name; + hostdevPropertyInfo *info; + int offset; + uint8_t bitnr; + uint8_t qtype; + int64_t defval; +}; + +struct hostdevPropertyInfo { + const char *name; + const char *legacy_name; + const char **enum_table; + int64_t min; + int64_t max; + int (*parse)(HOSTDevice *dev, + hostdevProperty *prop, + const char *str); + int (*print)(HOSTDevice *dev, + hostdevProperty *prop, + char *dest, + size_t len); + ObjectPropertyAccessor *get; + ObjectPropertyAccessor *set; + ObjectPropertyRelease *release; +}; + +extern hostdevPropertyInfo hostdev_prop_int32; +extern hostdevPropertyInfo hostdev_prop_string; +extern hostdevPropertyInfo hostdev_prop_netdev; + +#define DEFINE_HOSTDEV_PROP(_name, _state, _field, _prop, _type) { \ + .name = (_name), \ + .info = &(_prop), \ + .offset = offsetof(_state, _field) \ + + type_check(_type,typeof_field(_state, _field)), \ + } +#define DEFINE_HOSTDEV_PROP_DEFAULT(_name, _state, _field, _defval, _prop, _type) { \ + .name = (_name), \ + .info = &(_prop), \ + .offset = offsetof(_state, _field) \ + + type_check(_type,typeof_field(_state, _field)), \ + .qtype = QTYPE_QINT, \ + .defval = (_type)_defval, \ + } +#define DEFINE_HOSTDEV_PROP_END_OF_LIST() \ + {} +#define DEFINE_HOSTDEV_PROP_INT32(_n, _s, _f, _d) \ + DEFINE_HOSTDEV_PROP_DEFAULT(_n, _s, _f, _d, hostdev_prop_int32, int32_t) +#define DEFINE_HOSTDEV_PROP_PEER(_n, _s, _f) \ + DEFINE_HOSTDEV_PROP(_n, _s, _f, hostdev_prop_netdev, NetClientState*) +#define DEFINE_HOSTDEV_PROP_STRING(_n, _s, _f) \ + DEFINE_HOSTDEV_PROP(_n, _s, _f, hostdev_prop_string, char*) + +HOSTDevice *hostdev_device_create(const char *type); +int hostdev_device_init(HOSTDevice *dev, const char *type, const char *id); +void hostdev_prop_set_string(HOSTDevice *dev, + const char *name, char *value); +void hostdev_prop_set_peer(HOSTDevice *dev, + const char *name, NetClientState *value); + +#endif diff --git a/qom/Makefile b/qom/Makefile index 34c6de5..4731fb9 100644 --- a/qom/Makefile +++ b/qom/Makefile @@ -1,2 +1,2 @@ qom-y = object.o container.o qom-qobject.o -qom-twice-y = cpu.o +qom-twice-y = cpu.o hostdev.o diff --git a/qom/hostdev.c b/qom/hostdev.c new file mode 100644 index 0000000..867e869 --- /dev/null +++ b/qom/hostdev.c @@ -0,0 +1,333 @@ +/* + * QEMU host device model + * + * Copyright IBM, Corp. 2012 + * + * Authors: + * Zhi Yong Wu <wu...@linux.vnet.ibm.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#include "qemu/hostdev.h" +#include "qemu-common.h" +#include "net.h" + +void hostdev_prop_set_string(HOSTDevice *dev, + const char *name, char *value) +{ + Error *errp = NULL; + object_property_set_str(OBJECT(dev), value, name, &errp); + assert_no_error(errp); +} + +void hostdev_prop_set_peer(HOSTDevice *dev, + const char *name, NetClientState *value) +{ + Error *errp = NULL; + assert(!value || value->name); + object_property_set_str(OBJECT(dev), + value ? value->name : "", name, &errp); + assert_no_error(errp); +} + +static Object *hostdev_get_hostdev(void) +{ + static Object *dev; + + if (dev == NULL) { + dev = object_new("container"); + object_property_add_child(object_get_root(), "hostdev", + OBJECT(dev), NULL); + } + + return dev; +} + +HOSTDevice *hostdev_device_create(const char *type) +{ + HOSTDevice *hostdev; + + hostdev = HOST_DEVICE(object_new(type)); + if (!hostdev) { + return NULL; + } + + return hostdev; +} + +int hostdev_device_init(HOSTDevice *dev, const char *type, const char *id) +{ + HOSTDeviceClass *dc = HOSTDEV_GET_CLASS(dev); + gchar *dev_id; + int rc; + + rc = dc->init(dev); + if (rc < 0) { + object_delete(OBJECT(dev)); + return rc; + } + + if (id) { + dev_id = g_strdup(id); + } else { + static int anon_count; + dev_id = g_strdup_printf("%s[%d]", (char *)type, anon_count++); + } + + object_property_add_child(hostdev_get_hostdev(), dev_id, + OBJECT(dev), NULL); + g_free(dev_id); + + return 0; +} + +static void *hostdev_get_prop_ptr(HOSTDevice *dev, hostdevProperty *prop) +{ + void *ptr = dev; + ptr += prop->offset; + return ptr; +} + +static void error_set_from_hostdev_prop_error(Error **errp, int ret, + HOSTDevice *dev, hostdevProperty *prop, + const char *value) +{ + switch (ret) { + case -EEXIST: + error_set(errp, QERR_PROPERTY_VALUE_IN_USE, + object_get_typename(OBJECT(dev)), prop->name, value); + break; + default: + case -EINVAL: + error_set(errp, QERR_PROPERTY_VALUE_BAD, + object_get_typename(OBJECT(dev)), prop->name, value); + break; + case -ENOENT: + error_set(errp, QERR_PROPERTY_VALUE_NOT_FOUND, + object_get_typename(OBJECT(dev)), prop->name, value); + break; + case 0: + break; + } +} + +/* --- netdev device --- */ +static void get_pointer(Object *obj, Visitor *v, hostdevProperty *prop, + const char *(*print)(void *ptr), + const char *name, Error **errp) +{ + HOSTDevice *dev = HOST_DEVICE(obj); + void **ptr = hostdev_get_prop_ptr(dev, prop); + char *p; + + p = (char *) (*ptr ? print(*ptr) : ""); + visit_type_str(v, &p, name, errp); +} + +static void set_pointer(Object *obj, Visitor *v, hostdevProperty *prop, + int (*parse)(HOSTDevice *dev, const char *str, void **ptr), + const char *name, Error **errp) +{ + HOSTDevice *dev = HOST_DEVICE(obj); + Error *local_err = NULL; + void **ptr = hostdev_get_prop_ptr(dev, prop); + char *str; + int ret; + + visit_type_str(v, &str, name, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + if (!*str) { + g_free(str); + *ptr = NULL; + return; + } + ret = parse(dev, str, ptr); + error_set_from_hostdev_prop_error(errp, ret, dev, prop, str); + g_free(str); +} + +/* --- 32bit integer --- */ +static void get_int32(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + HOSTDevice *dev = HOST_DEVICE(obj); + hostdevProperty *prop = opaque; + int32_t *ptr = hostdev_get_prop_ptr(dev, prop); + int64_t value; + + value = *ptr; + visit_type_int(v, &value, name, errp); +} + +static void set_int32(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + HOSTDevice *dev = HOST_DEVICE(obj); + hostdevProperty *prop = opaque; + int32_t *ptr = hostdev_get_prop_ptr(dev, prop); + Error *local_err = NULL; + int64_t value; + + visit_type_int(v, &value, name, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + if (value >= prop->info->min && value <= prop->info->max) { + *ptr = value; + } else { + error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, + "", name, value, prop->info->min, + prop->info->max); + } +} + +hostdevPropertyInfo hostdev_prop_int32 = { + .name = "int32", + .get = get_int32, + .set = set_int32, + .min = -0x80000000LL, + .max = 0x7FFFFFFFLL, +}; + +/* --- netdev --- */ +static int parse_netdev(HOSTDevice *dev, const char *str, void **ptr) +{ + NetClientState *netdev = qemu_find_netdev(str); + + if (netdev == NULL) { + return -ENOENT; + } + if (netdev->peer) { + return -EEXIST; + } + *ptr = netdev; + return 0; +} + +static const char *print_netdev(void *ptr) +{ + NetClientState *netdev = ptr; + + return netdev->name ? netdev->name : ""; +} + +static void get_netdev(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + get_pointer(obj, v, opaque, print_netdev, name, errp); +} + +static void set_netdev(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + set_pointer(obj, v, opaque, parse_netdev, name, errp); +} + +hostdevPropertyInfo hostdev_prop_netdev = { + .name = "peer", + .get = get_netdev, + .set = set_netdev, +}; + +/* --- string --- */ +static void release_string(Object *obj, const char *name, void *opaque) +{ + hostdevProperty *prop = opaque; + g_free(*(char **)hostdev_get_prop_ptr(HOST_DEVICE(obj), prop)); +} + +static void get_string(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + HOSTDevice *dev = HOST_DEVICE(obj); + hostdevProperty *prop = opaque; + char **ptr = hostdev_get_prop_ptr(dev, prop); + + if (!*ptr) { + char *str = (char *)""; + visit_type_str(v, &str, name, errp); + } else { + visit_type_str(v, ptr, name, errp); + } +} + +static void set_string(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + HOSTDevice *dev = HOST_DEVICE(obj); + hostdevProperty *prop = opaque; + char **ptr = hostdev_get_prop_ptr(dev, prop); + Error *local_err = NULL; + char *str; + + visit_type_str(v, &str, name, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + if (*ptr) { + g_free(*ptr); + } + *ptr = str; +} + +hostdevPropertyInfo hostdev_prop_string = { + .name = "string", + .release = release_string, + .get = get_string, + .set = set_string, +}; +/* +static char *hostdev_get_type(Object *obj, Error **errp) +{ + return g_strdup(object_get_typename(obj)); +} +*/ +static void hostdev_property_add_static(HOSTDevice *dev, hostdevProperty *prop, + Error **errp) +{ + if (!prop->info->get && !prop->info->set) { + return; + } + + object_property_add(OBJECT(dev), prop->name, prop->info->name, + prop->info->get, prop->info->set, + prop->info->release, + prop, errp); +} + +static void hostdev_init(Object *obj) +{ + HOSTDevice *s = HOST_DEVICE(obj); + HOSTDeviceClass *dc = HOSTDEV_GET_CLASS(obj); + hostdevProperty *prop; + + for (prop = dc->props; prop && prop->name; prop++) { + hostdev_property_add_static(s, prop, NULL); + } + + //object_property_add_str(OBJECT(s), "type", hostdev_get_type, NULL, NULL); +} + +static TypeInfo hostdev_type_info = { + .name = TYPE_HOSTDEV, + .parent = TYPE_OBJECT, + .instance_size = sizeof(HOSTDevice), + .instance_init = hostdev_init, + .abstract = true, + .class_size = sizeof(HOSTDeviceClass), +}; + +static void hostdev_register_types(void) +{ + type_register_static(&hostdev_type_info); +} + +type_init(hostdev_register_types) -- 1.7.6