WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-devel

[Xen-devel] [PATCH 1/2] xenner: add event channel implementation.

To: qemu-devel@xxxxxxxxxx, xen-devel@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-devel] [PATCH 1/2] xenner: add event channel implementation.
From: Gerd Hoffmann <kraxel@xxxxxxxxxx>
Date: Fri, 22 Aug 2008 12:25:27 +0200
Cc: Gerd Hoffmann <kraxel@xxxxxxxxxx>
Delivery-date: Fri, 22 Aug 2008 03:27:13 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
In-reply-to: <1219400728-20422-1-git-send-email-kraxel@xxxxxxxxxx>
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
References: <1219400728-20422-1-git-send-email-kraxel@xxxxxxxxxx>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
This adds a xen event channel implementation to qemu, intented to be
used by xenner (aka xen emulation).

The patch also adds a XenEvtOps struct with function pointers for the
xc_evtchn_* family, which is used to switch between libxenctrl and the
qemu implementation at runtime.  By default libxenctrl is used.
---
 Makefile.target          |    1 +
 hw/xen_interfaces.h      |   27 +++
 hw/xen_machine_pv.c      |    2 +
 hw/xenner_libxc_evtchn.c |  396 ++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 426 insertions(+), 0 deletions(-)
 create mode 100644 hw/xen_interfaces.h
 create mode 100644 hw/xenner_libxc_evtchn.c

diff --git a/Makefile.target b/Makefile.target
index 5c97874..b88fd8f 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -521,6 +521,7 @@ endif
 # xen backend driver support
 XEN_OBJS := xen_machine_pv.o xen_backend.o xen_devconfig.o xen_domainbuild.o
 XEN_OBJS += xen_console.o xen_framebuffer.o xen_disk.o xen_nic.o
+XEN_OBJS += xenner_libxc_evtchn.o
 ifeq ($(CONFIG_XEN), yes)
   OBJS += $(XEN_OBJS)
   LIBS += $(XEN_LIBS)
diff --git a/hw/xen_interfaces.h b/hw/xen_interfaces.h
new file mode 100644
index 0000000..869b382
--- /dev/null
+++ b/hw/xen_interfaces.h
@@ -0,0 +1,27 @@
+#ifndef QEMU_XEN_INTERFACES_H
+#define QEMU_XEN_INTERFACES_H 1
+
+#include "xen_common.h"
+
+/* ------------------------------------------------------------- */
+/* xen event channel interface                                   */
+
+struct XenEvtOps {
+    int (*open)(void);
+    int (*domid)(int xce_handle, int domid);
+    int (*close)(int xce_handle);
+    int (*fd)(int xce_handle);
+    int (*notify)(int xce_handle, evtchn_port_t port);
+    evtchn_port_or_error_t (*bind_unbound_port)(int xce_handle, int domid);
+    evtchn_port_or_error_t (*bind_interdomain)(int xce_handle, int domid,
+                                              evtchn_port_t remote_port);
+    evtchn_port_or_error_t (*bind_virq)(int xce_handle, unsigned int virq);
+    int (*unbind)(int xce_handle, evtchn_port_t port);
+    evtchn_port_or_error_t (*pending)(int xce_handle);
+    int (*unmask)(int xce_handle, evtchn_port_t port);
+};
+extern struct XenEvtOps xc_evtchn;
+
+void xenner_evtchn_init(void);
+
+#endif /* QEMU_XEN_INTERFACES_H */
diff --git a/hw/xen_machine_pv.c b/hw/xen_machine_pv.c
index 9c67848..5d755f5 100644
--- a/hw/xen_machine_pv.c
+++ b/hw/xen_machine_pv.c
@@ -26,6 +26,7 @@
 #include "boards.h"
 
 #include "xen_backend.h"
+#include "xen_interfaces.h"
 #include "xen_domainbuild.h"
 
 /* -------------------------------------------------------------------- */
@@ -80,6 +81,7 @@ static int xen_init(void)
     if (!xen_detect()) {
         fprintf(stderr, "%s: emulating Xen\n", __FUNCTION__);
         xen_emulate = 1;
+        xenner_evtchn_init();
     }
 
     if (-1 == xen_be_init()) {
diff --git a/hw/xenner_libxc_evtchn.c b/hw/xenner_libxc_evtchn.c
new file mode 100644
index 0000000..f0c179d
--- /dev/null
+++ b/hw/xenner_libxc_evtchn.c
@@ -0,0 +1,396 @@
+#include <xenctrl.h>
+
+#include "hw.h"
+#include "xen_interfaces.h"
+
+/* ------------------------------------------------------------- */
+
+struct evtpriv;
+
+struct port {
+    struct evtpriv   *priv;
+    struct port      *peer;
+    int              port;
+};
+
+struct domain {
+    int              domid;
+    int              refcount;
+    struct port      p[NR_EVENT_CHANNELS];
+    TAILQ_ENTRY(domain) list;
+};
+static TAILQ_HEAD(domain_head, domain) domains = 
TAILQ_HEAD_INITIALIZER(domains);
+
+struct evtpriv {
+    int                      fd_read, fd_write;
+    struct domain            *domain;
+    int                      ports;
+    TAILQ_ENTRY(evtpriv)     list;
+};
+static TAILQ_HEAD(evtpriv_head, evtpriv) privs = TAILQ_HEAD_INITIALIZER(privs);
+
+static int debug = 0;
+
+/* ------------------------------------------------------------- */
+
+static struct evtpriv *getpriv(int handle)
+{
+    struct evtpriv *priv;
+
+    TAILQ_FOREACH(priv, &privs, list) {
+       if (priv->fd_read == handle)
+           return priv;
+    }
+    return NULL;
+}
+
+static struct domain *get_domain(int domid)
+{
+    struct domain *domain;
+
+    TAILQ_FOREACH(domain, &domains, list) {
+       if (domain->domid == domid)
+           goto done;
+    }
+
+    domain = qemu_mallocz(sizeof(*domain));
+    if (NULL == domain)
+       return NULL;
+    if (domid)
+       domain->domid = domid;
+    TAILQ_INSERT_TAIL(&domains, domain, list);
+    if (debug)
+       fprintf(stderr, "xen ev:  ?: new domain id %d\n", domain->domid);
+
+done:
+    domain->refcount++;
+    return domain;
+}
+
+static void put_domain(struct domain *domain)
+{
+    domain->refcount--;
+    if (domain->refcount)
+       return;
+    if (debug)
+       fprintf(stderr, "xen ev:  ?: del domain id %d\n", domain->domid);
+    TAILQ_REMOVE(&domains, domain, list);
+    qemu_free(domain);
+}
+
+static struct port *alloc_port(struct evtpriv *priv, char *reason)
+{
+    struct port *p = NULL;
+    int i;
+
+    for (i = 1; i < NR_EVENT_CHANNELS; i++) {
+       if (NULL != priv->domain->p[i].priv)
+           continue;
+       p = priv->domain->p+i;
+       p->port = i;
+       p->priv = priv;
+       priv->ports++;
+       if (debug)
+           fprintf(stderr, "xen ev:%3d: alloc port %d, domain %d (%s)\n",
+                   priv->fd_read, p->port, priv->domain->domid, reason);
+       return p;
+    }
+    return NULL;
+}
+
+static void bind_port_peer(struct port *p, int domid, int port)
+{
+    struct domain *domain;
+    struct port *o;
+    char *msg = "ok";
+
+    domain = get_domain(domid);
+    o = domain->p+port;
+    if (!o->priv) {
+       msg = "peer not allocated";
+    } else if (o->peer) {
+       msg = "peer already bound";
+    } else if (p->peer) {
+       msg = "port already bound";
+    } else {
+       o->peer = p;
+       p->peer = o;
+    }
+    if (debug)
+       fprintf(stderr, "xen ev:%3d: bind port %d domain %d  <->  port %d 
domain %d : %s\n",
+               p->priv->fd_read,
+               p->port, p->priv->domain->domid,
+               port, domid, msg);
+    put_domain(domain);
+}
+
+static void unbind_port(struct port *p)
+{
+    struct port *o;
+
+    o = p->peer;
+    if (o) {
+       if (debug)
+           fprintf(stderr,"xen ev:%3d: unbind port %d domain %d  <->  port %d 
domain %d\n",
+                   p->priv->fd_read,
+                   p->port, p->priv->domain->domid,
+                   o->port, o->priv->domain->domid);
+       o->peer = NULL;
+       p->peer = NULL;
+    }
+}
+
+static void notify_send_peer(struct port *peer)
+{
+    uint32_t evtchn = peer->port;
+    write(peer->priv->fd_write, &evtchn, sizeof(evtchn));
+}
+
+static void notify_port(struct port *p)
+{
+    if (p->peer) {
+       notify_send_peer(p->peer);
+       if (debug > 1)
+           fprintf(stderr, "xen ev:%3d: notify port %d domain %d  ->  port %d 
domain %d\n",
+                   p->priv->fd_read, p->port, p->priv->domain->domid,
+                   p->peer->port, p->peer->priv->domain->domid);
+    } else {
+       if (debug)
+           fprintf(stderr,"xen ev:%3d: notify port %d domain %d  ->  
unconnected\n",
+                   p->priv->fd_read, p->port, p->priv->domain->domid);
+    }
+}
+
+static void unmask_port(struct port *p)
+{
+    /* nothing to do */
+}
+
+static void release_port(struct port *p)
+{
+    if (debug)
+       fprintf(stderr,"xen ev:%3d: release port %d, domain %d\n",
+               p->priv->fd_read, p->port, p->priv->domain->domid);
+    unbind_port(p);
+    p->priv->ports--;
+    p->port = 0;
+    p->priv = 0;
+}
+
+/* ------------------------------------------------------------- */
+
+static int qemu_open(void)
+{
+    struct evtpriv *priv;
+    int fd[2];
+
+    priv = qemu_mallocz(sizeof(*priv));
+    if (NULL == priv)
+       goto err;
+    TAILQ_INSERT_TAIL(&privs, priv, list);
+
+    if (-1 == pipe(fd))
+       goto err;
+    priv->fd_read  = fd[0];
+    priv->fd_write = fd[1];
+    fcntl(priv->fd_read,F_SETFL,O_NONBLOCK);
+
+    priv->domain = get_domain(0);
+    return priv->fd_read;
+
+err:
+    qemu_free(priv);
+    return -1;
+}
+
+static int qemu_close(int handle)
+{
+    struct evtpriv *priv = getpriv(handle);
+    struct port *p;
+    int i;
+
+    if (!priv)
+       return -1;
+
+    for (i = 1; i < NR_EVENT_CHANNELS; i++) {
+       p = priv->domain->p+i;
+       if (priv != p->priv)
+           continue;
+       release_port(p);
+    }
+    put_domain(priv->domain);
+
+    close(priv->fd_read);
+    close(priv->fd_write);
+    TAILQ_REMOVE(&privs, priv, list);
+    qemu_free(priv);
+    return 0;
+}
+
+static int qemu_fd(int handle)
+{
+    struct evtpriv *priv = getpriv(handle);
+
+    if (!priv)
+       return -1;
+    return priv->fd_read;
+}
+
+static int qemu_notify(int handle, evtchn_port_t port)
+{
+    struct evtpriv *priv = getpriv(handle);
+    struct port *p;
+
+    if (!priv)
+       return -1;
+    if (port >= NR_EVENT_CHANNELS)
+       return -1;
+    p = priv->domain->p + port;
+    notify_port(p);
+    return -1;
+}
+
+static evtchn_port_or_error_t qemu_bind_unbound_port(int handle, int domid)
+{
+    struct evtpriv *priv = getpriv(handle);
+    struct port *p;
+
+    if (!priv)
+       return -1;
+    p = alloc_port(priv, "unbound");
+    if (!p)
+       return -1;
+    return p->port;
+}
+
+static evtchn_port_or_error_t qemu_bind_interdomain(int handle, int domid,
+                                                   evtchn_port_t remote_port)
+{
+    struct evtpriv *priv = getpriv(handle);
+    struct port *p;
+
+    if (!priv)
+       return -1;
+    if (remote_port >= NR_EVENT_CHANNELS)
+       return -1;
+    p = alloc_port(priv, "interdomain");
+    if (!p)
+       return -1;
+    bind_port_peer(p, domid, remote_port);
+    return p->port;
+}
+
+static evtchn_port_or_error_t qemu_bind_virq(int handle, unsigned int virq)
+{
+    struct evtpriv *priv = getpriv(handle);
+    struct port *p;
+
+    if (!priv)
+       return -1;
+    p = alloc_port(priv, "virq");
+    if (!p)
+       return -1;
+    /*
+     * FIXME: port not linked
+     * (but virq doesn't go this route anyway I think)
+     */
+    return p->port;
+}
+
+static int qemu_unbind(int handle, evtchn_port_t port)
+{
+    struct evtpriv *priv = getpriv(handle);
+    struct port *p;
+
+    if (!priv)
+       return -1;
+    if (port >= NR_EVENT_CHANNELS)
+       return -1;
+    p = priv->domain->p + port;
+    unbind_port(p);
+    release_port(p);
+    return 0;
+}
+
+static evtchn_port_or_error_t qemu_pending(int handle)
+{
+    struct evtpriv *priv = getpriv(handle);
+    uint32_t evtchn;
+    int rc;
+
+    if (!priv)
+       return -1;
+    rc = read(priv->fd_read, &evtchn, sizeof(evtchn));
+    if (rc != sizeof(evtchn))
+       return -1;
+    return evtchn;
+}
+
+static int qemu_unmask(int handle, evtchn_port_t port)
+{
+    struct evtpriv *priv = getpriv(handle);
+    struct port *p;
+
+    if (!priv)
+       return -1;
+    if (port >= NR_EVENT_CHANNELS)
+       return -1;
+    p = priv->domain->p + port;
+    unmask_port(p);
+    return 0;
+}
+
+static int qemu_domid(int handle, int domid)
+{
+    struct evtpriv *priv = getpriv(handle);
+
+    if (!priv)
+       return -1;
+    if (priv->ports)
+       return -1;
+    put_domain(priv->domain);
+    priv->domain = get_domain(domid);
+    return 0;
+}
+
+static struct XenEvtOps xenner_evtchn = {
+    .open               = qemu_open,
+    .domid              = qemu_domid,
+    .close              = qemu_close,
+    .fd                 = qemu_fd,
+    .notify             = qemu_notify,
+    .bind_unbound_port  = qemu_bind_unbound_port,
+    .bind_interdomain   = qemu_bind_interdomain,
+    .bind_virq          = qemu_bind_virq,
+    .unbind             = qemu_unbind,
+    .pending            = qemu_pending,
+    .unmask             = qemu_unmask,
+};
+
+/* ------------------------------------------------------------- */
+
+static int xc_evtchn_domid(int handle, int domid)
+{
+    return -1;
+}
+
+struct XenEvtOps xc_evtchn = {
+    .open               = xc_evtchn_open,
+    .domid              = xc_evtchn_domid,
+    .close              = xc_evtchn_close,
+    .fd                 = xc_evtchn_fd,
+    .notify             = xc_evtchn_notify,
+    .bind_unbound_port  = xc_evtchn_bind_unbound_port,
+    .bind_interdomain   = xc_evtchn_bind_interdomain,
+    .bind_virq          = xc_evtchn_bind_virq,
+    .unbind             = xc_evtchn_unbind,
+    .pending            = xc_evtchn_pending,
+    .unmask             = xc_evtchn_unmask,
+};
+
+/* ------------------------------------------------------------- */
+
+void xenner_evtchn_init(void)
+{
+    xc_evtchn = xenner_evtchn;
+}
-- 
1.5.5.1


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel