[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] Re: [Qemu-devel] [PATCH 2/7] xen: backend driver core
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 <kraxel@xxxxxxxxxx> --- 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 <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <inttypes.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <sys/signal.h> + +#include <xs.h> +#include <xenctrl.h> +#include <xen/grant_table.h> + +#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 <stddef.h> +#include <xs.h> +#include <xenctrl.h> +#include <xen/elfnote.h> +#include <xen/elfstructs.h> + +#include <xen/io/xenbus.h> + +#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 <xen/xen-compat.h> +#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 = { _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |