* [Qemu-devel] [RfC / Patch] xenner: event channel implementation.
@ 2009-04-22 13:43 Gerd Hoffmann
2009-04-22 16:23 ` Avi Kivity
2009-04-22 16:45 ` Anthony Liguori
0 siblings, 2 replies; 6+ messages in thread
From: Gerd Hoffmann @ 2009-04-22 13:43 UTC (permalink / raw)
To: qemu-devel@nongnu.org, Xen Development Mailing List
[-- Attachment #1: Type: text/plain, Size: 1337 bytes --]
Hi,
Merging the xen bits seems to be on a good way. Time to look at
un-bitrotting the xenner bits ...
Here is a first patch for comments. Not useful on its own. Right now
I'm looking more for comments on the way the integration is done.
Event channels on Xen are managed by calling the xc_evtchn_* functions
provided by libxenctrl. The library in turn does does hypercalls into
the xen kernel. xenner obviously has to provide an alternative
implementation for these functions. Also for others. This patch starts
with just the event channels though.
It works this way: There is a struct with function pointers to the
event channel functions. The struct can be switched at runtime to the
xen or xenner version of the functions depending on the qemu operation mode.
The struct is named "xc_evtchn", the function pointer are named like the
xc_evtchn_* functions, but without the xc_evtchn_ prefix, i.e.
"xc_evtchn_open(...)" becomes xc_evtchn.open(...).
The function calls in the source code (xen backend drivers) are not
changed directly, but using a include file with a bunch of #defines.
That way I don't have to change s/xc_evtchn_/xc_evtchn./ all over the
place. Also xenner can easily be disabled at compile time and the
indirect function pointer calls simply go away then.
Comments?
cheers,
Gerd
[-- Attachment #2: 0005-xenner-event-channel-implementation.patch --]
[-- Type: text/plain, Size: 17423 bytes --]
>From a0a4cfe5040d3792875d7cd105aa2b832f6d8967 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Wed, 22 Apr 2009 12:56:04 +0200
Subject: [PATCH 5/5] xenner: event channel implementation.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
Makefile.target | 6 +
configure | 13 ++-
hw/xen.h | 2 +
hw/xen_backend.h | 1 +
hw/xenner_hooks.h | 21 ++
hw/xenner_interfaces.h | 28 +++
hw/xenner_libxc_evtchn.c | 455 ++++++++++++++++++++++++++++++++++++++++++++++
monitor.c | 5 +
8 files changed, 530 insertions(+), 1 deletions(-)
create mode 100644 hw/xenner_hooks.h
create mode 100644 hw/xenner_interfaces.h
create mode 100644 hw/xenner_libxc_evtchn.c
diff --git a/Makefile.target b/Makefile.target
index 2171587..e630d21 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -568,6 +568,12 @@ ifeq ($(CONFIG_XEN), yes)
LIBS += $(XEN_LIBS)
endif
+# xenner support
+XENNER_OBJS := xenner_libxc_evtchn.o
+ifeq ($(CONFIG_XENNER), yes)
+ OBJS += $(XENNER_OBJS)
+endif
+
# SCSI layer
OBJS+= lsi53c895a.o esp.o
diff --git a/configure b/configure
index b7b7b01..9eb8221 100755
--- a/configure
+++ b/configure
@@ -192,6 +192,7 @@ blobs="yes"
fdt="yes"
sdl_x11="no"
xen="yes"
+xenner="yes"
pkgversion=""
# OS specific
@@ -422,7 +423,9 @@ for opt do
;;
--disable-kqemu) kqemu="no"
;;
- --disable-xen) xen="no"
+ --disable-xen) xen="no"; xenner="no"
+ ;;
+ --disable-xenner) xenner="no"
;;
--disable-brlapi) brlapi="no"
;;
@@ -590,6 +593,7 @@ echo " --audio-card-list=LIST set list of emulated audio cards [$audio_card_l
echo " Available cards: $audio_possible_cards"
echo " --enable-mixemu enable mixer emulation"
echo " --disable-xen disable xen backend driver support"
+echo " --disable-xenner disable xenner (xen emulation) support"
echo " --disable-brlapi disable BrlAPI"
echo " --disable-vnc-tls disable TLS encryption for VNC server"
echo " --disable-vnc-sasl disable SASL encryption for VNC server"
@@ -818,6 +822,7 @@ EOF
:
else
xen="no"
+ xenner="no"
fi
fi
@@ -1317,6 +1322,7 @@ if test -n "$sparc_cpu"; then
fi
echo "kqemu support $kqemu"
echo "xen support $xen"
+echo "xenner support $xenner"
echo "brlapi support $brlapi"
echo "Documentation $build_docs"
[ ! -z "$uname_release" ] && \
@@ -1806,6 +1812,11 @@ case "$target_cpu" in
echo "CONFIG_XEN=yes" >> $config_mak
echo "#define CONFIG_XEN 1" >> $config_h
fi
+ if test "$xenner" = "yes" -a "$target_softmmu" = "yes";
+ then
+ echo "CONFIG_XENNER=yes" >> $config_mak
+ echo "#define CONFIG_XENNER 1" >> $config_h
+ fi
;;
x86_64)
echo "TARGET_ARCH=x86_64" >> $config_mak
diff --git a/hw/xen.h b/hw/xen.h
index 3c8da41..525a179 100644
--- a/hw/xen.h
+++ b/hw/xen.h
@@ -17,4 +17,6 @@ enum xen_mode {
extern uint32_t xen_domid;
extern enum xen_mode xen_mode;
+void do_info_evtchn(Monitor *mon);
+
#endif /* QEMU_HW_XEN_H */
diff --git a/hw/xen_backend.h b/hw/xen_backend.h
index 4dbfdb4..e9863cd 100644
--- a/hw/xen_backend.h
+++ b/hw/xen_backend.h
@@ -2,6 +2,7 @@
#define QEMU_HW_XEN_BACKEND_H 1
#include "xen_common.h"
+#include "xenner_hooks.h"
#include "sysemu.h"
#include "net.h"
#include "block_int.h"
diff --git a/hw/xenner_hooks.h b/hw/xenner_hooks.h
new file mode 100644
index 0000000..168a474
--- /dev/null
+++ b/hw/xenner_hooks.h
@@ -0,0 +1,21 @@
+#ifndef QEMU_HW_XENNER_HOOKS_H
+#define QEMU_HW_XENNER_HOOKS_H 1
+
+#include "xenner_interfaces.h"
+
+#if defined(CONFIG_XENNER)
+
+/* xen event channel interface */
+#define xc_evtchn_open xc_evtchn.open
+#define xc_evtchn_close xc_evtchn.close
+#define xc_evtchn_fd xc_evtchn.fd
+#define xc_evtchn_notify xc_evtchn.notify
+#define xc_evtchn_bind_unbound_port xc_evtchn.bind_unbound_port
+#define xc_evtchn_bind_interdomain xc_evtchn.bind_interdomain
+#define xc_evtchn_bind_virq xc_evtchn.bind_virq
+#define xc_evtchn_unbind xc_evtchn.unbind
+#define xc_evtchn_pending xc_evtchn.pending
+#define xc_evtchn_unmask xc_evtchn.unmask
+
+#endif /* CONFIG_XENNER */
+#endif /* QEMU_HW_XENNER_HOOKS_H */
diff --git a/hw/xenner_interfaces.h b/hw/xenner_interfaces.h
new file mode 100644
index 0000000..2a96ff4
--- /dev/null
+++ b/hw/xenner_interfaces.h
@@ -0,0 +1,28 @@
+#ifndef QEMU_HW_XENNER_INTERFACES_H
+#define QEMU_HW_XENNER_INTERFACES_H 1
+
+#if defined(CONFIG_XENNER)
+
+/* ------------------------------------------------------------- */
+/* 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 /* CONFIG_XENNER */
+#endif /* QEMU_HW_XENNER_INTERFACES_H */
diff --git a/hw/xenner_libxc_evtchn.c b/hw/xenner_libxc_evtchn.c
new file mode 100644
index 0000000..1fc49f3
--- /dev/null
+++ b/hw/xenner_libxc_evtchn.c
@@ -0,0 +1,455 @@
+#include <xenctrl.h>
+
+#include "hw.h"
+#include "qemu-log.h"
+#include "console.h"
+#include "monitor.h"
+#include "xen.h"
+#include "xenner_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;
+ 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;
+ int pending;
+ TAILQ_ENTRY(evtpriv) list;
+};
+static TAILQ_HEAD(evtpriv_head, evtpriv) privs = TAILQ_HEAD_INITIALIZER(privs);
+
+static int debug = 1;
+
+/* ------------------------------------------------------------- */
+
+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 (domid)
+ domain->domid = domid;
+ TAILQ_INSERT_TAIL(&domains, domain, list);
+ if (debug)
+ qemu_log("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)
+ qemu_log("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, const char *reason)
+{
+ struct port *p = NULL;
+ int i;
+
+ for (i = 1; i < NR_EVENT_CHANNELS; i++) {
+#if 1
+ /* debug hack */
+#define EA_START 20
+ if (priv->domain->domid && i < EA_START)
+ i = 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);
+ 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;
+
+ peer->count_snd++;
+ if (peer->pending)
+ return;
+
+ write(peer->priv->fd_write, &evtchn, sizeof(evtchn));
+ 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) {
+ qemu_log("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_open(void)
+{
+ struct evtpriv *priv;
+ int fd[2];
+
+ priv = qemu_mallocz(sizeof(*priv));
+ TAILQ_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);
+ }
+ 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;
+ /*
+ * 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;
+ 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,
+};
+
+/* ------------------------------------------------------------- */
+
+static int evtchn_emulation;
+
+void do_info_evtchn(Monitor *mon)
+{
+ struct evtpriv *priv;
+ struct port *port;
+ int i;
+
+ if (!evtchn_emulation) {
+ monitor_printf(mon, "Not emulating xen event channels.\n");
+ return;
+ }
+
+ TAILQ_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");
+ }
+ }
+}
+
+void xenner_evtchn_init(void)
+{
+ xc_evtchn = xenner_evtchn;
+ evtchn_emulation = 1;
+}
diff --git a/monitor.c b/monitor.c
index 3e945db..dc7ce7a 100644
--- a/monitor.c
+++ b/monitor.c
@@ -27,6 +27,7 @@
#include "hw/pcmcia.h"
#include "hw/pc.h"
#include "hw/pci.h"
+#include "hw/xen.h"
#include "gdbstub.h"
#include "net.h"
#include "qemu-char.h"
@@ -1846,6 +1847,10 @@ static const mon_cmd_t info_cmds[] = {
{ "migrate", "", do_info_migrate, "", "show migration status" },
{ "balloon", "", do_info_balloon,
"", "show balloon information" },
+#if defined(CONFIG_XENNER)
+ { "evtchn", "", do_info_evtchn,
+ "", "show xenner event channel information" },
+#endif
{ NULL, NULL, },
};
--
1.6.2.2
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [Qemu-devel] [RfC / Patch] xenner: event channel implementation.
2009-04-22 13:43 [Qemu-devel] [RfC / Patch] xenner: event channel implementation Gerd Hoffmann
@ 2009-04-22 16:23 ` Avi Kivity
2009-04-23 10:30 ` Gerd Hoffmann
2009-04-28 15:00 ` Gerd Hoffmann
2009-04-22 16:45 ` Anthony Liguori
1 sibling, 2 replies; 6+ messages in thread
From: Avi Kivity @ 2009-04-22 16:23 UTC (permalink / raw)
To: Gerd Hoffmann; +Cc: Xen Development Mailing List, qemu-devel@nongnu.org
Gerd Hoffmann wrote:
> Hi,
>
> Merging the xen bits seems to be on a good way. Time to look at
> un-bitrotting the xenner bits ...
>
> Here is a first patch for comments. Not useful on its own. Right now
> I'm looking more for comments on the way the integration is done.
>
> Event channels on Xen are managed by calling the xc_evtchn_* functions
> provided by libxenctrl. The library in turn does does hypercalls into
> the xen kernel. xenner obviously has to provide an alternative
> implementation for these functions. Also for others. This patch
> starts with just the event channels though.
>
> It works this way: There is a struct with function pointers to the
> event channel functions. The struct can be switched at runtime to the
> xen or xenner version of the functions depending on the qemu operation
> mode.
>
> The struct is named "xc_evtchn", the function pointer are named like
> the xc_evtchn_* functions, but without the xc_evtchn_ prefix, i.e.
> "xc_evtchn_open(...)" becomes xc_evtchn.open(...).
>
> The function calls in the source code (xen backend drivers) are not
> changed directly, but using a include file with a bunch of #defines.
> That way I don't have to change s/xc_evtchn_/xc_evtchn./ all over the
> place. Also xenner can easily be disabled at compile time and the
> indirect function pointer calls simply go away then.
>
I don't think the last bit is worthwhile. Function pointers these days
are pretty fast, their cost will be dwarfed by the syscall and hypercall
overhead.
> pecific
> @@ -422,7 +423,9 @@ for opt do
> ;;
> --disable-kqemu) kqemu="no"
> ;;
> - --disable-xen) xen="no"
> + --disable-xen) xen="no"; xenner="no"
> + ;;
> + --disable-xenner) xenner="no"
It would be nice to be able to build without the original Xen libraries.
>
> +
> +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 (domid)
> + domain->domid = domid;
> + TAILQ_INSERT_TAIL(&domains, domain, list);
> + if (debug)
> + qemu_log("xen ev: ?: new domain id %d\n", domain->domid);
> +
> +done:
> + domain->refcount++;
> + return domain;
> +}
Curious, can there be any domain other than the guest and the fake dom0
you're emulating?
--
error compiling committee.c: too many arguments to function
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Qemu-devel] [RfC / Patch] xenner: event channel implementation.
2009-04-22 16:23 ` Avi Kivity
@ 2009-04-23 10:30 ` Gerd Hoffmann
2009-04-28 15:00 ` Gerd Hoffmann
1 sibling, 0 replies; 6+ messages in thread
From: Gerd Hoffmann @ 2009-04-23 10:30 UTC (permalink / raw)
To: Avi Kivity; +Cc: Xen Development Mailing List, qemu-devel@nongnu.org
On 04/22/09 18:23, Avi Kivity wrote:
> Gerd Hoffmann wrote:
>> The function calls in the source code (xen backend drivers) are not
>> changed directly, but using a include file with a bunch of #defines.
>> That way I don't have to change s/xc_evtchn_/xc_evtchn./ all over the
>> place. Also xenner can easily be disabled at compile time and the
>> indirect function pointer calls simply go away then.
>
> I don't think the last bit is worthwhile. Function pointers these days
> are pretty fast, their cost will be dwarfed by the syscall and hypercall
> overhead.
>
>> - --disable-xen) xen="no"
>> + --disable-xen) xen="no"; xenner="no"
>
> It would be nice to be able to build without the original Xen libraries.
Hmm. I'll at least need the xen header files (at build time) anyway.
Making xen and xenner independent config options and don't link the xen
libraries for the !xen case should work without too much hassle (have to
make the function pointers mandatory then though).
>> +
>> +static struct domain *get_domain(int domid)
>> +{
>> + struct domain *domain;
>
> Curious, can there be any domain other than the guest and the fake dom0
> you're emulating?
No. It is the case for the current xenner implementation. The event
channels are handled by a daemon then and the guests can talk to each
other. This code is derived from the daemon. When moving xenner into
qemu the event channels allow only host <=> guest communication, so that
can probably simplified a bit. Not sure that would save that much code
though. I'll have a look.
cheers,
Gerd
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Qemu-devel] [RfC / Patch] xenner: event channel implementation.
2009-04-22 16:23 ` Avi Kivity
2009-04-23 10:30 ` Gerd Hoffmann
@ 2009-04-28 15:00 ` Gerd Hoffmann
1 sibling, 0 replies; 6+ messages in thread
From: Gerd Hoffmann @ 2009-04-28 15:00 UTC (permalink / raw)
To: Avi Kivity; +Cc: Xen Development Mailing List, qemu-devel@nongnu.org
[-- Attachment #1: Type: text/plain, Size: 1010 bytes --]
On 04/22/09 18:23, Avi Kivity wrote:
> Gerd Hoffmann wrote:
>> The function calls in the source code (xen backend drivers) are not
>> changed directly, but using a include file with a bunch of #defines.
>> That way I don't have to change s/xc_evtchn_/xc_evtchn./ all over the
>> place. Also xenner can easily be disabled at compile time and the
>> indirect function pointer calls simply go away then.
>
> I don't think the last bit is worthwhile. Function pointers these days
> are pretty fast, their cost will be dwarfed by the syscall and hypercall
> overhead.
New revision of the patch.
>> - --disable-xen) xen="no"
>> + --disable-xen) xen="no"; xenner="no"
>
> It would be nice to be able to build without the original Xen libraries.
Planned for. Will not work (yet) though as I'll have to emulate all xen
bits, and the event channels are only a part of the whole story.
> Curious, can there be any domain other than the guest and the fake dom0
> you're emulating?
Simplified that.
cheers,
Gerd
[-- Attachment #2: 0001-xenner-event-channel-implementation.patch --]
[-- Type: text/plain, Size: 18758 bytes --]
>From aa19020667d6ccab98eab2077042785e4a8559df Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Wed, 22 Apr 2009 12:56:04 +0200
Subject: [PATCH] xenner: event channel implementation.
---
Makefile.target | 19 ++-
configure | 18 ++-
hw/xen.h | 2 +
hw/xen_backend.h | 1 +
hw/xen_interfaces.c | 53 ++++++
hw/xen_interfaces.h | 31 ++++
hw/xen_machine_pv.c | 1 +
hw/xen_redirect.h | 18 ++
hw/xenner_libxc_evtchn.c | 401 ++++++++++++++++++++++++++++++++++++++++++++++
monitor.c | 5 +
10 files changed, 541 insertions(+), 8 deletions(-)
create mode 100644 hw/xen_interfaces.c
create mode 100644 hw/xen_interfaces.h
create mode 100644 hw/xen_redirect.h
create mode 100644 hw/xenner_libxc_evtchn.c
diff --git a/Makefile.target b/Makefile.target
index 82ada5a..4195026 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -561,14 +561,23 @@ ifdef CONFIG_BLUEZ
LIBS += $(CONFIG_BLUEZ_LIBS)
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 xenfb.o xen_disk.o xen_nic.o
-ifeq ($(CONFIG_XEN), yes)
- OBJS += $(XEN_OBJS)
+# xen backend drivers (shared by xenner+xen)
+ifneq ($(CONFIG_XEN)$(CONFIG_XENNER),)
+ OBJS += xen_machine_pv.o xen_backend.o xen_devconfig.o xen_interfaces.o
+ OBJS += xen_console.o xenfb.o xen_disk.o xen_nic.o
+endif
+
+# xen support
+ifeq ($(CONFIG_XEN),yes)
+ OBJS += xen_domainbuild.o
LIBS += $(XEN_LIBS)
endif
+# xenner support
+ifeq ($(CONFIG_XENNER),yes)
+ OBJS += xenner_libxc_evtchn.o
+endif
+
# SCSI layer
OBJS+= lsi53c895a.o esp.o
diff --git a/configure b/configure
index 1cbeabc..b28a664 100755
--- a/configure
+++ b/configure
@@ -194,6 +194,7 @@ blobs="yes"
fdt="yes"
sdl_x11="no"
xen="yes"
+xenner="yes"
pkgversion=""
# OS specific
@@ -424,7 +425,9 @@ for opt do
;;
--disable-kqemu) kqemu="no"
;;
- --disable-xen) xen="no"
+ --disable-xen) xen="no"; xenner="no"
+ ;;
+ --disable-xenner) xenner="no"
;;
--disable-brlapi) brlapi="no"
;;
@@ -596,6 +599,7 @@ echo " --audio-card-list=LIST set list of emulated audio cards [$audio_card_l
echo " Available cards: $audio_possible_cards"
echo " --enable-mixemu enable mixer emulation"
echo " --disable-xen disable xen backend driver support"
+echo " --disable-xenner disable xenner (xen emulation) support"
echo " --disable-brlapi disable BrlAPI"
echo " --disable-vnc-tls disable TLS encryption for VNC server"
echo " --disable-vnc-sasl disable SASL encryption for VNC server"
@@ -814,9 +818,10 @@ else
fi
##########################################
-# xen probe
+# probe for xen libs and includes
+# note: xenner included here as it needs the headers too.
-if test "$xen" = "yes" ; then
+if test "$xen" = "yes" -o "$xenner" = "yes"; then
cat > $TMPC <<EOF
#include <xenctrl.h>
#include <xs.h>
@@ -826,6 +831,7 @@ EOF
:
else
xen="no"
+ xenner="no"
fi
fi
@@ -1330,6 +1336,7 @@ if test -n "$sparc_cpu"; then
fi
echo "kqemu support $kqemu"
echo "xen support $xen"
+echo "xenner support $xenner"
echo "brlapi support $brlapi"
echo "Documentation $build_docs"
[ ! -z "$uname_release" ] && \
@@ -1825,6 +1832,11 @@ case "$target_cpu" in
echo "CONFIG_XEN=yes" >> $config_mak
echo "#define CONFIG_XEN 1" >> $config_h
fi
+ if test "$xenner" = "yes" -a "$target_softmmu" = "yes";
+ then
+ echo "CONFIG_XENNER=yes" >> $config_mak
+ echo "#define CONFIG_XENNER 1" >> $config_h
+ fi
;;
x86_64)
echo "TARGET_ARCH=x86_64" >> $config_mak
diff --git a/hw/xen.h b/hw/xen.h
index 3c8da41..525a179 100644
--- a/hw/xen.h
+++ b/hw/xen.h
@@ -17,4 +17,6 @@ enum xen_mode {
extern uint32_t xen_domid;
extern enum xen_mode xen_mode;
+void do_info_evtchn(Monitor *mon);
+
#endif /* QEMU_HW_XEN_H */
diff --git a/hw/xen_backend.h b/hw/xen_backend.h
index 4dbfdb4..2011dee 100644
--- a/hw/xen_backend.h
+++ b/hw/xen_backend.h
@@ -2,6 +2,7 @@
#define QEMU_HW_XEN_BACKEND_H 1
#include "xen_common.h"
+#include "xen_redirect.h"
#include "sysemu.h"
#include "net.h"
#include "block_int.h"
diff --git a/hw/xen_interfaces.c b/hw/xen_interfaces.c
new file mode 100644
index 0000000..573c674
--- /dev/null
+++ b/hw/xen_interfaces.c
@@ -0,0 +1,53 @@
+#include <xenctrl.h>
+
+#include "hw.h"
+#include "xen.h"
+#include "xen_interfaces.h"
+
+#ifdef CONFIG_XEN
+
+static int xc_evtchn_domid(int handle, int domid)
+{
+ return -1;
+}
+
+static struct XenEvtOps xc_evtchn_xen = {
+ .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,
+};
+
+#endif
+
+struct XenEvtOps xc_evtchn;
+
+void xen_interfaces_init(void)
+{
+ switch (xen_mode) {
+ case XEN_ATTACH:
+ case XEN_CREATE:
+#ifdef CONFIG_XEN
+ xc_evtchn = xc_evtchn_xen;
+#else
+ fprintf(stderr, "ERROR: Compiled without xen support, sorry.\n");
+ exit(1);
+#endif
+ break;
+ case XEN_EMULATE:
+#ifdef CONFIG_XENNER
+ xc_evtchn = xc_evtchn_xenner;
+#else
+ fprintf(stderr, "ERROR: Compiled without xenner support, sorry.\n");
+ exit(1);
+#endif
+ break;
+ }
+}
diff --git a/hw/xen_interfaces.h b/hw/xen_interfaces.h
new file mode 100644
index 0000000..119e0e0
--- /dev/null
+++ b/hw/xen_interfaces.h
@@ -0,0 +1,31 @@
+#ifndef QEMU_HW_XEN_INTERFACES_H
+#define QEMU_HW_XEN_INTERFACES_H 1
+
+/* ------------------------------------------------------------- */
+/* 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;
+
+/* ------------------------------------------------------------- */
+
+#ifdef CONFIG_XENNER
+extern struct XenEvtOps xc_evtchn_xenner;
+#endif
+
+void xen_interfaces_init(void);
+
+#endif /* QEMU_HW_XEN_INTERFACES_H */
diff --git a/hw/xen_machine_pv.c b/hw/xen_machine_pv.c
index 58209b8..0476ebe 100644
--- a/hw/xen_machine_pv.c
+++ b/hw/xen_machine_pv.c
@@ -54,6 +54,7 @@ static void xen_init_pv(ram_addr_t ram_size, int vga_ram_size,
env->halted = 1;
/* Initialize backend core & drivers */
+ xen_interfaces_init();
if (xen_be_init() != 0) {
fprintf(stderr, "%s: xen backend core setup failed\n", __FUNCTION__);
exit(1);
diff --git a/hw/xen_redirect.h b/hw/xen_redirect.h
new file mode 100644
index 0000000..ea08fd9
--- /dev/null
+++ b/hw/xen_redirect.h
@@ -0,0 +1,18 @@
+#ifndef QEMU_HW_XEN_REDIRECT_H
+#define QEMU_HW_XEN_REDIRECT_H 1
+
+#include "xen_interfaces.h"
+
+/* xen event channel interface */
+#define xc_evtchn_open xc_evtchn.open
+#define xc_evtchn_close xc_evtchn.close
+#define xc_evtchn_fd xc_evtchn.fd
+#define xc_evtchn_notify xc_evtchn.notify
+#define xc_evtchn_bind_unbound_port xc_evtchn.bind_unbound_port
+#define xc_evtchn_bind_interdomain xc_evtchn.bind_interdomain
+#define xc_evtchn_bind_virq xc_evtchn.bind_virq
+#define xc_evtchn_unbind xc_evtchn.unbind
+#define xc_evtchn_pending xc_evtchn.pending
+#define xc_evtchn_unmask xc_evtchn.unmask
+
+#endif /* QEMU_HW_XEN_REDIRECT_H */
diff --git a/hw/xenner_libxc_evtchn.c b/hw/xenner_libxc_evtchn.c
new file mode 100644
index 0000000..486674b
--- /dev/null
+++ b/hw/xenner_libxc_evtchn.c
@@ -0,0 +1,401 @@
+#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;
+ TAILQ_ENTRY(evtpriv) list;
+};
+static TAILQ_HEAD(evtpriv_head, evtpriv) privs = TAILQ_HEAD_INITIALIZER(privs);
+
+static int debug = 1;
+
+/* ------------------------------------------------------------- */
+
+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)
+{
+ if (domid == 0)
+ return &dom0;
+ if (domU.domid == 0)
+ 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++) {
+#if 1
+ /* debug hack */
+#define EA_START 20
+ if (priv->domain->domid && i < EA_START)
+ i = 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;
+
+ peer->count_snd++;
+ if (peer->pending)
+ return;
+
+ write(peer->priv->fd_write, &evtchn, sizeof(evtchn));
+ 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) {
+ qemu_log("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_open(void)
+{
+ struct evtpriv *priv;
+ int fd[2];
+
+ priv = qemu_mallocz(sizeof(*priv));
+ TAILQ_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);
+ 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;
+ /*
+ * 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_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,
+};
+
+/* ------------------------------------------------------------- */
+
+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;
+ }
+
+ TAILQ_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");
+ }
+ }
+}
diff --git a/monitor.c b/monitor.c
index b33fea1..33b0dcc 100644
--- a/monitor.c
+++ b/monitor.c
@@ -27,6 +27,7 @@
#include "hw/pcmcia.h"
#include "hw/pc.h"
#include "hw/pci.h"
+#include "hw/xen.h"
#include "gdbstub.h"
#include "net.h"
#include "qemu-char.h"
@@ -1846,6 +1847,10 @@ static const mon_cmd_t info_cmds[] = {
{ "migrate", "", do_info_migrate, "", "show migration status" },
{ "balloon", "", do_info_balloon,
"", "show balloon information" },
+#if defined(CONFIG_XENNER)
+ { "evtchn", "", do_info_evtchn,
+ "", "show xenner event channel information" },
+#endif
{ NULL, NULL, },
};
--
1.6.2.2
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [Qemu-devel] [RfC / Patch] xenner: event channel implementation.
2009-04-22 13:43 [Qemu-devel] [RfC / Patch] xenner: event channel implementation Gerd Hoffmann
2009-04-22 16:23 ` Avi Kivity
@ 2009-04-22 16:45 ` Anthony Liguori
2009-04-23 10:34 ` Gerd Hoffmann
1 sibling, 1 reply; 6+ messages in thread
From: Anthony Liguori @ 2009-04-22 16:45 UTC (permalink / raw)
To: Gerd Hoffmann; +Cc: Xen Development Mailing List, qemu-devel@nongnu.org
Gerd Hoffmann wrote:
> Hi,
>
> Merging the xen bits seems to be on a good way. Time to look at
> un-bitrotting the xenner bits ...
>
> Here is a first patch for comments. Not useful on its own. Right now
> I'm looking more for comments on the way the integration is done.
>
> Event channels on Xen are managed by calling the xc_evtchn_* functions
> provided by libxenctrl. The library in turn does does hypercalls into
> the xen kernel. xenner obviously has to provide an alternative
> implementation for these functions. Also for others. This patch
> starts with just the event channels though.
With xenner, do you still use xenstore/xenconsoled? If so, don't you
need some LD_PRELOAD magic to make that work?
Regards,
Anthony Liguori
> It works this way: There is a struct with function pointers to the
> event channel functions. The struct can be switched at runtime to the
> xen or xenner version of the functions depending on the qemu operation
> mode.
>
> The struct is named "xc_evtchn", the function pointer are named like
> the xc_evtchn_* functions, but without the xc_evtchn_ prefix, i.e.
> "xc_evtchn_open(...)" becomes xc_evtchn.open(...).
>
> The function calls in the source code (xen backend drivers) are not
> changed directly, but using a include file with a bunch of #defines.
> That way I don't have to change s/xc_evtchn_/xc_evtchn./ all over the
> place. Also xenner can easily be disabled at compile time and the
> indirect function pointer calls simply go away then.
>
> Comments?
>
> cheers,
> Gerd
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Qemu-devel] [RfC / Patch] xenner: event channel implementation.
2009-04-22 16:45 ` Anthony Liguori
@ 2009-04-23 10:34 ` Gerd Hoffmann
0 siblings, 0 replies; 6+ messages in thread
From: Gerd Hoffmann @ 2009-04-23 10:34 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Xen Development Mailing List, qemu-devel@nongnu.org
On 04/22/09 18:45, Anthony Liguori wrote:
> Gerd Hoffmann wrote:
>> Event channels on Xen are managed by calling the xc_evtchn_* functions
>> provided by libxenctrl. The library in turn does does hypercalls into
>> the xen kernel. xenner obviously has to provide an alternative
>> implementation for these functions. Also for others. This patch starts
>> with just the event channels though.
>
> With xenner, do you still use xenstore/xenconsoled?
The current standalone version does. The qemu-merged version will not.
cheers,
Gerd
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2009-04-28 15:01 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-04-22 13:43 [Qemu-devel] [RfC / Patch] xenner: event channel implementation Gerd Hoffmann
2009-04-22 16:23 ` Avi Kivity
2009-04-23 10:30 ` Gerd Hoffmann
2009-04-28 15:00 ` Gerd Hoffmann
2009-04-22 16:45 ` Anthony Liguori
2009-04-23 10:34 ` Gerd Hoffmann
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).