qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Gerd Hoffmann <kraxel@redhat.com>
To: qemu-devel@nongnu.org, xen-devel@lists.xensource.com
Cc: Gerd Hoffmann <kraxel@redhat.com>
Subject: [Qemu-devel] [PATCH 1/2] xenner: add event channel implementation.
Date: Fri, 22 Aug 2008 12:25:27 +0200	[thread overview]
Message-ID: <1219400728-20422-2-git-send-email-kraxel@redhat.com> (raw)
In-Reply-To: <1219400728-20422-1-git-send-email-kraxel@redhat.com>

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

  reply	other threads:[~2008-08-22 10:25 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-08-22 10:25 [Qemu-devel] [PATCH 0/2] RfC: xenner (aka xen emulation) bits Gerd Hoffmann
2008-08-22 10:25 ` Gerd Hoffmann [this message]
2008-08-22 13:46   ` [Qemu-devel] [PATCH 1/2] xenner: add event channel implementation Anthony Liguori
2008-08-22 15:04     ` Gerd Hoffmann
2008-08-25 12:58       ` Gerd Hoffmann
2008-08-25 14:15         ` Anthony Liguori
2008-08-25 15:12           ` [Xen-devel] " Keir Fraser
2008-08-25 17:57             ` Anthony Liguori
2008-08-25 18:42               ` Keir Fraser
2008-08-26  8:27                 ` Gerd Hoffmann
2008-08-26  8:40                   ` Keir Fraser
2008-08-26  8:39                 ` Daniel P. Berrange
2008-08-22 10:25 ` [Qemu-devel] [PATCH 2/2] xenner: use evtchn function pointers in the backends Gerd Hoffmann
     [not found] ` <m2n.s.1KWU8S-002Pyj@chiark.greenend.org.uk>
2008-08-26 11:02   ` [Qemu-devel] [PATCH 1/2] xenner: add event channel implementation Ian Jackson
2008-08-26 13:13     ` Gerd Hoffmann
2008-08-26 13:28       ` Ian Jackson
2008-08-26 19:34         ` Gerd Hoffmann

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=1219400728-20422-2-git-send-email-kraxel@redhat.com \
    --to=kraxel@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=xen-devel@lists.xensource.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).