Blob Blame History Raw
diff -ruNp xen-3.1.0-src.orig/tools/ioemu/hw/oldxenfb.c xen-3.1.0-src.new/tools/ioemu/hw/oldxenfb.c
--- xen-3.1.0-src.orig/tools/ioemu/hw/oldxenfb.c	1969-12-31 19:00:00.000000000 -0500
+++ xen-3.1.0-src.new/tools/ioemu/hw/oldxenfb.c	2007-09-24 18:51:06.000000000 -0400
@@ -0,0 +1,610 @@
+#include <stdarg.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <xenctrl.h>
+#include <xen/io/xenbus.h>
+#include <xen/io/protocols.h>
+#include <sys/select.h>
+#include <stdbool.h>
+#include <xen/linux/evtchn.h>
+#include <xen/event_channel.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <xs.h>
+
+#include "xenfb.h"
+#include "oldxenfb.h"
+#include "oldxenkbd.h"
+
+// FIXME defend against malicious frontend?
+
+/* 
+ * NB our back-compat hack relies on these structs being the same size
+ * or smaller than the same named structs in xenfb.c, and having the
+ * same field offsets in both. Do not change this !
+ */
+struct xenfb_device {
+	const char *devicetype;
+	char nodename[64];	/* backend xenstore dir */
+	char otherend[64];	/* frontend xenstore dir */
+	int otherend_id;	/* frontend domid */
+	enum xenbus_state state; /* backend state */
+	void *page;		/* shared page */
+	evtchn_port_t port;
+	struct xenfb_private *xenfb;
+};
+
+struct xenfb_private {
+	struct xenfb pub;
+	int evt_xch;		/* event channel driver handle */
+	int xc;			/* hypervisor interface handle */
+	struct xs_handle *xsh;	/* xs daemon handle */
+	struct xenfb_device fb, kbd;
+	size_t fb_len;		/* size of framebuffer */
+	char protocol[64];	/* frontend protocol */
+};
+
+static void oldxenfb_detach_dom(struct xenfb_private *);
+static int oldxenfb_fb_event(struct xenfb_private *, union xenfb_in_event *);
+
+static char *oldxenfb_path_in_dom(struct xs_handle *xsh,
+				  char *buf, size_t size,
+				  unsigned domid, const char *fmt, ...)
+{
+	va_list ap;
+	char *domp = xs_get_domain_path(xsh, domid);
+	int n;
+
+        if (domp == NULL)
+		return NULL;
+
+	n = snprintf(buf, size, "%s/", domp);
+	free(domp);
+	if (n >= size)
+		return NULL;
+
+	va_start(ap, fmt);
+	n += vsnprintf(buf + n, size - n, fmt, ap);
+	va_end(ap);
+	if (n >= size)
+		return NULL;
+
+	return buf;
+}
+
+static int oldxenfb_xs_scanf1(struct xs_handle *xsh,
+			      const char *dir, const char *node,
+			      const char *fmt, void *dest)
+{
+	char buf[1024];
+	char *p;
+	int ret;
+
+	if (snprintf(buf, sizeof(buf), "%s/%s", dir, node) >= sizeof(buf)) {
+		errno = ENOENT;
+		return -1;
+        }
+	p = xs_read(xsh, XBT_NULL, buf, NULL);
+	if (!p) {
+		errno = ENOENT;
+		return -1;
+        }
+	ret = sscanf(p, fmt, dest);
+	free(p);
+	if (ret != 1) {
+		errno = EDOM;
+		return -1;
+        }
+	return ret;
+}
+
+static int oldxenfb_xs_printf(struct xs_handle *xsh,
+			      const char *dir, const char *node, char *fmt, ...)
+{
+	va_list ap;
+	char key[1024];
+	char val[1024];
+	int n;
+
+	if (snprintf(key, sizeof(key), "%s/%s", dir, node) >= sizeof(key)) {
+		errno = ENOENT;
+		return -1;
+        }
+
+	va_start(ap, fmt);
+	n = vsnprintf(val, sizeof(val), fmt, ap);
+	va_end(ap);
+	if (n >= sizeof(val)) {
+		errno = ENOSPC; /* close enough */
+		return -1;
+	}
+
+	if (!xs_write(xsh, XBT_NULL, key, val, n))
+		return -1;
+	return 0;
+}
+
+int oldxenfb_device_set_domain(struct xenfb_device *dev, int domid)
+{
+	struct xenfb_private *xenfb = dev->xenfb;
+
+	dev->otherend_id = domid;
+
+	if (!oldxenfb_path_in_dom(xenfb->xsh,
+				  dev->otherend, sizeof(dev->otherend),
+				  domid, "device/%s/0", dev->devicetype)) {
+		errno = ENOENT;
+		return -1;
+	}
+	if (!oldxenfb_path_in_dom(xenfb->xsh,
+				  dev->nodename, sizeof(dev->nodename),
+				  0, "backend/%s/%d/0", dev->devicetype, domid)) {
+		errno = ENOENT;
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static enum xenbus_state oldxenfb_read_state(struct xs_handle *xsh,
+					     const char *dir)
+{
+	int ret, state;
+
+	ret = oldxenfb_xs_scanf1(xsh, dir, "state", "%d", &state);
+	if (ret < 0)
+		return XenbusStateUnknown;
+
+	if ((unsigned)state > XenbusStateClosed)
+		state = XenbusStateUnknown;
+	return state;
+}
+
+static int oldxenfb_switch_state(struct xenfb_device *dev,
+				 enum xenbus_state state)
+{
+	struct xs_handle *xsh = dev->xenfb->xsh;
+
+	if (oldxenfb_xs_printf(xsh, dev->nodename, "state", "%d", state) < 0)
+		return -1;
+	dev->state = state;
+	return 0;
+}
+
+static void oldxenfb_copy_mfns(int mode, int count, unsigned long *dst, void *src)
+{
+	uint32_t *src32 = src;
+	uint64_t *src64 = src;
+	int i;
+
+	for (i = 0; i < count; i++)
+		dst[i] = (mode == 32) ? src32[i] : src64[i];
+}
+
+static int oldxenfb_map_fb(struct xenfb_private *xenfb, int domid)
+{
+	struct xenfb_page *page = xenfb->fb.page;
+	int n_fbmfns;
+	int n_fbdirs;
+	unsigned long *pgmfns = NULL;
+	unsigned long *fbmfns = NULL;
+	void *map;
+	int mode, ret = -1;
+
+	if (0 == strcmp(xenfb->protocol, XEN_IO_PROTO_ABI_NATIVE))
+	    mode = sizeof(unsigned long) * 8;
+	else if (0 == strcmp(xenfb->protocol, XEN_IO_PROTO_ABI_X86_32))
+	    mode = 32;
+	else if (0 == strcmp(xenfb->protocol, XEN_IO_PROTO_ABI_X86_64))
+	    mode = 64;
+	else
+	    return -1;
+
+	n_fbmfns = (xenfb->fb_len + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
+	n_fbdirs = n_fbmfns * mode / 8;
+	n_fbdirs = (n_fbdirs + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
+
+	pgmfns = malloc(sizeof(unsigned long) * n_fbdirs);
+	fbmfns = malloc(sizeof(unsigned long) * n_fbmfns);
+	if (!pgmfns || !fbmfns)
+		goto out;
+
+	/*
+	 * Bug alert: xc_map_foreign_batch() can fail partly and
+	 * return a non-null value.  This is a design flaw.  When it
+	 * happens, we happily continue here, and later crash on
+	 * access.
+	 */
+	oldxenfb_copy_mfns(mode, n_fbdirs, pgmfns, page->pd);
+	map = xc_map_foreign_batch(xenfb->xc, domid,
+				   PROT_READ, pgmfns, n_fbdirs);
+	if (map == NULL)
+		goto out;
+	oldxenfb_copy_mfns(mode, n_fbmfns, fbmfns, map);
+	munmap(map, n_fbdirs * XC_PAGE_SIZE);
+
+	xenfb->pub.pixels = xc_map_foreign_batch(xenfb->xc, domid,
+				PROT_READ | PROT_WRITE, fbmfns, n_fbmfns);
+	if (xenfb->pub.pixels == NULL) {
+		goto out;
+	}
+
+	ret = 0; /* all is fine */
+
+ out:
+	if (pgmfns)
+		free(pgmfns);
+	if (fbmfns)
+		free(fbmfns);
+	return ret;
+}
+
+static int oldxenfb_bind(struct xenfb_device *dev)
+{
+	struct xenfb_private *xenfb = dev->xenfb;
+	unsigned long mfn;
+	evtchn_port_t evtchn;
+	char buf[64];
+	char *p, **vec;
+	unsigned dummy;
+
+	p = oldxenfb_path_in_dom(xenfb->xsh, buf, sizeof(buf),
+				 dev->otherend_id, dev->devicetype);
+	if (!xs_watch(xenfb->xsh, p, ""))
+		return -1;
+	for (;;) {
+		if (oldxenfb_xs_scanf1(xenfb->xsh, p, "page-ref", "%lu",
+				       &mfn) < 0) {
+			if (errno == ENOENT || errno == EAGAIN)
+				goto wait;
+			return -1;
+		}
+		if (oldxenfb_xs_scanf1(xenfb->xsh, p, "event-channel", "%u",
+				       &evtchn) < 0) {
+			if (errno == ENOENT || errno == EAGAIN)
+				goto wait;
+			return -1;
+		}
+		break;
+
+	wait:
+		printf("Waiting...\n");
+		vec = xs_read_watch(xenfb->xsh, &dummy);
+		if (!vec)
+			return -1;
+		free(vec);
+	}
+
+	dev->port = xc_evtchn_bind_interdomain(xenfb->evt_xch,
+					       dev->otherend_id, evtchn);
+	if (dev->port == -1)
+		return -1;
+
+	dev->page = xc_map_foreign_range(xenfb->xc, dev->otherend_id,
+			XC_PAGE_SIZE, PROT_READ | PROT_WRITE, mfn);
+	if (dev->page == NULL)
+		return -1;
+
+	return 0;
+}
+
+static void oldxenfb_unbind(struct xenfb_device *dev)
+{
+	if (dev->page) {
+		munmap(dev->page, XC_PAGE_SIZE);
+		dev->page = NULL;
+	}
+        if (dev->port >= 0) {
+		xc_evtchn_unbind(dev->xenfb->evt_xch, dev->port);
+		dev->port = -1;
+	}
+}
+
+static void oldxenfb_dev_fatal(struct xenfb_device *dev, int err,
+			       const char *fmt, ...)
+{
+	struct xs_handle *xsh = dev->xenfb->xsh;
+	va_list ap;
+	char errdir[80];
+	char buf[1024];
+	int n;
+
+	fprintf(stderr, "%s ", dev->nodename); /* somewhat crude */
+	va_start(ap, fmt);
+	vfprintf(stderr, fmt, ap);
+	va_end(ap);
+	if (err)
+		fprintf(stderr, " (%s)", strerror(err));
+	putc('\n', stderr);
+
+	if (!oldxenfb_path_in_dom(xsh, errdir, sizeof(errdir), 0,
+				  "error/%s", dev->nodename))
+		goto out;	/* FIXME complain */
+
+	va_start(ap, fmt);
+	n = snprintf(buf, sizeof(buf), "%d ", err);
+	snprintf(buf + n, sizeof(buf) - n, fmt, ap);
+	va_end(ap);
+
+	if (oldxenfb_xs_printf(xsh, buf, "error", "%s", buf) < 0)
+		goto out;	/* FIXME complain */
+
+ out:
+	oldxenfb_switch_state(dev, XenbusStateClosing);
+}
+
+int oldxenfb_attach_dom(struct xenfb *xenfb_pub, int domid)
+{
+	struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
+	struct xs_handle *xsh = xenfb->xsh;
+	int serrno;
+	struct xenfb_page *fb_page;
+	union xenfb_in_event event;
+
+	if (oldxenfb_bind(&xenfb->fb) < 0)
+		goto error;
+	if (oldxenfb_bind(&xenfb->kbd) < 0)
+		goto error;
+
+	if (oldxenfb_xs_scanf1(xsh, xenfb->fb.otherend, "protocol", "%63s",
+			       xenfb->protocol) < 0)
+		xenfb->protocol[0] = '\0';
+
+	/* TODO check for permitted ranges */
+	fb_page = xenfb->fb.page;
+	xenfb->pub.depth = fb_page->depth;
+	xenfb->pub.width = fb_page->width;
+	xenfb->pub.height = fb_page->height;
+	/* TODO check for consistency with the above */
+	xenfb->fb_len = fb_page->mem_length;
+	xenfb->pub.row_stride = fb_page->line_length;
+
+	if (oldxenfb_map_fb(xenfb, domid) < 0)
+		goto error;
+
+	event.type = XENFB_TYPE_SET_EVENTS;
+	event.set_events.flags = XENFB_FLAG_UPDATE;
+	if (oldxenfb_fb_event(xenfb, &event))
+		goto error;
+
+	fprintf(stderr, "Old protocol attach complete\n");
+	return 0;
+
+ error:
+	fprintf(stderr, "Old protocol attach failed\n");
+	serrno = errno;
+	oldxenfb_detach_dom(xenfb);
+	oldxenfb_dev_fatal(&xenfb->fb, serrno, "on fire");
+	oldxenfb_dev_fatal(&xenfb->kbd, serrno, "on fire");
+        errno = serrno;
+        return -1;
+}
+
+static void oldxenfb_detach_dom(struct xenfb_private *xenfb)
+{
+	oldxenfb_unbind(&xenfb->fb);
+	oldxenfb_unbind(&xenfb->kbd);
+	if (xenfb->pub.pixels) {
+		munmap(xenfb->pub.pixels, xenfb->fb_len);
+		xenfb->pub.pixels = NULL;
+	}
+}
+
+static void oldxenfb_on_fb_event(struct xenfb_private *xenfb)
+{
+	uint32_t prod, cons;
+	struct xenfb_page *page = xenfb->fb.page;
+
+	prod = page->out_prod;
+	if (prod == page->out_cons)
+		return;
+	rmb();			/* ensure we see ring contents up to prod */
+	for (cons = page->out_cons; cons != prod; cons++) {
+		union xenfb_out_event *event = &XENFB_OUT_RING_REF(page, cons);
+
+		switch (event->type) {
+		case XENFB_TYPE_UPDATE:
+                    if (xenfb->pub.update)
+			xenfb->pub.update(&xenfb->pub,
+					  event->update.x, event->update.y,
+					  event->update.width, event->update.height);
+                    break;
+		}
+	}
+	mb();			/* ensure we're done with ring contents */
+	page->out_cons = cons;
+	xc_evtchn_notify(xenfb->evt_xch, xenfb->fb.port);
+}
+
+static void oldxenfb_on_kbd_event(struct xenfb_private *xenfb)
+{
+	struct xenkbd_info *page = xenfb->kbd.page;
+
+	/* We don't understand any keyboard events, so just ignore them. */
+	if (page->out_prod == page->out_cons)
+		return;
+	page->out_cons = page->out_prod;
+	xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd.port);
+}
+
+static int oldxenfb_on_state_change(struct xenfb_device *dev)
+{
+	enum xenbus_state state;
+
+	state = oldxenfb_read_state(dev->xenfb->xsh, dev->otherend);
+
+	switch (state) {
+	case XenbusStateUnknown:
+		/* There was an error reading the frontend state.  The
+		   domain has probably gone away; in any case, there's
+		   not much point in us continuing. */
+		return -1;
+	case XenbusStateInitialising:
+	case XenbusStateInitWait:
+	case XenbusStateInitialised:
+	case XenbusStateConnected:
+		break;
+	case XenbusStateClosing:
+		oldxenfb_unbind(dev);
+		oldxenfb_switch_state(dev, state);
+		break;
+	case XenbusStateClosed:
+		oldxenfb_switch_state(dev, state);
+	}
+	return 0;
+}
+
+
+int oldxenfb_dispatch_channel(struct xenfb *xenfb_pub)
+{
+	struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
+	evtchn_port_t port;
+	port = xc_evtchn_pending(xenfb->evt_xch);
+	if (port == -1)
+		return -1;
+
+	if (port == xenfb->fb.port)
+		oldxenfb_on_fb_event(xenfb);
+	else if (port == xenfb->kbd.port)
+		oldxenfb_on_kbd_event(xenfb);
+
+	if (xc_evtchn_unmask(xenfb->evt_xch, port) == -1)
+		return -1;
+
+	return 0;
+}
+
+int oldxenfb_dispatch_store(struct xenfb *xenfb_pub)
+{
+	struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
+	unsigned dummy;
+	char **vec;
+	int r;
+
+	vec = xs_read_watch(xenfb->xsh, &dummy);
+	free(vec);
+	r = oldxenfb_on_state_change(&xenfb->fb);
+	if (r == 0)
+		r = oldxenfb_on_state_change(&xenfb->kbd);
+	if (r == -1)
+		return -2;
+
+	return 0;
+}
+
+
+static int oldxenfb_fb_event(struct xenfb_private *xenfb,
+			     union xenfb_in_event *event)
+{
+	uint32_t prod;
+	struct xenfb_page *page = xenfb->fb.page;
+
+	prod = page->in_prod;
+	if (prod - page->in_cons == XENFB_IN_RING_LEN) {
+		errno = EAGAIN;
+		return -1;
+	}
+
+	mb();			/* ensure ring space available */
+	XENFB_IN_RING_REF(page, prod) = *event;
+	wmb();			/* ensure ring contents visible */
+	page->in_prod = prod + 1;
+	return xc_evtchn_notify(xenfb->evt_xch, xenfb->fb.port);
+}
+
+static int oldxenfb_kbd_event(struct xenfb_private *xenfb,
+			      union xenkbd_in_event *event)
+{
+	uint32_t prod;
+	struct xenkbd_info *page = xenfb->kbd.page;
+
+	prod = page->in_prod;
+	if (prod - page->in_cons == XENKBD_IN_RING_LEN) {
+		errno = EAGAIN;
+		return -1;
+	}
+
+	mb();			/* ensure ring space available */
+	XENKBD_IN_RING_REF(page, prod) = *event;
+	wmb();			/* ensure ring contents visible */
+	page->in_prod = prod + 1;
+	return xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd.port);
+}
+
+int oldxenfb_send_key(struct xenfb *xenfb_pub, bool down, int keycode)
+{
+	struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
+	union xenkbd_in_event event;
+
+	memset(&event, 0, XENKBD_IN_EVENT_SIZE);
+	event.type = XENKBD_TYPE_KEY;
+	event.key.pressed = down ? 1 : 0;
+	event.key.keycode = keycode;
+
+	return oldxenfb_kbd_event(xenfb, &event);
+}
+
+int oldxenfb_send_motion(struct xenfb *xenfb_pub, int rel_x, int rel_y)
+{
+	struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
+	union xenkbd_in_event event;
+
+	memset(&event, 0, XENKBD_IN_EVENT_SIZE);
+	event.type = XENKBD_TYPE_MOTION;
+	event.motion.rel_x = rel_x;
+	event.motion.rel_y = rel_y;
+
+	return oldxenfb_kbd_event(xenfb, &event);
+}
+
+
+int xenfb_using_old_protocol(struct xenfb *xenfb_pub)
+{
+	struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
+        struct xs_handle *xsh = xenfb->xsh;
+        char buf[64];
+        char *p, *v, **vec;
+        enum xenbus_state state;
+        unsigned dummy;
+        int ret;
+
+        p = oldxenfb_path_in_dom(xsh, buf, sizeof(buf),
+				 xenfb->fb.otherend_id, "vfb/page-ref");
+        if (!xs_watch(xsh, p, ""))
+                return -1;
+
+        for (;;) {
+                state = oldxenfb_read_state(xsh, xenfb->fb.otherend);
+                if (state == XenbusStateUnknown) {
+                        ret = -1;
+                        break;
+                }
+                if (state > XenbusStateInitialising) {
+                        ret = 0; /* frontend talks xenbus protocol */
+                        break;
+                }
+
+                v = xs_read(xsh, XBT_NULL, p, NULL);
+                free(v);
+                if (v) {
+                        ret = 1; /* frontend talks old protocol */
+                        break;
+                }
+
+                vec = xs_read_watch(xsh, &dummy);
+                if (!vec) {
+                        ret = -1;
+                        break;
+                }
+                free(vec);
+        }
+
+        xs_unwatch(xsh, p, "");
+        return ret;
+}
diff -ruNp xen-3.1.0-src.orig/tools/ioemu/hw/oldxenfb.h xen-3.1.0-src.new/tools/ioemu/hw/oldxenfb.h
--- xen-3.1.0-src.orig/tools/ioemu/hw/oldxenfb.h	1969-12-31 19:00:00.000000000 -0500
+++ xen-3.1.0-src.new/tools/ioemu/hw/oldxenfb.h	2007-09-24 18:50:44.000000000 -0400
@@ -0,0 +1,106 @@
+/*
+ * linux/include/linux/xenfb.h -- Xen virtual frame buffer device
+ *
+ * Copyright (C) 2005
+ *
+ *      Anthony Liguori <aliguori@us.ibm.com>
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License. See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+#ifndef _LINUX_XENFB_H
+#define _LINUX_XENFB_H
+
+#include <asm/types.h>
+
+/* out events */
+
+#define XENFB_OUT_EVENT_SIZE 40
+
+#define XENFB_TYPE_MOTION 1
+#define XENFB_TYPE_UPDATE 2
+
+struct xenfb_motion	    /* currently unused */
+{
+	__u8 type;          /* XENFB_TYPE_MOTION */
+	__u16 x;            /* The new x coordinate */
+	__u16 y;            /* The new y coordinate */
+};
+
+struct xenfb_update
+{
+	__u8 type;          /* XENFB_TYPE_UPDATE */
+	__u16 x;            /* source x */
+	__u16 y;            /* source y */
+	__u16 width;        /* rect width */
+	__u16 height;       /* rect height */
+};
+
+union xenfb_out_event
+{
+	__u8 type;
+	struct xenfb_motion motion;
+	struct xenfb_update update;
+	char _[XENFB_OUT_EVENT_SIZE];
+};
+
+/* in events */
+
+#define XENFB_IN_EVENT_SIZE 40
+
+#define XENFB_TYPE_SET_EVENTS 1
+
+#define XENFB_FLAG_MOTION 1
+#define XENFB_FLAG_UPDATE 2
+#define XENFB_FLAG_COPY 4
+#define XENFB_FLAG_FILL 8
+
+struct xenfb_set_events
+{
+	__u8 type;          /* XENFB_TYPE_SET_EVENTS */
+	__u32 flags;        /* combination of XENFB_FLAG_* */
+};
+
+union xenfb_in_event
+{
+	__u8 type;
+	struct xenfb_set_events set_events;
+	char _[XENFB_OUT_EVENT_SIZE];
+};
+
+/* shared page */
+
+#define XENFB_IN_RING_SIZE 1024
+#define XENFB_IN_RING_LEN (XENFB_IN_RING_SIZE / XENFB_IN_EVENT_SIZE)
+#define XENFB_IN_RING_OFFS 1024
+#define XENFB_IN_RING(page) \
+    ((union xenfb_in_event *)((char *)(page) + XENFB_IN_RING_OFFS))
+#define XENFB_IN_RING_REF(page, idx) \
+    (XENFB_IN_RING((page))[(idx) % XENFB_IN_RING_LEN])
+
+#define XENFB_OUT_RING_SIZE 2048
+#define XENFB_OUT_RING_LEN (XENFB_OUT_RING_SIZE / XENFB_OUT_EVENT_SIZE)
+#define XENFB_OUT_RING_OFFS (XENFB_IN_RING_OFFS + XENFB_IN_RING_SIZE)
+#define XENFB_OUT_RING(page) \
+    ((union xenfb_out_event *)((char *)(page) + XENFB_OUT_RING_OFFS))
+#define XENFB_OUT_RING_REF(page, idx) \
+    (XENFB_OUT_RING((page))[(idx) % XENFB_OUT_RING_LEN])
+
+struct xenfb_page
+{
+	__u16 width;         /* the width of the framebuffer (in pixels) */
+	__u16 height;        /* the height of the framebuffer (in pixels) */
+	__u32 line_length;   /* the length of a row of pixels (in bytes) */
+	__u32 mem_length;    /* the length of the framebuffer (in bytes) */
+	__u8 depth;          /* the depth of a pixel (in bits) */
+
+	unsigned long pd[2];	/* FIXME rename to pgdir? */
+	/* FIXME pd[1] unused at this time, shrink? */
+
+	__u32 in_cons, in_prod;
+	__u32 out_cons, out_prod;
+};
+
+#endif
diff -ruNp xen-3.1.0-src.orig/tools/ioemu/hw/oldxenkbd.h xen-3.1.0-src.new/tools/ioemu/hw/oldxenkbd.h
--- xen-3.1.0-src.orig/tools/ioemu/hw/oldxenkbd.h	1969-12-31 19:00:00.000000000 -0500
+++ xen-3.1.0-src.new/tools/ioemu/hw/oldxenkbd.h	2007-09-24 18:50:44.000000000 -0400
@@ -0,0 +1,92 @@
+/*
+ * linux/include/linux/xenkbd.h -- Xen virtual keyboard/mouse
+ *
+ * Copyright (C) 2005
+ *
+ *      Anthony Liguori <aliguori@us.ibm.com>
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License. See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+#ifndef _LINUX_XENKBD_H
+#define _LINUX_XENKBD_H
+
+#include <asm/types.h>
+
+/* in events */
+
+#define XENKBD_IN_EVENT_SIZE 40
+
+#define XENKBD_TYPE_MOTION  1     /* mouse movement event */
+#define XENKBD_TYPE_BUTTON  2     /* mouse button event */
+#define XENKBD_TYPE_KEY     3     /* keyboard event */
+
+struct xenkbd_motion
+{
+	__u8 type;         /* XENKBD_TYPE_MOTION */
+	__s16 rel_x;       /* relative X motion */
+	__s16 rel_y;       /* relative Y motion */
+};
+
+struct xenkbd_button
+{
+	__u8 type;         /* XENKBD_TYPE_BUTTON */
+	__u8 pressed;      /* 1 if pressed; 0 otherwise */
+	__u8 button;       /* the button (0, 1, 2 is right, middle, left) */
+};
+
+struct xenkbd_key
+{
+	__u8 type;         /* XENKBD_TYPE_KEY */
+	__u8 pressed;      /* 1 if pressed; 0 otherwise */
+	__u16 keycode;     /* KEY_* from linux/input.h */
+};
+
+union xenkbd_in_event
+{
+	__u8 type;
+	struct xenkbd_motion motion;
+	struct xenkbd_button button;
+	struct xenkbd_key key;
+	char _[XENKBD_IN_EVENT_SIZE];
+};
+
+/* out events */
+
+#define XENKBD_OUT_EVENT_SIZE 40
+
+union xenkbd_out_event
+{
+	__u8 type;
+	char _[XENKBD_OUT_EVENT_SIZE];
+};
+
+/* shared page */
+
+#define XENKBD_IN_RING_SIZE 2048
+#define XENKBD_IN_RING_LEN (XENKBD_IN_RING_SIZE / XENKBD_IN_EVENT_SIZE)
+#define XENKBD_IN_RING_OFFS 1024
+#define XENKBD_IN_RING(page) \
+    ((union xenkbd_in_event *)((char *)(page) + XENKBD_IN_RING_OFFS))
+#define XENKBD_IN_RING_REF(page, idx) \
+    (XENKBD_IN_RING((page))[(idx) % XENKBD_IN_RING_LEN])
+
+#define XENKBD_OUT_RING_SIZE 1024
+#define XENKBD_OUT_RING_LEN (XENKBD_OUT_RING_SIZE / XENKBD_OUT_EVENT_SIZE)
+#define XENKBD_OUT_RING_OFFS (XENKBD_IN_RING_OFFS + XENKBD_IN_RING_SIZE)
+#define XENKBD_OUT_RING(page) \
+    ((union xenkbd_out_event *)((char *)(page) + XENKBD_OUT_RING_OFFS))
+#define XENKBD_OUT_RING_REF(page, idx) \
+    (XENKBD_OUT_RING((page))[(idx) % XENKBD_OUT_RING_LEN])
+
+struct xenkbd_info
+{
+	__u32 in_cons, in_prod;
+	__u32 out_cons, out_prod;
+};
+
+void xenkbd_resume(void);
+
+#endif
diff -ruNp xen-3.1.0-src.orig/tools/ioemu/hw/xenfb.c xen-3.1.0-src.new/tools/ioemu/hw/xenfb.c
--- xen-3.1.0-src.orig/tools/ioemu/hw/xenfb.c	2007-09-24 18:42:25.000000000 -0400
+++ xen-3.1.0-src.new/tools/ioemu/hw/xenfb.c	2007-09-24 18:50:44.000000000 -0400
@@ -41,6 +41,7 @@ struct xenfb_private {
 	struct xenfb_device fb, kbd;
 	size_t fb_len;		/* size of framebuffer */
 	char protocol[64];	/* frontend protocol */
+	int oldprotocol;        /* Legacy FC6 compat */
 };
 
 static void xenfb_detach_dom(struct xenfb_private *);
@@ -545,6 +546,15 @@ int xenfb_attach_dom(struct xenfb *xenfb
 	if (!xs_watch(xsh, xenfb->kbd.otherend, ""))
 		goto error;
 
+	/* !!! FC-5/6 guest compatability - not upstream !!! */
+	if (xenfb_using_old_protocol(xenfb_pub)) {
+		fprintf(stderr, "Switching to old protocol\n");
+		xenfb->oldprotocol = 1;
+		return oldxenfb_attach_dom(xenfb_pub, domid);
+	} else {
+		fprintf(stderr, "Sticking to new protocol\n");
+	}
+
 	if (xenfb_wait_for_frontend_initialised(&xenfb->fb) < 0)
 		goto error;
 	if (xenfb_wait_for_frontend_initialised(&xenfb->kbd) < 0)
@@ -680,6 +690,10 @@ int xenfb_dispatch_channel(struct xenfb 
 {
 	struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
 	evtchn_port_t port;
+
+	if (xenfb->oldprotocol)
+		return oldxenfb_dispatch_channel(xenfb_pub);
+
 	port = xc_evtchn_pending(xenfb->evt_xch);
 	if (port == -1)
 		return -1;
@@ -702,6 +716,9 @@ int xenfb_dispatch_store(struct xenfb *x
 	char **vec;
 	int r;
 
+	if (xenfb->oldprotocol)
+		return oldxenfb_dispatch_store(xenfb_pub);
+
 	vec = xs_read_watch(xenfb->xsh, &dummy);
 	free(vec);
 	r = xenfb_on_state_change(&xenfb->fb);
@@ -783,6 +800,9 @@ int xenfb_send_key(struct xenfb *xenfb_p
 	struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
 	union xenkbd_in_event event;
 
+	if (xenfb->oldprotocol)
+		return oldxenfb_send_key(xenfb_pub, down, keycode);
+
 	memset(&event, 0, XENKBD_IN_EVENT_SIZE);
 	event.type = XENKBD_TYPE_KEY;
 	event.key.pressed = down ? 1 : 0;
@@ -796,6 +816,9 @@ int xenfb_send_motion(struct xenfb *xenf
 	struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
 	union xenkbd_in_event event;
 
+	if (xenfb->oldprotocol)
+		return oldxenfb_send_motion(xenfb_pub, rel_x, rel_y);
+
 	memset(&event, 0, XENKBD_IN_EVENT_SIZE);
 	event.type = XENKBD_TYPE_MOTION;
 	event.motion.rel_x = rel_x;
@@ -809,6 +832,9 @@ int xenfb_send_position(struct xenfb *xe
 	struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
 	union xenkbd_in_event event;
 
+	if (xenfb->oldprotocol)
+		return -1;
+
 	memset(&event, 0, XENKBD_IN_EVENT_SIZE);
 	event.type = XENKBD_TYPE_POS;
 	event.pos.abs_x = abs_x;
diff -ruNp xen-3.1.0-src.orig/tools/ioemu/hw/xenfb.h xen-3.1.0-src.new/tools/ioemu/hw/xenfb.h
--- xen-3.1.0-src.orig/tools/ioemu/hw/xenfb.h	2007-09-24 18:42:25.000000000 -0400
+++ xen-3.1.0-src.new/tools/ioemu/hw/xenfb.h	2007-09-24 18:50:44.000000000 -0400
@@ -36,4 +36,18 @@ int xenfb_send_key(struct xenfb *xenfb, 
 int xenfb_send_motion(struct xenfb *xenfb, int rel_x, int rel_y);
 int xenfb_send_position(struct xenfb *xenfb, int abs_x, int abs_y);
 
+/* Detect if using old FC5/6 guest protocol */
+int xenfb_using_old_protocol(struct xenfb *xenfb_pub);
+
+/* Pass-through legacy handlers */
+int oldxenfb_attach_dom(struct xenfb *xenfb, int domid);
+
+int oldxenfb_dispatch_store(struct xenfb *xenfb_pub);
+int oldxenfb_dispatch_channel(struct xenfb *xenfb_pub);
+
+int oldxenfb_send_key(struct xenfb *xenfb, bool down, int keycode);
+int oldxenfb_send_motion(struct xenfb *xenfb, int rel_x, int rel_y);
+int oldxenfb_send_position(struct xenfb *xenfb, int abs_x, int abs_y);
+
+
 #endif
diff -ruNp xen-3.1.0-src.orig/tools/ioemu/Makefile.target xen-3.1.0-src.new/tools/ioemu/Makefile.target
--- xen-3.1.0-src.orig/tools/ioemu/Makefile.target	2007-09-24 18:42:25.000000000 -0400
+++ xen-3.1.0-src.new/tools/ioemu/Makefile.target	2007-09-24 18:50:44.000000000 -0400
@@ -371,7 +371,7 @@ VL_OBJS+= xenstore.o
 VL_OBJS+= xen_platform.o
 VL_OBJS+= xen_machine_fv.o
 VL_OBJS+= xen_machine_pv.o
-VL_OBJS+= xenfb.o
+VL_OBJS+= xenfb.o oldxenfb.o
 VL_OBJS+= tpm_tis.o
 DEFINES += -DHAS_AUDIO
 endif
diff -ruNp xen-3.1.0-src.orig/tools/python/xen/xend/server/vfbif.py xen-3.1.0-src.new/tools/python/xen/xend/server/vfbif.py
--- xen-3.1.0-src.orig/tools/python/xen/xend/server/vfbif.py	2007-09-24 18:42:25.000000000 -0400
+++ xen-3.1.0-src.new/tools/python/xen/xend/server/vfbif.py	2007-09-24 18:50:44.000000000 -0400
@@ -50,7 +50,11 @@ class VfbifController(DevController):
         if self.vm.info.is_hvm():
             # is HVM, so qemu-dm will handle the vfb.
             return
-        
+
+        # old frontend compatibility
+        self.vm._writeDom("console/use_graphics", "1")
+        # /old
+
         args = [ xen.util.auxbin.pathTo("qemu-dm"),
                  "-M", "xenpv",
                  "-d", "%d" % self.vm.getDomid(),
diff -ruNp xen-3.1.0-src.orig/tools/python/xen/xend/XendConfig.py xen-3.1.0-src.new/tools/python/xen/xend/XendConfig.py
--- xen-3.1.0-src.orig/tools/python/xen/xend/XendConfig.py	2007-05-18 10:45:21.000000000 -0400
+++ xen-3.1.0-src.new/tools/python/xen/xend/XendConfig.py	2007-09-24 18:50:44.000000000 -0400
@@ -689,7 +689,7 @@ class XendConfig(dict):
         self['vtpm_refs'] = cfg.get('vtpm_refs', [])
 
         # coalesce hvm vnc frame buffer with vfb config
-        if self.is_hvm() and int(self['platform'].get('vnc', 0)) != 0:
+        if int(self['platform'].get('vnc', 0)) != 0:
             # add vfb device if it isn't there already
             has_rfb = False
             for console_uuid in self['console_refs']:
@@ -704,7 +704,7 @@ class XendConfig(dict):
                 dev_config = ['vfb']
                 # copy VNC related params from platform config to vfb dev conf
                 for key in ['vncpasswd', 'vncunused', 'vncdisplay',
-                            'vnclisten']:
+                            'vnclisten', 'keymap']:
                     if key in self['platform']:
                         dev_config.append([key, self['platform'][key]])
 
diff -ruNp xen-3.1.0-src.orig/tools/python/xen/xm/create.py xen-3.1.0-src.new/tools/python/xen/xm/create.py
--- xen-3.1.0-src.orig/tools/python/xen/xm/create.py	2007-05-18 10:45:21.000000000 -0400
+++ xen-3.1.0-src.new/tools/python/xen/xm/create.py	2007-09-24 18:50:44.000000000 -0400
@@ -610,7 +610,7 @@ def configure_vfbs(config_devs, vals):
             d['type'] = 'sdl'
         for (k,v) in d.iteritems():
             if not k in [ 'vnclisten', 'vncunused', 'vncdisplay', 'display',
-                          'xauthority', 'type', 'vncpasswd' ]:
+                          'xauthority', 'type', 'vncpasswd', 'keymap' ]:
                 err("configuration option %s unknown to vfbs" % k)
             config.append([k,v])
         if not d.has_key("keymap"):