[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH 1/2] xenner: add event channel implementation.
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
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |