qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH 28/40] xenner: libxc emu: evtchn


From: Anthony Liguori
Subject: Re: [Qemu-devel] [PATCH 28/40] xenner: libxc emu: evtchn
Date: Mon, 01 Nov 2010 10:45:19 -0500
User-agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.15) Gecko/20101027 Lightning/1.0b1 Thunderbird/3.0.10

On 11/01/2010 10:01 AM, Alexander Graf wrote:
Xenner emulates parts of libxc, so we can not use the real xen infrastructure
when running xen pv guests without xen.

This patch adds support for event channel communication.

Signed-off-by: Alexander Graf<address@hidden>

Has anyone checked with the Xen folks about supporting this type of functionality in libxc directly?

Regards,

Anthony Liguori

---
  hw/xenner_libxc_evtchn.c |  467 ++++++++++++++++++++++++++++++++++++++++++++++
  1 files changed, 467 insertions(+), 0 deletions(-)
  create mode 100644 hw/xenner_libxc_evtchn.c

diff --git a/hw/xenner_libxc_evtchn.c b/hw/xenner_libxc_evtchn.c
new file mode 100644
index 0000000..bb1984c
--- /dev/null
+++ b/hw/xenner_libxc_evtchn.c
@@ -0,0 +1,467 @@
+/*
+ *  Copyright (C) Red Hat 2007
+ *  Copyright (C) Novell Inc. 2010
+ *
+ *  Author(s): Gerd Hoffmann<address@hidden>
+ *             Alexander Graf<address@hidden>
+ *
+ *  Xenner emulation -- event channels
+ *
+ *  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; under version 2 of the License.
+ *
+ *  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/>.
+ */
+
+#include<assert.h>
+#include<xenctrl.h>
+
+#include "hw.h"
+#include "qemu-log.h"
+#include "console.h"
+#include "monitor.h"
+#include "xen.h"
+#include "xen_interfaces.h"
+
+/* ------------------------------------------------------------- */
+
+struct evtpriv;
+
+struct port {
+    struct evtpriv   *priv;
+    struct port      *peer;
+    int              port;
+    int              pending;
+    int              count_snd;
+    int              count_fwd;
+    int              count_msg;
+};
+
+struct domain {
+    int              domid;
+    struct port      p[NR_EVENT_CHANNELS];
+};
+static struct domain dom0;  /* host  */
+static struct domain domU;  /* guest */
+
+struct evtpriv {
+    int                      fd_read, fd_write;
+    struct domain            *domain;
+    int                      ports;
+    int                      pending;
+    QTAILQ_ENTRY(evtpriv)    list;
+};
+static QTAILQ_HEAD(evtpriv_head, evtpriv) privs = 
QTAILQ_HEAD_INITIALIZER(privs);
+
+static int debug = 0;
+
+/* ------------------------------------------------------------- */
+
+static struct evtpriv *getpriv(int handle)
+{
+    struct evtpriv *priv;
+
+    QTAILQ_FOREACH(priv,&privs, list) {
+        if (priv->fd_read == handle) {
+            return priv;
+        }
+    }
+    return NULL;
+}
+
+static struct domain *get_domain(int domid)
+{
+    if (domid == 0) {
+        return&dom0;
+    }
+    if (!domU.domid) {
+        domU.domid = domid;
+    }
+    assert(domU.domid == domid);
+    return&domU;
+}
+
+static struct port *alloc_port(struct evtpriv *priv, const char *reason)
+{
+    struct port *p = NULL;
+    int i;
+
+    for (i = 1; i<  NR_EVENT_CHANNELS; i++) {
+#ifdef DEBUG
+        /* debug hack */
+#define EA_START 20
+        if (priv->domain->domid&&  i<  EA_START)
+            i = EA_START;
+#undef EA_START
+#endif
+        if (priv->domain->p[i].priv != NULL) {
+            continue;
+        }
+        p = priv->domain->p+i;
+        p->port = i;
+        p->priv = priv;
+        p->count_snd = 0;
+        p->count_fwd = 0;
+        p->count_msg = 1;
+        priv->ports++;
+        if (debug) {
+            qemu_log("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;
+    const 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) {
+        qemu_log("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);
+    }
+}
+
+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;
+    int r;
+
+    peer->count_snd++;
+    if (peer->pending) {
+        return;
+    }
+
+    r = write(peer->priv->fd_write,&evtchn, sizeof(evtchn));
+    if (r != sizeof(evtchn)) {
+        // XXX break
+    }
+    peer->count_fwd++;
+    peer->pending++;
+    peer->priv->pending++;
+}
+
+static void notify_port(struct port *p)
+{
+    if (p->peer) {
+        notify_send_peer(p->peer);
+        if (debug&&  p->peer->count_snd>= p->peer->count_msg) {
+            fprintf(stderr, "xen ev:%3d: notify port %d domain %d  ->   port %d 
"
+                            "domain %d  |  counts %d/%d\n",
+                     p->priv->fd_read, p->port, p->priv->domain->domid,
+                     p->peer->port, p->peer->priv->domain->domid,
+                     p->peer->count_fwd, p->peer->count_snd);
+            p->peer->count_msg *= 10;
+        }
+    } 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_xopen(void)
+{
+    struct evtpriv *priv;
+    int fd[2];
+
+    priv = qemu_mallocz(sizeof(*priv));
+    QTAILQ_INSERT_TAIL(&privs, priv, list);
+
+    if (pipe(fd)<  0) {
+        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);
+    }
+
+    close(priv->fd_read);
+    close(priv->fd_write);
+    QTAILQ_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;
+    }
+    /*
+     * Note: port not linked here, we only allocate some port.
+     */
+    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;
+    }
+    priv->pending--;
+    priv->domain->p[evtchn].pending--;
+    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;
+    }
+    priv->domain = get_domain(domid);
+    return 0;
+}
+
+struct XenEvtOps xc_evtchn_xenner = {
+    .open               = qemu_xopen,
+    .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,
+};
+
+/* ------------------------------------------------------------- */
+
+#if 0
+
+void do_info_evtchn(Monitor *mon)
+{
+    struct evtpriv *priv;
+    struct port *port;
+    int i;
+
+    if (xen_mode != XEN_EMULATE) {
+        monitor_printf(mon, "Not emulating xen event channels.\n");
+        return;
+    }
+
+    QTAILQ_FOREACH(priv,&privs, list) {
+        monitor_printf(mon, "%p: domid %d, fds %d,%d\n", priv,
+                       priv->domain->domid,
+                       priv->fd_read, priv->fd_write);
+        for (i = 1; i<  NR_EVENT_CHANNELS; i++) {
+            port = priv->domain->p + i;
+            if (port->priv != priv) {
+                continue;
+            }
+            monitor_printf(mon, "  port #%d: ", port->port);
+            if (port->peer) {
+                monitor_printf(mon, "peer #%d (%p, domid %d)\n",
+                               port->peer->port, port->peer->priv,
+                               port->peer->priv->domain->domid);
+            } else {
+                monitor_printf(mon, "no peer\n");
+            }
+        }
+    }
+}
+
+#endif
+




reply via email to

[Prev in Thread] Current Thread [Next in Thread]