qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: zwu.kernel@gmail.com
To: qemu-devel@nongnu.org
Cc: zwu.kernel@gmail.com, pbonzini@redhat.com,
	Zhi Yong Wu <wuzhy@linux.vnet.ibm.com>,
	stefanha@linux.vnet.ibm.com
Subject: [Qemu-devel] [RFC 1/9] hostdev: introduce the infrastructure for host device model
Date: Mon, 26 Mar 2012 13:40:13 +0800	[thread overview]
Message-ID: <1332740423-8426-2-git-send-email-zwu.kernel@gmail.com> (raw)
In-Reply-To: <1332740423-8426-1-git-send-email-zwu.kernel@gmail.com>

From: Zhi Yong Wu <wuzhy@linux.vnet.ibm.com>

Signed-off-by: Zhi Yong Wu <wuzhy@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   <wuzhy@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   <wuzhy@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

  reply	other threads:[~2012-03-26  5:40 UTC|newest]

Thread overview: 38+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-03-26  5:40 [Qemu-devel] [RFC 0/9] QOM: qomify -netdev zwu.kernel
2012-03-26  5:40 ` zwu.kernel [this message]
2012-03-26  5:54   ` [Qemu-devel] [RFC 1/9] hostdev: introduce the infrastructure for host device model Zhi Yong Wu
2012-03-27  8:23   ` Paolo Bonzini
2012-03-27  9:06     ` Zhi Yong Wu
2012-03-27 10:15       ` Paolo Bonzini
2012-03-27 11:59         ` Zhi Yong Wu
2012-03-27 13:58           ` Paolo Bonzini
2012-03-27 14:18             ` Zhi Yong Wu
2012-03-27 14:50               ` Paolo Bonzini
2012-03-27 21:21                 ` Zhi Yong Wu
2012-03-28  6:41                   ` Paolo Bonzini
2012-03-28  7:50                     ` Zhi Yong Wu
2012-03-28  7:53                     ` Zhi Yong Wu
2012-03-28  8:02                       ` Paolo Bonzini
2012-03-28  8:05                         ` 陳韋任
2012-03-28  8:25                           ` Zhi Yong Wu
2012-03-28  8:29                             ` 陳韋任
2012-03-26  5:40 ` [Qemu-devel] [PATCH] net: qomify -netdev zwu.kernel
2012-03-26  5:40 ` zwu.kernel
2012-03-26  5:44   ` Zhi Yong Wu
2012-03-26  5:40 ` [Qemu-devel] [RFC 2/9] net: introduce one net host device class zwu.kernel
2012-03-27  8:30   ` Paolo Bonzini
2012-03-27  9:13     ` Zhi Yong Wu
2012-03-26  5:40 ` [Qemu-devel] [RFC 3/9] net: adjust net common part for qomify -netdev zwu.kernel
2012-03-26  5:40 ` [Qemu-devel] [RFC 4/9] net: adjust nic init API zwu.kernel
2012-03-26  5:40 ` [Qemu-devel] [RFC 5/9] net: adjust dump " zwu.kernel
2012-03-26  5:40 ` [Qemu-devel] [RFC 6/9] net: qomify -netdev user zwu.kernel
2012-03-26  5:40 ` [Qemu-devel] [RFC 7/9] net: qomify -netdev socket zwu.kernel
2012-03-26  5:40 ` [Qemu-devel] [RFC 8/9] net: qomify -netdev vde zwu.kernel
2012-03-26  5:40 ` [Qemu-devel] [RFC 9/9] net: qomify -netdev tap & -netdev bridge zwu.kernel
2012-03-26 11:54 ` [Qemu-devel] [RFC 0/9] QOM: qomify -netdev Stefan Hajnoczi
2012-03-26 14:20   ` Zhi Yong Wu
2012-03-27  8:19     ` Paolo Bonzini
2012-03-27  9:03       ` Zhi Yong Wu
2012-03-26 14:39   ` Andreas Färber
2012-03-26 14:57     ` Stefan Hajnoczi
2012-03-26 15:01     ` Zhi Yong Wu

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1332740423-8426-2-git-send-email-zwu.kernel@gmail.com \
    --to=zwu.kernel@gmail.com \
    --cc=pbonzini@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=stefanha@linux.vnet.ibm.com \
    --cc=wuzhy@linux.vnet.ibm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).