From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1KNTTo-00006U-F5 for qemu-devel@nongnu.org; Mon, 28 Jul 2008 10:13:40 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1KNTTn-00005F-6c for qemu-devel@nongnu.org; Mon, 28 Jul 2008 10:13:40 -0400 Received: from [199.232.76.173] (port=46141 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1KNTTm-00004q-Q2 for qemu-devel@nongnu.org; Mon, 28 Jul 2008 10:13:38 -0400 Received: from wr-out-0506.google.com ([64.233.184.238]:43562) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1KNTTm-0003sj-7Q for qemu-devel@nongnu.org; Mon, 28 Jul 2008 10:13:38 -0400 Received: by wr-out-0506.google.com with SMTP id c46so4016068wra.18 for ; Mon, 28 Jul 2008 07:13:37 -0700 (PDT) Message-ID: <488DD3F0.9060007@codemonkey.ws> Date: Mon, 28 Jul 2008 09:13:04 -0500 From: Anthony Liguori MIME-Version: 1.0 Subject: Re: [Qemu-devel] [PATCH 2/7] xen: backend driver core References: <1217251078-6591-1-git-send-email-kraxel@redhat.com> <1217251078-6591-3-git-send-email-kraxel@redhat.com> In-Reply-To: <1217251078-6591-3-git-send-email-kraxel@redhat.com> Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Reply-To: qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: xen-devel@lists.xensource.com, Gerd Hoffmann Gerd Hoffmann wrote: > This patch adds infrastructure for xen backend drivers living in qemu, > so drivers don't need to implement common stuff on their own. It's > mostly xenbus management stuff: some functions to access xentore, > setting up xenstore watches, callbacks on device discovery and state > changes, handle event channel, ... > > Signed-off-by: Gerd Hoffmann > --- > Makefile.target | 2 +- > hw/list.h | 169 ++++++++++++++ > hw/xen-backend.c | 663 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ > hw/xen-backend.h | 116 ++++++++++ > hw/xen-machine.c | 5 +- > 5 files changed, 953 insertions(+), 2 deletions(-) > create mode 100644 hw/list.h > create mode 100644 hw/xen-backend.c > create mode 100644 hw/xen-backend.h > > diff --git a/Makefile.target b/Makefile.target > index 4f42582..0451048 100644 > --- a/Makefile.target > +++ b/Makefile.target > @@ -516,7 +516,7 @@ LIBS += $(CONFIG_VNC_TLS_LIBS) > endif > > # xen backend driver support > -XEN_OBJS := xen-machine.o > +XEN_OBJS := xen-machine.o xen-backend.o > ifeq ($(CONFIG_XEN), yes) > OBJS += $(XEN_OBJS) > LIBS += $(XEN_LIBS) > diff --git a/hw/list.h b/hw/list.h > new file mode 100644 > index 0000000..fa9f790 > --- /dev/null > +++ b/hw/list.h > There's already a list implementation in audio/sys-queue.h > diff --git a/hw/xen-backend.c b/hw/xen-backend.c > new file mode 100644 > index 0000000..4819624 > --- /dev/null > +++ b/hw/xen-backend.c > @@ -0,0 +1,663 @@ > +/* > + * xen backend driver infrastructure > + * > + * 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, write to the Free Software > + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include > +#include > + > +#include "hw.h" > +#include "qemu-char.h" > +#include "xen-backend.h" > + > +/* ------------------------------------------------------------- */ > + > +/* public */ > +int xen_xc; > +struct xs_handle *xenstore = NULL; > + > +/* private */ > +static LIST_HEAD(xendevs); > +static const char *root = "/local/domain/0/backend"; > +static int debug = 0; > + > +/* ------------------------------------------------------------- */ > I think it would be good to provide some more commenting in this file. Just a high level description of XenStore and how all of this stuff fits together would be nice. > +int xenstore_write_str(const char *base, const char *node, const char *val) > +{ > + char abspath[BUFSIZE]; > + > + snprintf(abspath, sizeof(abspath), "%s/%s", base, node); > + if (!xs_write(xenstore, 0, abspath, val, strlen(val))) > + return -1; > + return 0; > +} > + > +char *xenstore_read_str(const char *base, const char *node) > +{ > + char abspath[BUFSIZE]; > + unsigned int len; > + > + snprintf(abspath, sizeof(abspath), "%s/%s", base, node); > + return xs_read(xenstore, 0, abspath, &len); > +} > + > +int xenstore_write_int(const char *base, const char *node, int ival) > +{ > + char val[32]; > + > + snprintf(val, sizeof(val), "%d", ival); > + return xenstore_write_str(base, node, val); > +} > + > +int xenstore_read_int(const char *base, const char *node, int *ival) > +{ > + char *val; > + int rc = -1; > + > + val = xenstore_read_str(base, node); > + if (val && 1 == sscanf(val, "%d", ival)) > + rc = 0; > + free(val); > + return rc; > +} > + > +int xenstore_write_be_str(struct xendev *xendev, const char *node, const char *val) > +{ > + return xenstore_write_str(xendev->be, node, val); > +} > + > +int xenstore_write_be_int(struct xendev *xendev, const char *node, int ival) > +{ > + return xenstore_write_int(xendev->be, node, ival); > +} > + > +char *xenstore_read_be_str(struct xendev *xendev, const char *node) > +{ > + return xenstore_read_str(xendev->be, node); > +} > + > +int xenstore_read_be_int(struct xendev *xendev, const char *node, int *ival) > +{ > + return xenstore_read_int(xendev->be, node, ival); > +} > + > +char *xenstore_read_fe_str(struct xendev *xendev, const char *node) > +{ > + return xenstore_read_str(xendev->fe, node); > +} > + > +int xenstore_read_fe_int(struct xendev *xendev, const char *node, int *ival) > +{ > + return xenstore_read_int(xendev->fe, node, ival); > +} > + > +/* ------------------------------------------------------------- */ > + > +const char *xenbus_strstate(enum xenbus_state state) > +{ > + static const char *const name[] = { > + [ XenbusStateUnknown ] = "Unknown", > + [ XenbusStateInitialising ] = "Initialising", > + [ XenbusStateInitWait ] = "InitWait", > + [ XenbusStateInitialised ] = "Initialised", > + [ XenbusStateConnected ] = "Connected", > + [ XenbusStateClosing ] = "Closing", > + [ XenbusStateClosed ] = "Closed", > + }; > + return (state < ARRAY_SIZE(name)) ? name[state] : "INVALID"; > +} > + > +int xen_be_set_state(struct xendev *xendev, enum xenbus_state state) > +{ > + int rc; > + > + rc = xenstore_write_be_int(xendev, "state", state); > + if (0 != rc) > It's a nit, but try to avoid the defensive ifs. > + return rc; > + xen_be_printf(xendev, 1, "backend state: %s -> %s\n", > + xenbus_strstate(xendev->be_state), xenbus_strstate(state)); > + xendev->be_state = state; > + return 0; > +} > + > +/* ------------------------------------------------------------- */ > + > +struct xendev *xen_be_find_xendev(char *type, int dom, int dev) > +{ > + struct xendev *xendev; > + struct list_head *item; > + > + list_for_each(item, &xendevs) { > + xendev = list_entry(item, struct xendev, next); > + if (xendev->dom != dom) > + continue; > + if (xendev->dev != dev) > + continue; > + if (0 != strcmp(xendev->type, type)) > + continue; > + return xendev; > + } > + return NULL; > +} > + > +/* > + * get xen backend device, allocate a new one if it doesn't exist. > + */ > +static struct xendev *xen_be_get_xendev(char *type, int dom, int dev, > + struct devops *ops) > +{ > + struct xendev *xendev; > + > + xendev = xen_be_find_xendev(type, dom, dev); > + if (xendev) > + return xendev; > + > + /* init new xendev */ > + xendev = malloc(ops->size); > + memset(xendev,0,ops->size); > qemu_mallocz() > + xendev->type = type; > + xendev->dom = dom; > + xendev->dev = dev; > + xendev->ops = ops; > + snprintf(xendev->be, sizeof(xendev->be), "%s/%s/%d/%d", > + root, xendev->type, xendev->dom, xendev->dev); > + snprintf(xendev->name, sizeof(xendev->name), "%s-%d", > + xendev->type, xendev->dev); > + > + xendev->debug = debug; > + xendev->local_port = -1; > + > + xendev->evtchndev = xc_evtchn_open(); > + if (xendev->evtchndev < 0) { > + fprintf(stderr, "can't open evtchn device\n"); > + free(xendev); > qemu_free() Considering all you're doing, the patch looks pretty nice. Regards, Anthony Liguori > + return NULL; > + } > + fcntl(xc_evtchn_fd(xendev->evtchndev), F_SETFD, FD_CLOEXEC); > + > + if (ops->flags & DEVOPS_FLAG_NEED_GNTDEV) { > + xendev->gnttabdev = xc_gnttab_open(); > + if (xendev->gnttabdev < 0) { > + fprintf(stderr, "can't open gnttab device\n"); > + xc_evtchn_close(xendev->evtchndev); > + free(xendev); > + return NULL; > + } > + } else { > + xendev->gnttabdev = -1; > + } > + > + list_add_tail(&xendev->next, &xendevs); > + > + if (xendev->ops->alloc) > + xendev->ops->alloc(xendev); > + > + return xendev; > +} > + > +/* > + * release xen backend device. > + */ > +static struct xendev *xen_be_del_xendev(int dom, int dev) > +{ > + struct xendev *xendev; > + struct list_head *item, *tmp; > + > + list_for_each_safe(item, tmp, &xendevs) { > + xendev = list_entry(item, struct xendev, next); > + if (xendev->dom != dom) > + continue; > + if (xendev->dev != dev && dev != -1) > + continue; > + > + if (xendev->ops->free) > + xendev->ops->free(xendev); > + > + if (xendev->fe) { > + char token[BUFSIZE]; > + snprintf(token, sizeof(token), "fe:%p", xendev); > + xs_unwatch(xenstore, xendev->fe, token); > + free(xendev->fe); > + } > + > + if (xendev->evtchndev >= 0) > + xc_evtchn_close(xendev->evtchndev); > + if (xendev->gnttabdev >= 0) > + xc_gnttab_close(xendev->gnttabdev); > + > + list_del(&xendev->next); > + free(xendev); > + } > + return NULL; > +} > + > +/* > + * Sync internal data structures on xenstore updates. > + * Node specifies the changed field. node = NULL means > + * update all fields (used for initialization). > + */ > +static void xen_be_backend_changed(struct xendev *xendev, const char *node) > +{ > + if (NULL == node || 0 == strcmp(node, "online")) { > + if (-1 == xenstore_read_be_int(xendev, "online", &xendev->online)) > + xendev->online = 0; > + } > + > + if (node) { > + xen_be_printf(xendev, 2, "backend update: %s\n", node); > + if (xendev->ops->backend_changed) > + xendev->ops->backend_changed(xendev, node); > + } > +} > + > +static void xen_be_frontend_changed(struct xendev *xendev, const char *node) > +{ > + int fe_state; > + > + if (NULL == node || 0 == strcmp(node, "state")) { > + if (-1 == xenstore_read_fe_int(xendev, "state", &fe_state)) > + fe_state = XenbusStateUnknown; > + if (xendev->fe_state != fe_state) > + xen_be_printf(xendev, 1, "frontend state: %s -> %s\n", > + xenbus_strstate(xendev->fe_state), > + xenbus_strstate(fe_state)); > + xendev->fe_state = fe_state; > + } > + if (NULL == node || 0 == strcmp(node, "protocol")) { > + free(xendev->protocol); > + xendev->protocol = xenstore_read_fe_str(xendev, "protocol"); > + if (xendev->protocol) > + xen_be_printf(xendev, 1, "frontend protocol: %s\n", xendev->protocol); > + } > + > + if (node) { > + xen_be_printf(xendev, 2, "frontend update: %s\n", node); > + if (xendev->ops->frontend_changed) > + xendev->ops->frontend_changed(xendev, node); > + } > +} > + > +/* ------------------------------------------------------------- */ > +/* Check for possible state transitions and perform them. */ > + > +/* > + * Initial xendev setup. Read frontend path, register watch for it. > + * Should succeed once xend finished setting up the backend device. > + * > + * Also sets initial state (-> Initializing) when done. Which > + * only affects the xendev->be_state variable as xenbus should > + * already be put into that state by xend. > + */ > +static int xen_be_try_setup(struct xendev *xendev) > +{ > + char token[BUFSIZE]; > + int be_state; > + > + if (-1 == xenstore_read_be_int(xendev, "state", &be_state)) { > + xen_be_printf(xendev, 0, "reading backend state failed\n"); > + return -1; > + } > + > + if (be_state != XenbusStateInitialising) { > + xen_be_printf(xendev, 0, "initial backend state is wrong (%s)\n", > + xenbus_strstate(be_state)); > + return -1; > + } > + > + xendev->fe = xenstore_read_be_str(xendev, "frontend"); > + if (NULL == xendev->fe) { > + xen_be_printf(xendev, 0, "reading frontend path failed\n"); > + return -1; > + } > + > + /* setup frontend watch */ > + snprintf(token, sizeof(token), "fe:%p", xendev); > + if (!xs_watch(xenstore, xendev->fe, token)) { > + xen_be_printf(xendev, 0, "watching frontend path (%s) failed\n", > + xendev->fe); > + return -1; > + } > + xen_be_set_state(xendev, XenbusStateInitialising); > + > + xen_be_backend_changed(xendev, NULL); > + xen_be_frontend_changed(xendev, NULL); > + return 0; > +} > + > +/* > + * Try initialize xendev. Prepare everything the backend can do > + * without synchronizing with the frontend. Fakes hotplug-status. No > + * hotplug involved here because this is about userspace drivers, thus > + * there are kernel backend devices which could invoke hotplug. > + * > + * Goes to InitWait on success. > + */ > +static int xen_be_try_init(struct xendev *xendev) > +{ > + int rc = 0; > + > + if (!xendev->online) { > + xen_be_printf(xendev, 1, "not online\n"); > + return -1; > + } > + > + if (xendev->ops->init) > + rc = xendev->ops->init(xendev); > + if (0 != rc) { > + xen_be_printf(xendev, 1, "init() failed\n"); > + return rc; > + } > + > + xenstore_write_be_str(xendev, "hotplug-status", "connected"); > + xen_be_set_state(xendev, XenbusStateInitWait); > + return 0; > +} > + > +/* > + * Try to connect xendev. Depends on the frontend being ready > + * for it (shared ring and evtchn info in xenstore, state being > + * Initialised or Connected). > + * > + * Goes to Connected on success. > + */ > +static int xen_be_try_connect(struct xendev *xendev) > +{ > + int rc = 0; > + > + if (xendev->fe_state != XenbusStateInitialised && > + xendev->fe_state != XenbusStateConnected) { > + if (xendev->ops->flags & DEVOPS_FLAG_IGNORE_STATE) { > + xen_be_printf(xendev, 2, "frontend not ready, ignoring\n"); > + } else { > + xen_be_printf(xendev, 2, "frontend not ready (yet)\n"); > + return -1; > + } > + } > + > + if (xendev->ops->connect) > + rc = xendev->ops->connect(xendev); > + if (0 != rc) { > + xen_be_printf(xendev, 0, "connect() failed\n"); > + return rc; > + } > + > + xen_be_set_state(xendev, XenbusStateConnected); > + > +#if 0 > + if (xendev->ops->event) > + xendev->ops->event(xendev); > +#endif > + return 0; > +} > + > +/* > + * Teardown connection. > + * > + * Goes to Closed when done. > + */ > +static void xen_be_disconnect(struct xendev *xendev) > +{ > + if (xendev->be_state == XenbusStateClosed) > + return; > + if (xendev->ops->disconnect) > + xendev->ops->disconnect(xendev); > + xen_be_set_state(xendev, XenbusStateClosed); > +} > + > +/* > + * state change dispatcher function > + */ > +void xen_be_check_state(struct xendev *xendev) > +{ > + int rc = 0; > + > + /* frontend may request shutdown from almost anywhere */ > + if (xendev->fe_state == XenbusStateClosing || > + xendev->fe_state == XenbusStateClosed) { > + xen_be_disconnect(xendev); > + return; > + } > + > + /* check for possible backend state transitions */ > + for (;;) { > + switch (xendev->be_state) { > + case XenbusStateUnknown: > + rc = xen_be_try_setup(xendev); > + break; > + case XenbusStateInitialising: > + rc = xen_be_try_init(xendev); > + break; > + case XenbusStateInitWait: > + rc = xen_be_try_connect(xendev); > + break; > + default: > + rc = -1; > + } > + if (0 != rc) > + break; > + } > +} > + > +/* ------------------------------------------------------------- */ > + > +static int xenstore_scan(char *type, int dom, struct devops *ops) > +{ > + struct xendev *xendev; > + char path[BUFSIZE], token[BUFSIZE]; > + char **dev = NULL; > + unsigned int cdev, j; > + > + /* setup watch */ > + snprintf(token, sizeof(token), "be:%p:%d:%p", type, dom, ops); > + snprintf(path, sizeof(path), "%s/%s/%d", root, type, dom); > + if (!xs_watch(xenstore, path, token)) { > + fprintf(stderr, "xen be: watching backend path (%s) failed\n", path); > + return -1; > + } > + > + /* look for backends */ > + dev = xs_directory(xenstore, 0, path, &cdev); > + if (!dev) > + return 0; > + for (j = 0; j < cdev; j++) { > + xendev = xen_be_get_xendev(type, dom, atoi(dev[j]), ops); > + if (NULL == xendev) > + continue; > + xen_be_check_state(xendev); > + } > + free(dev); > + return 0; > +} > + > +static void xenstore_update_be(char *watch, char *type, int dom, > + struct devops *ops) > +{ > + struct xendev *xendev; > + char path[BUFSIZE]; > + unsigned int len, dev; > + > + len = snprintf(path, sizeof(path), "%s/%s/%d", root, type, dom); > + if (0 != strncmp(path, watch, len)) > + return; > + if (2 != sscanf(watch+len, "/%u/%255s", &dev, path)) { > + strcpy(path, ""); > + if (1 != sscanf(watch+len, "/%u", &dev)) > + dev = -1; > + } > + if (-1 == dev) > + return; > + > + if (0) { > + /* FIXME: detect devices being deleted from xenstore ... */ > + xen_be_del_xendev(dom, dev); > + } > + > + xendev = xen_be_get_xendev(type, dom, dev, ops); > + if (NULL != xendev) { > + xen_be_backend_changed(xendev, path); > + xen_be_check_state(xendev); > + } > +} > + > +static void xenstore_update_fe(char *watch, struct xendev *xendev) > +{ > + char *node; > + unsigned int len; > + > + len = strlen(xendev->fe); > + if (0 != strncmp(xendev->fe, watch, len)) > + return; > + if (watch[len] != '/') > + return; > + node = watch + len + 1; > + > + xen_be_frontend_changed(xendev, node); > + xen_be_check_state(xendev); > +} > + > +static void xenstore_update(void *unused) > +{ > + char **vec = NULL; > + intptr_t type, ops, ptr; > + unsigned int dom, count; > + > + vec = xs_read_watch(xenstore, &count); > + if (NULL == vec) > + goto cleanup; > + > + if (3 == sscanf(vec[XS_WATCH_TOKEN], "be:%" PRIxPTR ":%d:%" PRIxPTR, > + &type, &dom, &ops)) > + xenstore_update_be(vec[XS_WATCH_PATH], (void*)type, dom, (void*)ops); > + if (1 == sscanf(vec[XS_WATCH_TOKEN], "fe:%" PRIxPTR, &ptr)) > + xenstore_update_fe(vec[XS_WATCH_PATH], (void*)ptr); > + > +cleanup: > + free(vec); > +} > + > +static void xen_be_evtchn_event(void *opaque) > +{ > + struct xendev *xendev = opaque; > + evtchn_port_t port; > + > + port = xc_evtchn_pending(xendev->evtchndev); > + if (port != xendev->local_port) { > + xen_be_printf(xendev, 0, "xc_evtchn_pending returned %d (expected %d)\n", > + port, xendev->local_port); > + return; > + } > + xc_evtchn_unmask(xendev->evtchndev, port); > + > + if (xendev->ops->event) > + xendev->ops->event(xendev); > +} > + > +/* -------------------------------------------------------------------- */ > + > +int xen_be_init(void) > +{ > + xenstore = xs_daemon_open(); > + if (!xenstore) { > + fprintf(stderr, "can't connect to xenstored\n"); > + return -1; > + } > + > + if (qemu_set_fd_handler(xs_fileno(xenstore), xenstore_update, NULL, NULL) < 0) > + goto err; > + > + xen_xc = xc_interface_open(); > + if (-1 == xen_xc) { > + fprintf(stderr, "can't open xen interface\n"); > + goto err; > + } > + return 0; > + > +err: > + qemu_set_fd_handler(xs_fileno(xenstore), NULL, NULL, NULL); > + xs_daemon_close(xenstore); > + xenstore = NULL; > + > + return -1; > +} > + > +int xen_be_register(char *type, struct devops *ops) > +{ > + return xenstore_scan(type, xen_domid, ops); > +} > + > +int xen_be_bind_evtchn(struct xendev *xendev) > +{ > + if (xendev->local_port != -1) > + return 0; > + xendev->local_port = xc_evtchn_bind_interdomain > + (xendev->evtchndev, xendev->dom, xendev->remote_port); > + if (-1 == xendev->local_port) { > + xendev->local_port = 0; > + return -1; > + } > + qemu_set_fd_handler(xc_evtchn_fd(xendev->evtchndev), > + xen_be_evtchn_event, NULL, xendev); > +#if 0 > + xc_evtchn_unmask(xendev->evtchndev, xendev->local_port); > +#endif > + return 0; > +} > + > +void xen_be_unbind_evtchn(struct xendev *xendev) > +{ > + if (xendev->local_port == -1) > + return; > + qemu_set_fd_handler(xc_evtchn_fd(xendev->evtchndev), NULL, NULL, NULL); > + xc_evtchn_unbind(xendev->evtchndev, xendev->local_port); > + xendev->local_port = -1; > +} > + > +int xen_be_send_notify(struct xendev *xendev) > +{ > + return xc_evtchn_notify(xendev->evtchndev, xendev->local_port); > +} > + > +/* > + * msg_level: > + * 0 == errors. > + * 1 == informative debug messages. > + * 2 == noisy debug messages. > + * 3 == will flood your log. > + */ > +void xen_be_printf(struct xendev *xendev, int msg_level, const char *fmt, ...) > +{ > + va_list args; > + > + if (msg_level > xendev->debug) > + return; > + fprintf(stderr, "xen be: %s: ", xendev->name); > + va_start(args, fmt); > + vfprintf(stderr, fmt, args); > + va_end(args); > +} > diff --git a/hw/xen-backend.h b/hw/xen-backend.h > new file mode 100644 > index 0000000..db36ae7 > --- /dev/null > +++ b/hw/xen-backend.h > @@ -0,0 +1,116 @@ > +#include > +#include > +#include > +#include > +#include > + > +#include > + > +#include "list.h" > + > +#include "hw.h" > +#include "xen.h" > + > +/* > + * tweaks needed to build with different xen versions > + * 0x00030205 -> 3.1.0 > + * 0x00030207 -> 3.2.0 > + * 0x00030208 -> unstable > + */ > +#include > +#if __XEN_LATEST_INTERFACE_VERSION__ < 0x00030207 > +# define xc_map_foreign_pages xc_map_foreign_batch > +#endif > +#if __XEN_LATEST_INTERFACE_VERSION__ < 0x00030208 > +# define xen_mb() mb() > +# define xen_rmb() rmb() > +# define xen_wmb() wmb() > +#endif > + > +/* ------------------------------------------------------------- */ > + > +#define container_of(ptr, type, member) ({ \ > + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ > + (type *)( (char *)__mptr - offsetof(type,member) );}) > + > +/* ------------------------------------------------------------- */ > + > +#define BUFSIZE 1024 > + > +struct xendev; > + > +/* driver uses grant tables -> open gntdev device (xendev->gnttabdev) */ > +#define DEVOPS_FLAG_NEED_GNTDEV 1 > +/* don't expect frontend doing correct state transitions (aka console quirk) */ > +#define DEVOPS_FLAG_IGNORE_STATE 2 > + > +struct devops { > + size_t size; > + uint32_t flags; > + void (*alloc)(struct xendev *xendev); > + int (*init)(struct xendev *xendev); > + int (*connect)(struct xendev *xendev); > + void (*event)(struct xendev *xendev); > + void (*disconnect)(struct xendev *xendev); > + int (*free)(struct xendev *xendev); > + void (*backend_changed)(struct xendev *xendev, const char *node); > + void (*frontend_changed)(struct xendev *xendev, const char *node); > +}; > + > +struct xendev { > + char *type; > + int dom; > + int dev; > + char name[64]; > + int debug; > + > + enum xenbus_state be_state; > + enum xenbus_state fe_state; > + int online; > + char be[BUFSIZE]; > + char *fe; > + char *protocol; > + int remote_port; > + int local_port; > + > + int evtchndev; > + int gnttabdev; > + > + struct devops *ops; > + struct list_head next; > +}; > + > +/* ------------------------------------------------------------- */ > + > +/* variables */ > +extern int xen_domid; /* set by cmd line option, in vl.c */ > +extern int xen_xc; > +extern struct xs_handle *xenstore; > + > +/* xenstore helper functions */ > +int xenstore_write_str(const char *base, const char *node, const char *val); > +int xenstore_write_int(const char *base, const char *node, int ival); > +char *xenstore_read_str(const char *base, const char *node); > +int xenstore_read_int(const char *base, const char *node, int *ival); > + > +int xenstore_write_be_str(struct xendev *xendev, const char *node, const char *val); > +int xenstore_write_be_int(struct xendev *xendev, const char *node, int ival); > +char *xenstore_read_be_str(struct xendev *xendev, const char *node); > +int xenstore_read_be_int(struct xendev *xendev, const char *node, int *ival); > +char *xenstore_read_fe_str(struct xendev *xendev, const char *node); > +int xenstore_read_fe_int(struct xendev *xendev, const char *node, int *ival); > + > +const char *xenbus_strstate(enum xenbus_state state); > +struct xendev *xen_be_find_xendev(char *type, int dom, int dev); > +void xen_be_check_state(struct xendev *xendev); > + > +/* xen backend driver bits */ > +int xen_be_init(void); > +int xen_be_register(char *type, struct devops *ops); > +int xen_be_set_state(struct xendev *xendev, enum xenbus_state state); > +int xen_be_bind_evtchn(struct xendev *xendev); > +void xen_be_unbind_evtchn(struct xendev *xendev); > +int xen_be_send_notify(struct xendev *xendev); > +void xen_be_printf(struct xendev *xendev, int msg_level, const char *fmt, ...) > + __attribute__ ((format(printf, 3, 4))); > + > diff --git a/hw/xen-machine.c b/hw/xen-machine.c > index 88f0f6e..798c0a7 100644 > --- a/hw/xen-machine.c > +++ b/hw/xen-machine.c > @@ -25,7 +25,7 @@ > #include "hw.h" > #include "boards.h" > > -#include "xen.h" > +#include "xen-backend.h" > > /* -------------------------------------------------------------------- */ > /* variables */ > @@ -54,6 +54,9 @@ static void xenpv_init(ram_addr_t ram_size, int vga_ram_size, > } > env = cpu_init(cpu_model); > env->halted = 1; > + > + /* setup xen backend handlers */ > + xen_be_init(); > } > > QEMUMachine xenpv_machine = { >