From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from [140.186.70.92] (port=53875 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1PCwsi-0006ix-O9 for qemu-devel@nongnu.org; Mon, 01 Nov 2010 12:05:21 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1PCwZX-0001Ad-9a for qemu-devel@nongnu.org; Mon, 01 Nov 2010 11:45:25 -0400 Received: from mail-pv0-f173.google.com ([74.125.83.173]:39520) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1PCwZW-0001AU-VE for qemu-devel@nongnu.org; Mon, 01 Nov 2010 11:45:23 -0400 Received: by pvh11 with SMTP id 11so593362pvh.4 for ; Mon, 01 Nov 2010 08:45:22 -0700 (PDT) Message-ID: <4CCEE08F.4030403@codemonkey.ws> Date: Mon, 01 Nov 2010 10:45:19 -0500 From: Anthony Liguori MIME-Version: 1.0 Subject: Re: [Qemu-devel] [PATCH 28/40] xenner: libxc emu: evtchn References: <1288623713-28062-1-git-send-email-agraf@suse.de> <1288623713-28062-29-git-send-email-agraf@suse.de> In-Reply-To: <1288623713-28062-29-git-send-email-agraf@suse.de> Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Alexander Graf Cc: qemu-devel Developers , Gerd Hoffmann 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 > 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 > + * Alexander Graf > + * > + * 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. > + */ > + > +#include > +#include > + > +#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 > + >