WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-devel

Re: [Xen-devel] [PATCH] Paravirt framebuffer backend tools [2/5]

To: Steven Smith <sos22-xen@xxxxxxxxxxxxx>
Subject: Re: [Xen-devel] [PATCH] Paravirt framebuffer backend tools [2/5]
From: Markus Armbruster <armbru@xxxxxxxxxx>
Date: Sat, 30 Sep 2006 10:51:57 +0200
Cc: aliguori <aliguori@xxxxxxxxxxxxxxx>, Jeremy Katz <katzj@xxxxxxxxxx>, xen-devel <xen-devel@xxxxxxxxxxxxxxxxxxx>, sos22@xxxxxxxxxxxxx
Delivery-date: Sat, 30 Sep 2006 01:52:28 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
In-reply-to: <20060904090150.GC4812@xxxxxxxxx> (Steven Smith's message of "Mon, 4 Sep 2006 10:01:51 +0100")
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
References: <20060904090150.GC4812@xxxxxxxxx>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
User-agent: Gnus/5.1008 (Gnus v5.10.8) Emacs/21.4 (gnu/linux)
Steven Smith <sos22-xen@xxxxxxxxxxxxx> writes:

>> --- a/tools/Makefile Sat Sep 02 15:11:17 2006 -0400
>> +++ b/tools/Makefile Sat Sep 02 15:19:25 2006 -0400
>> @@ -18,6 +18,7 @@ SUBDIRS-y += xenstat
>>  SUBDIRS-y += xenstat
>>  SUBDIRS-y += libaio
>>  SUBDIRS-y += blktap
>> +SUBDIRS-y += xenfb
>>  
>>  # These don't cross-compile
>>  ifeq ($(XEN_COMPILE_ARCH),$(XEN_TARGET_ARCH))
>> --- /dev/null        Thu Jan 01 00:00:00 1970 +0000
>> +++ b/tools/xenfb/Makefile   Sat Sep 02 15:19:25 2006 -0400
>> @@ -0,0 +1,36 @@
>> +XEN_ROOT=../..
>> +include $(XEN_ROOT)/tools/Rules.mk
>> +
>> +CFLAGS += -g -Wall
> You shouldn't need to add -g here; Rules.mk handles it for you if
> debug is set.

Jeremy took care of this.

>> +CFLAGS += -I$(XEN_LIBXC) -I$(XEN_XENSTORE) 
>> -I$(XEN_ROOT)/linux-2.6-xen-sparse/include
>> +LDFLAGS += -L$(XEN_LIBXC) -L$(XEN_XENSTORE)
>> +
>> +INSTALL         = install
>> +INSTALL_PROG    = $(INSTALL) -m0755
>> +INSTALL_DIR     = $(INSTALL) -d -m0755
>> +
>> +.PHONY: all
>> +all: build
>> +
>> +.PHONY: build
>> +build: mk-symlinks
>> +    $(MAKE) vncfb sdlfb
>> +
>> +install: all
>> +    $(INSTALL_DIR) -p $(DESTDIR)/usr/$(LIBDIR)/xen/bin
>> +    $(INSTALL_PROG) vncfb $(DESTDIR)/usr/$(LIBDIR)/xen/bin/xen-vncfb
>> +    $(INSTALL_PROG) sdlfb $(DESTDIR)/usr/$(LIBDIR)/xen/bin/xen-sdlfb
>> +
>> +sdlfb: sdlfb.o xenfb.o
>> +
>> +sdlfb.o: CFLAGS += $(shell sdl-config --cflags)
>> +sdlfb: LDLIBS += $(shell sdl-config --libs) -lxenctrl -lxenstore
>> +
>> +clean:
>> +    $(RM) *.o *~ vncfb sdlfb
>> +
>> +keymapping.o: CFLAGS += $(shell pkg-config --cflags gtk+-2.0)
>> +
>> +vncfb: vncfb.o xenfb.o keymapping.o
>> +vncfb.o: CFLAGS += $(shell libvncserver-config --cflags)
>> +vncfb: LDLIBS += $(shell libvncserver-config --libs) -lxenctrl -lxenstore
>> --- /dev/null        Thu Jan 01 00:00:00 1970 +0000
>> +++ b/tools/xenfb/keymapping.c       Sat Sep 02 15:19:25 2006 -0400
>> @@ -0,0 +1,141 @@
>> +#include <stdint.h>
>> +#include <gdk/gdkkeysyms.h>
>> +#include <linux/input.h>
>> +
>> +uint32_t gdk_linux_mapping[0x10000] = {
>> +    [GDK_a] = KEY_A,
> This is kind of ugly.  Is there any chance it could be autogenerated?
> Also, where did 0x10000 come from?
>
> Also, depending on GTK just for the keymap table is a real pain.  Or
> is it already required for libvncserver?

Jeremy answered this one.

There was quite a bit of discussion on how to best encode keys (thanks
to Laurent for patiently explaining the issue).  I'm *not* ignoring
that problem.  However, the patch is large enough as it is, so let's
get the things it addresses nailed down before we address the key code
problem.

> <snip>
>
>> +    [GDK_plus] = KEY_EQUAL,
>> +};
>> +
>> --- /dev/null        Thu Jan 01 00:00:00 1970 +0000
>> +++ b/tools/xenfb/sdlfb.c    Sat Sep 02 15:19:25 2006 -0400
>> @@ -0,0 +1,191 @@
>> +#include <SDL.h>
>> +#include <sys/types.h>
>> +#include <sys/select.h>
>> +#include <stdlib.h>
>> +#include <linux/input.h>
>> +#include <getopt.h>
>> +#include <string.h>
>> +#include "xenfb.h"
>> +
>> +struct data
> That's a really wonderful name.

Jeremy took care of this.

>> +{
>> +    SDL_Surface *dst;
>> +    SDL_Surface *src;
>> +};
>> +
>> +void sdl_update(struct xenfb *xenfb, int x, int y, int width, int height)
>> +{
>> +    struct data *data = xenfb->user_data;
>> +    SDL_Rect r = { x, y, width, height };
>> +    SDL_BlitSurface(data->src, &r, data->dst, &r);
>> +    SDL_UpdateRect(data->dst, x, y, width, height);
>> +}
>> +
>> +int sdl2linux[1024] = {
>> +    [SDLK_a] = KEY_A,
> Another really ugly mapping table, although not quite as bad as the
> GTK one.
>
> Where'd the magic 1024 come from?

Jeremy answered this one.

>> +    [SDLK_RALT] = KEY_RIGHTALT,
>> +};
>> +
>> +static struct option options[] = {
>> +    { "domid", 1, NULL, 'd' },
>> +    { "title", 1, NULL, 't' },
>> +};
>> +
>> +int main(int argc, char **argv)
>> +{
>> +    struct xenfb *xenfb;
>> +    int fd;
>> +    int domid = -1;
>> +        char * title = NULL;
>> +    fd_set readfds;
>> +    struct data data;
>> +    SDL_Rect r;
>> +    struct timeval tv = { 0, 500 };
>> +    int do_quit = 0;
>> +        int opt;
> Slightly strange whitespace, but nevermind.

Fixed anyway.

>> +
>> +    while ((opt = getopt_long(argc, argv, "d:t:", options,
>> +                              NULL)) != -1) {
>> +            switch (opt) {
>> +                case 'd':
>> +                    domid = strtol(optarg, NULL, 10);
> It'd be nice to check for a malformed argument here.

Done.

>> +                    break;
>> +                case 't':
>> +                    title = strdup(optarg);
> This can fail.

Jeremy answered this one.

>> +                    break;
>> +                }
>> +        }
>> +        if (optind != argc) {
>> +            fprintf(stderr, "Invalid options!\n");
>> +            exit(1);
> errx() maybe?

Jeremy answered this one.

>> +        }
>> +        if (domid == -1) {
>> +            fprintf(stderr, "Domain ID must be specified!\n");
>> +            exit(1);
>> +        }
>> +
>> +    xenfb = xenfb_new();
>> +    if (xenfb == NULL)
>> +            return 1;
> Why have you used exit(1) in some places and return 1 in others?

It's all exit(1) now.

> Also, an error message here would be a good idea.

Done.

>> +
>> +    if (!xenfb_attach_dom(xenfb, domid))
>> +            return 1;
> An error mesasge would be good.

Done.

>> +
>> +    SDL_Init(SDL_INIT_VIDEO);
>> +
>> +    fd = xenfb_get_fileno(xenfb);
>> +
>> +    data.dst = SDL_SetVideoMode(xenfb->width, xenfb->height, xenfb->depth,
>> +                                SDL_SWSURFACE);
>> +
>> +    data.src = SDL_CreateRGBSurfaceFrom(xenfb->pixels,
>> +                                        xenfb->width, xenfb->height,
>> +                                        xenfb->depth, xenfb->row_stride,
>> +                                        0xFF0000, 0xFF00, 0xFF, 0);
>> +
>> +        if (title == NULL)
>> +            title = strdup("xen-sdlfb");
> This can fail.

Jeremy answered this one.

>> +        SDL_WM_SetCaption(title, title);
>> +
>> +    r.x = r.y = 0;
>> +    r.w = xenfb->width;
>> +    r.h = xenfb->height;
>> +    SDL_BlitSurface(data.src, &r, data.dst, &r);
>> +    SDL_UpdateRect(data.dst, 0, 0, xenfb->width, xenfb->height);
>> +
>> +    xenfb->update = sdl_update;
>> +    xenfb->user_data = &data;
>> +
>> +    FD_ZERO(&readfds);
>> +    FD_SET(fd, &readfds);
>> +
>> +    SDL_ShowCursor(0);
>> +
>> +    while (!do_quit && select(fd + 1, &readfds, NULL, NULL, &tv) != -1) {
> Select can say -1 because of EINTR (e.g. when strace attaches).  It's
> not clear to me whether you want to exit or retry in that case.
>
> Also, if you quit because select returns -1, you need an error
> message.

Reworked the loop.

>> +            SDL_Event event;
>> +
>> +            while (SDL_PollEvent(&event)) {
>> +                    switch (event.type) {
>> +                    case SDL_KEYDOWN:
>> +                    case SDL_KEYUP:
>> +                            xenfb_send_key(xenfb,
>> +                                           event.type == SDL_KEYDOWN,
>> +                                           sdl2linux[event.key.keysym.sym]);
>> +                            break;
>> +                    case SDL_MOUSEMOTION: {
>> +                            int x, y;
>> +                            Uint8 button;
>> +
>> +                            button = SDL_GetRelativeMouseState(&x, &y);
>> +                            xenfb_send_motion(xenfb, x, y);
>> +                    }       break;
>> +                    case SDL_MOUSEBUTTONDOWN:
>> +                    case SDL_MOUSEBUTTONUP:
>> +                            xenfb_send_button(xenfb,
>> +                                              
>> event.type==SDL_MOUSEBUTTONDOWN,
>> +                                              3 - event.button.button);
>> +                            break;
>> +                    case SDL_QUIT:
>> +                            do_quit = 1;
>> +                            break;
>> +                    }
>> +            }
>> +            if (FD_ISSET(fd, &readfds))
>> +                    xenfb_on_incoming(xenfb);
>> +
>> +            FD_ZERO(&readfds);
>> +            FD_SET(fd, &readfds);
>> +
>> +            tv = (struct timeval){0, 500};
> I think 500us is a little short here.  About ten milliseconds sounds
> more plausible.  This is a bit of a bikeshed.

Changed to 10ms.

> It's a pity SDL doesn't allow you to wait for either an SDL event or
> an fd to become readable.  Could you do something like spawn a thread
> which does the selects in a loop, and then SDL_PushEvent()s a user
> event when the fd becomes readable?
>
> Admittedly, SDL_WaitEvent also contains this kind of loop-with-sleep,
> but it'd reduce the number of magic tunables a bit.

Added a comment explaining the clunkiness and sketching the solution
you proposed.

>> +    }
>> +
>> +    xenfb_delete(xenfb);
>> +
>> +    SDL_Quit();
>> +
>> +    return 0;
>> +}
>> --- b/tools/xenfb/vncfb.c    Sat Sep 02 15:19:25 2006 -0400
>> +++ b/tools/xenfb/vncfb.c    Sat Sep 02 15:22:19 2006 -0400
>
> Minor nit: generally, putting a vnc_ prefix on these functions
> confused me, since it looks like they should be in libvncserver.  This
> may just be because I'm not paying enough attention.
>
>> @@ -0,0 +1,245 @@
>> +#define _GNU_SOURCE
>> +#include <errno.h>
>> +#include <getopt.h>
>> +#include <stdlib.h>
>> +#include <unistd.h>
>> +#include <malloc.h>
>> +#include <rfb/rfb.h>
>> +#include <xs.h>
>> +#include "xenfb.h"
>> +
>> +static void on_kbd_event(rfbBool down, rfbKeySym keycode, rfbClientPtr cl)
>> +{
>> +    extern uint32_t gdk_linux_mapping[0x10000];
> Is there any chance of moving this into a header file somewhere?

I moved the table into this file instead.

>> +    rfbScreenInfoPtr server = cl->screen;
>> +    struct xenfb *xenfb = server->screenData;
>> +    xenfb_send_key(xenfb, down, gdk_linux_mapping[keycode & 0xFFFF]);
>> +}
>> +
>> +static void on_ptr_event(int buttonMask, int x, int y, rfbClientPtr cl)
>> +{
>> +    static int last_x = -1, last_y = -1;
>> +    static int last_button = -1;
>> +    rfbScreenInfoPtr server = cl->screen;
>> +    struct xenfb *xenfb = server->screenData;
>> +
>> +    if (last_button != -1) {
>> +            int i;
>> +
>> +            for (i = 0; i < 8; i++) {
>> +                    if ((last_button & (1 << i)) !=
>> +                        (buttonMask & (1 << i))) {
>> +                            printf("%d %d\n", buttonMask & (1 << i), i);
> Umm?

Anthony's debug code.  Gone.

>> +                            xenfb_send_button(xenfb, buttonMask & (1 << i),
>> +                                              2 - i);
>> +                    }
>> +            }
>> +    }
>> +
>> +    if (last_x != -1)
>> +            xenfb_send_motion(xenfb, x - last_x, y - last_y);
>> +
>> +    last_button = buttonMask;
>> +
>> +    last_x = x;
>> +    last_y = y;
>> +}
>> +
>> +static void xenstore_write_vncport(int port, int domid)
>> +{
>> +    char *buf = NULL, *path;
>> +    char *portstr = NULL;
>> +    struct xs_handle *xsh = NULL;
>> +
>> +    xsh = xs_daemon_open();
>> +    if (xsh == NULL)
>> +    return;
>> +
>> +    path = xs_get_domain_path(xsh, domid);
>> +    if (path == NULL) {
>> +        fprintf(stderr, "xs_get_domain_path() error\n");
>> +        goto out;
>> +    }
>> +
>> +    buf = malloc(256);
> Could fail.  Also, consider using asprintf.

Jeremy took care of this.

>> +    if (snprintf(buf, 256, "%s/console/vnc-port", path) == -1)
>> +    goto out;
>> +
>> +    portstr = malloc(10);
> Why is this on the heap rather than the stack?

Jeremy took care of this.

>> +    if (snprintf(portstr, 10, "%d", port) == -1)
>> +    goto out;
>> +
>> +    if (xs_write(xsh, XBT_NULL, buf, portstr, strlen(portstr)) == 0)
>> +        fprintf(stderr, "xs_write() vncport failed\n");
>> +
>> + out:
>> +    free(portstr);
>> +    free(buf);
>> +}
>> +
>> +
>> +static void vnc_update(struct xenfb *xenfb, int x, int y, int w, int h)
>> +{
>> +    rfbScreenInfoPtr server = xenfb->user_data;
>> +    rfbMarkRectAsModified(server, x, y, x + w, y + h);
>> +}
>> +
>> +static int vnc_start_viewer(int port) 
> I'm not convinced the backend server process is the best place to
> start the viewer from.  Perhaps xend would be a better choice?  Not
> sure about this.

Jeremy answered this one.

>> +{
>> +    int pid;
>> +    char s[16];
>> +
>> +    snprintf(s, 16, ":%d", port);
>> +    switch (pid = fork()) {
>> +    case -1:
>> +    fprintf(stderr, "vncviewer failed fork\n");
>> +    exit(1);
> err()?
>
>> +
>> +    case 0: /* child */
>> +    execlp("vncviewer", "vncviewer", s, 0);
>> +    fprintf(stderr, "vncviewer execlp failed\n");
>> +    exit(1);
> err()?
>
>> +
>> +    default:
>> +    return pid;
> This is ignored.  Also, the parent process makes no attempt to check
> whether the child was exec()ed successfully or anything along those
> lines.  This is enough of a pain to fix that I'd probably just ignore
> it, though.

Agreed.

>> +    }
>> +}
>> +
>> +static struct option options[] = {
>> +    { "domid", 1, NULL, 'd' },
>> +    { "vncport", 1, NULL, 'p' },
>> +    { "title", 1, NULL, 't' },
>> +    { "unused", 0, NULL, 'u' },
> What does this do?

Jeremy?

>> +    { "listen", 1, NULL, 'l' },
>> +    { "vncviewer", 0, NULL, 'v' },
>> +};
>> +
>> +int main(int argc, char **argv)
>> +{
>> +    rfbScreenInfoPtr server;
>> +    char *fake_argv[7] = { "vncfb", "-rfbport", "5901", 
>> +                               "-desktop", "xen-vncfb", 
>> +                               "-listen", "0.0.0.0" };
>> +    int fake_argc = sizeof(fake_argv) / sizeof(fake_argv[0]);
>> +    int domid = -1, port = -1;
>> +        char * title = NULL;
>> +        char * listen = NULL;
> Whitespace is a bit funny again.

Fixed.

>> +    struct xenfb *xenfb;
>> +    fd_set readfds;
>> +    int fd;
>> +    char buffer[1024];
> Could do with a better name, and is larger than it needs to be.

Jeremy took care of this.

>> +        int opt;
>> +        bool unused = FALSE;
> You're inconsistent about the capitalisation of bools.

Jeremy took care of this.

>> +        bool viewer = FALSE;
>> +
>> +    while ((opt = getopt_long(argc, argv, "d:p:t:u", options,
>> +                              NULL)) != -1) {
>> +            switch (opt) {
>> +                case 'd':
>> +                    domid = strtol(optarg, NULL, 10);
> It would be nice to sanity check the argument here.

Done.

>> +                    break;
>> +                case 'p':
>> +                    port = strtol(optarg, NULL, 10);
> Again.

Done.

>> +                    break;
>> +                case 't':
>> +                    title = strdup(optarg);
> Can fail.
>
>> +                    break;
>> +                case 'u':
>> +                    unused = TRUE;
>> +                    break;
>> +                case 'l':
>> +                    listen = strdup(optarg);
> Can fail.
>
>> +                    break;
>> +                case 'v':
>> +                    viewer = TRUE;
>> +                    break;
>> +                case 'l':
>> +                    listen = strdup(optarg);
> Can fail.
>
>> +                    break;
>> +                }
>> +        }
>> +        if (optind != argc) {
>> +            fprintf(stderr, "Invalid options!\n");
>> +            exit(1);
>> +        }
>> +        if (domid == -1) {
>> +            fprintf(stderr, "Domain ID must be specified!\n");
>> +            exit(1);
>> +        }
>> +            
>> +        if (port == -1)
>> +            port = 5900 + domid;
>> +    snprintf(buffer, sizeof(buffer), "%d", port);
>> +    fake_argv[2] = buffer;
>> +
>> +        if (title != NULL)
>> +            fake_argv[4] = title;
>> +
>> +        if (listen != NULL)
>> +            fake_argv[6] = listen;
>> +
>> +        if (listen != NULL)
>> +            fake_argv[6] = listen;
> Umm... What's going on here?

Jeremy took care of this.

>> +
>> +    xenfb = xenfb_new();
>> +    if (xenfb == NULL) {
>> +            fprintf(stderr, "Could not create framebuffer (%s)\n",
>> +                    strerror(errno));
>> +            exit(1);
>> +    }
>> +
>> +    if (!xenfb_attach_dom(xenfb, domid)) {
>> +            fprintf(stderr, "Could not connect to domain (%s)\n",
>> +                    strerror(errno));
>> +            exit(1);
>> +    }
>> +
>> +    server = rfbGetScreen(&fake_argc, fake_argv, 
>> +                          xenfb->width, xenfb->height,
>> +                          8, 3, xenfb->depth / 8);
>> +    if (server == NULL) {
>> +            fprintf(stderr, "Could not create VNC server\n");
>> +            exit(1);
>> +    }
>> +
>> +    xenfb->user_data = server;
>> +    xenfb->update = vnc_update;
>> +
>> +        if (unused)
>> +            server->autoPort = TRUE;
>> +
>> +    server->serverFormat.redShift = 16;
>> +    server->serverFormat.greenShift = 8;
>> +    server->serverFormat.blueShift = 0;
>> +    server->kbdAddEvent = on_kbd_event;
>> +    server->ptrAddEvent = on_ptr_event;
>> +    server->frameBuffer = (char *)xenfb->pixels;
>> +    server->screenData = xenfb;
>> +    rfbInitServer(server);
>> +
>> +    rfbRunEventLoop(server, -1, TRUE);
>> +
>> +    fd = xenfb_get_fileno(xenfb);
>> +
>> +    FD_ZERO(&readfds);
>> +    FD_SET(fd, &readfds);
>> +
>> +        xenstore_write_vncport(server->port, domid);
>> +
>> +        if (viewer)
>> +            vnc_start_viewer(server->port);
>> +
>> +    while (select(fd + 1, &readfds, NULL, NULL, NULL) != -1) {
>> +            if (FD_ISSET(fd, &readfds)) {
>> +                    xenfb_on_incoming(xenfb);
>> +            }
>> +            
>> +            FD_ZERO(&readfds);
>> +            FD_SET(fd, &readfds);
>> +    }
>> +
>> +    rfbScreenCleanup(server);
>> +    xenfb_delete(xenfb);
>> +
>> +    return 0;
>> +}
>> --- /dev/null        Thu Jan 01 00:00:00 1970 +0000
>> +++ b/tools/xenfb/xenfb.c    Sat Sep 02 15:19:25 2006 -0400
>> @@ -0,0 +1,434 @@
>> +#include <malloc.h>
>> +#include <stdlib.h>
>> +#include <sys/types.h>
>> +#include <fcntl.h>
>> +#include <unistd.h>
>> +#include <xenctrl.h>
>> +#include <linux/xenfb.h>
>> +#include <linux/xenkbd.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"
>> +
>> +// FIXME defend against malicous backend?
> Well, this is the backend, so defending against a malicious frontend
> would be a better choice.

Thanks.

>> +
>> +struct xenfb_private
>> +{
>> +    struct xenfb pub;
>> +    int domid;
>> +    unsigned long fbdev_mfn, kbd_mfn;
>> +    int fbdev_evtchn, kbd_evtchn;
>> +    evtchn_port_t fbdev_port, kbd_port;
> How do {fbdev,kbd}_port differ from {fbdev,kbd}_evtchn?

Jeremy answered this one.

> The _evtchn fields are only ever accessed from xenfb_attach_dom.  Could
> they be locals to that function?

Done.

>> +    int evt_xch;
>> +    int xc;
>> +    unsigned char *fb;
>> +    struct xenfb_page *fb_info;
>> +    struct xenkbd_info *kbd_info;
>> +    unsigned long *fbmfns;
>> +    int n_fbmfns, n_fbdirs;
>> +};
>> +
>> +struct xenfb *xenfb_new(void)
>> +{
>> +    struct xenfb_private *xenfb = malloc(sizeof(*xenfb));
>> +
>> +    if (xenfb == NULL)
>> +            return NULL;
>> +
>> +    memset(xenfb, 0, sizeof(*xenfb));
> Use calloc instead of malloc, perhaps?

Hate it.

>> +
>> +    xenfb->domid = -1;
>> +
>> +    xenfb->evt_xch = xc_evtchn_open();
>> +    if (xenfb->evt_xch == -1) {
>> +            int serrno = errno;
>> +            free(xenfb);
>> +            errno = serrno;
>> +            return NULL;
>> +    }
>> +
>> +    xenfb->xc = xc_interface_open();
>> +    if (xenfb->xc == -1) {
>> +            int serrno = errno;
>> +            xc_evtchn_close(xenfb->evt_xch);
>> +            free(xenfb);
>> +            errno = serrno;
>> +            return NULL;
> It's a pity we don't have a macro which hides this ugliness.  Perhaps
>
> #define PRESERVING_ERRNO(x) do {
>       int tmp = errno;
>       x;
>       errno = tmp;
> } while (0)
>
> You could then do something like
>
> if (xenfb_evt_sch == -1) {
>       PRESERVING_ERRNO(xc_evtchn_close(xenfb->evt_xch);free(xenfb));
>       return NULL;
> }
>
> Not sure whether that's more or less ugly, to be honest.

I think I prefer my poison straight here, without macro wrapping :)

>> +    }
>> +
>> +    return &xenfb->pub;
>> +}
>> +
>> +int xenfb_get_fileno(struct xenfb *xenfb_pub)
>> +{
>> +    struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
>> +
>> +    return xc_evtchn_fd(xenfb->evt_xch);
>> +}
>> +
>> +static void xenfb_detach_dom(struct xenfb_private *xenfb)
>> +{
>> +    xenfb->domid = -1;
>> +    munmap(xenfb->fb, xenfb->fb_info->mem_length);
>> +    munmap(xenfb->fb_info, XC_PAGE_SIZE);
>> +    munmap(xenfb->kbd_info, XC_PAGE_SIZE);
>> +    xc_evtchn_unbind(xenfb->evt_xch, xenfb->fbdev_port);
>> +    xc_evtchn_unbind(xenfb->evt_xch, xenfb->kbd_port);
>> +}
>> +
>> +void xenfb_delete(struct xenfb *xenfb_pub)
>> +{
>> +    struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
>> +    if (xenfb->domid != -1)
>> +            xenfb_detach_dom(xenfb);
>> +    free(xenfb);
>> +}
>> +
>> +static int xenfb_fb_event(struct xenfb_private *xenfb, union xenfb_in_event 
>> *event)
>> +{
>> +    uint32_t prod;
>> +    struct xenfb_page *info = xenfb->fb_info;
>> +
>> +    prod = info->in_prod;
>> +    if (prod - info->in_cons == XENFB_IN_RING_LEN) {
>> +        errno = EAGAIN;
>> +        return -1;
>> +    }
>> +
>> +    mb();                   /* ensure ring space available */
>> +    XENFB_IN_RING_REF(info, prod) = *event;
>> +    wmb();                  /* ensure ring contents visible */
>> +    info->in_prod = prod + 1;
>> +    return xc_evtchn_notify(xenfb->evt_xch, xenfb->fbdev_port);
>> +}
>> +
>> +static int xenfb_kbd_event(struct xenfb_private *xenfb, union 
>> xenkbd_in_event *event)
>> +{
>> +    uint32_t prod;
>> +    struct xenkbd_info *info = xenfb->kbd_info;
>> +
>> +    prod = info->in_prod;
>> +    if (prod - info->in_cons == XENKBD_IN_RING_LEN) {
>> +        errno = EAGAIN;
>> +        return -1;
>> +    }
>> +
>> +    mb();                   /* ensure ring space available */
>> +    XENKBD_IN_RING_REF(info, prod) = *event;
>> +    wmb();                  /* ensure ring contents visible */
>> +    info->in_prod = prod + 1;
>> +    return xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd_port);
>> +}
>> +
>> +static char *xenfb_path_in_dom(struct xs_handle *h,
>> +                     unsigned domid, const char *path,
>> +                     char *buffer, size_t size)
>> +{
>> +    char *domp = xs_get_domain_path(h, domid);
> Can fail.

Jeremy took care of this.

>> +    int n = snprintf(buffer, size, "%s/%s", domp, path);
>> +    free(domp);
>> +    if (n >= size)
>> +            return NULL;
>> +    return buffer;
>> +}
>> +
>> +static int xenfb_xs_scanf1(struct xs_handle *xsh, unsigned domid,
>> +                       const char *path, const char *fmt,
>> +                       void *dest)
>> +{
>> +    char buffer[1024];
>> +    char *p;
>> +    int ret;
>> +
>> +    p = xenfb_path_in_dom(xsh, domid, path, buffer, sizeof(buffer));
> What happens if this fails?

Catched.

>> +    p = xs_read(xsh, XBT_NULL, p, NULL);
>> +    if (!p)
>> +            return -ENOENT;
>> +    ret = sscanf(p, fmt, dest);
>> +    free(p);
>> +    if (ret != 1)
>> +            return -EDOM;
>> +    return 0;
>> +}
> You're somewhat inconsistent about returning error numbers as negative
> return values or through errno.  I'd prefer the latter in userspace
> code, but it doesn't matter too much, privided you pick one.

Jeremy took care of this.

>> +
>> +bool xenfb_attach_dom(struct xenfb *xenfb_pub, int domid)
>> +{
>> +    struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
>> +    char buffer[1024];
>> +    struct xs_handle *xsh;
>> +    unsigned dummy;
>> +    int ret;
>> +    char *p, **vec;
>> +    union xenfb_in_event event;
>> +
>> +    if (xenfb->domid != -1) {
>> +            xenfb_detach_dom(xenfb);
>> +            if (domid == -1)
>> +                    return true;
>> +    }
>> +
>> +    xsh = xs_daemon_open_readonly();
>> +    if (!xsh)
>> +        goto error;
>> +
>> +    p = xenfb_path_in_dom(xsh, domid, "vfb", buffer, sizeof(buffer));
>> +    if (!xs_watch(xsh, p, ""))
>> +            goto error;
>> +    p = xenfb_path_in_dom(xsh, domid, "vkbd", buffer, sizeof(buffer));
>> +    if (!xs_watch(xsh, p, ""))
>> +            goto error;
>> +
>> +    for (;;) {
>> +            ret = xenfb_xs_scanf1(xsh, domid, "vfb/page-ref", "%lu",
>> +                                  &xenfb->fbdev_mfn);
>> +            if (ret == -ENOENT || ret == -EAGAIN)
> xenfb_xs_scanf can't return -EAGAIN.  What are you trying to achieve
> here?

Jeremy took care of this.

>> +                    goto wait;
>> +            if (ret < 0)
>> +                    goto error;
>> +            ret = xenfb_xs_scanf1(xsh, domid, "vfb/event-channel", "%u",
>> +                                  &xenfb->fbdev_evtchn);
>> +            if (ret == -ENOENT || ret == -EAGAIN)
>> +                    goto wait;
>> +            if (ret < 0)
>> +                    goto error;
>> +            ret = xenfb_xs_scanf1(xsh, domid, "vkbd/page-ref", "%lu",
>> +                                  &xenfb->kbd_mfn);
>> +            if (ret == -ENOENT || ret == -EAGAIN)
>> +                    goto wait;
>> +            if (ret < 0)
>> +                    goto error;
>> +            ret = xenfb_xs_scanf1(xsh, domid, "vkbd/event-channel", "%u",
>> +                                  &xenfb->kbd_evtchn);
>> +            if (ret == -ENOENT || ret == -EAGAIN)
>> +                    goto wait;
>> +            if (ret < 0)
>> +                    goto error;
>> +            break;
>> +
>> +    wait:
>> +            printf("Waiting...\n");
> Where does this message go?

Jeremy answered this one.

>> +            vec = xs_read_watch(xsh, &dummy);
>> +            if (!vec)
>> +                    goto error;
>> +            free(vec);
>> +    }
>> +    xs_daemon_close(xsh);
>> +    xsh = NULL;
>> +
>> +    xenfb->fbdev_port = xc_evtchn_bind_interdomain(xenfb->evt_xch, domid,
>> +                                                   xenfb->fbdev_evtchn);
>> +    if (xenfb->fbdev_port == -1)
>> +            goto error;
>> +
>> +    xenfb->kbd_port = xc_evtchn_bind_interdomain(xenfb->evt_xch, domid,
>> +                                                 xenfb->kbd_evtchn);
>> +    if (xenfb->kbd_port == -1) 
>> +            goto error_fbdev;
>> +
>> +    xenfb->fb_info = xc_map_foreign_range(xenfb->xc, domid, XC_PAGE_SIZE,
>> +                                          PROT_READ | PROT_WRITE,
>> +                                          xenfb->fbdev_mfn);
>> +    if (xenfb->fb_info == NULL)
>> +            goto error_kbd;
>> +
>> +    xenfb->kbd_info = xc_map_foreign_range(xenfb->xc, domid, XC_PAGE_SIZE,
>> +                                           PROT_READ | PROT_WRITE,
>> +                                           xenfb->kbd_mfn);
>> +    if (xenfb->kbd_info == NULL)
>> +            goto error_fbinfo;
>> +
>> +    xenfb->n_fbmfns = (xenfb->fb_info->mem_length + (XC_PAGE_SIZE - 1)) / 
>> XC_PAGE_SIZE;
>> +    xenfb->n_fbdirs = xenfb->n_fbmfns * sizeof(unsigned long);
>> +    xenfb->n_fbdirs = (xenfb->n_fbdirs + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
>> +
>> +    xenfb->fbmfns = xc_map_foreign_batch(xenfb->xc, domid, PROT_READ, 
>> xenfb->fb_info->pd, xenfb->n_fbdirs);
>> +    if (xenfb->fbmfns == NULL)
>> +            goto error_kbdinfo;
>> +
>> +    xenfb->fb = xc_map_foreign_batch(xenfb->xc, domid, PROT_READ | 
>> PROT_WRITE, xenfb->fbmfns, xenfb->n_fbmfns);
>> +    if (xenfb->fb == NULL)
>> +            goto error_fbmfns;
>> +
>> +    event.type = XENFB_TYPE_SET_EVENTS;
>> +    event.set_events.flags = XENFB_FLAG_UPDATE;
>> +    if (xenfb_fb_event(xenfb, &event))
>> +            goto error_fb;
>> +
>> +    munmap(xenfb->fbmfns, xenfb->n_fbdirs * XC_PAGE_SIZE);
> Please make fbmfns a local rather than putting it in the info
> structure.

Done.

>> +
>> +    xenfb->domid = domid;
>> +
>> +    xenfb->pub.pixels = xenfb->fb;
>> +
>> +    xenfb->pub.row_stride = xenfb->fb_info->line_length;
>> +    xenfb->pub.depth = xenfb->fb_info->depth;
>> +    xenfb->pub.width = xenfb->fb_info->width;
>> +    xenfb->pub.height = xenfb->fb_info->height;
>> +
>> +    return true;
>> +
>> + error_fb:
> The error path here is utterly revolting.  Perhaps something like this:
>
> error:
>       serrno = errno;
>       if (xenfb->fb)
>               munmap(xenfb->fb, xenfb->fb_info->mem_length);
>       if (fbmfns)
>               munmap(fbmfns, xenfb->fb_info->mem_length);
>       ...
>       errno = serrno;
>
>       return false;
>
> Or would that be too easy?

Done.

>> +    printf("%d\n", __LINE__);
>> +    {
>> +            int serrno = errno;
>> +            munmap(xenfb->fb, xenfb->fb_info->mem_length);
>> +            errno = serrno;
>> +    }
>> + error_fbmfns:
>> +    printf("%d\n", __LINE__);
>> +    {
>> +            int serrno = errno;
>> +            munmap(xenfb->fbmfns, xenfb->n_fbdirs * XC_PAGE_SIZE);
>> +            errno = serrno;
>> +    }
>> + error_kbdinfo:
>> +    printf("%d\n", __LINE__);
>> +    {
>> +            int serrno = errno;
>> +            munmap(xenfb->kbd_info, XC_PAGE_SIZE);
>> +            errno = serrno;
>> +    }
>> + error_fbinfo:
>> +    printf("%d\n", __LINE__);
>> +    {
>> +            int serrno = errno;
>> +            munmap(xenfb->fb_info, XC_PAGE_SIZE);
>> +            errno = serrno;
>> +    }
>> + error_kbd:
>> +    printf("%d\n", __LINE__);
>> +    {
>> +            int serrno = errno;
>> +            xc_evtchn_unbind(xenfb->evt_xch, xenfb->kbd_port);
>> +            errno = serrno;
>> +    }
>> + error_fbdev:
>> +    printf("%d\n", __LINE__);
>> +    {
>> +            int serrno = errno;
>> +            xc_evtchn_unbind(xenfb->evt_xch, xenfb->fbdev_port);
>> +            errno = serrno;
>> +    }
>> + error:
>> +    printf("%d\n", __LINE__);
>> +    if (xsh) {
>> +            int serrno = errno;
>> +            xs_daemon_close(xsh);
> I think you may end up closing the connection to the daemon twice here.

Don't think so, because xsh is cleared on the other close.

>> +            errno = serrno;
>> +    }
>> +
>> +    return false;
>> +}
>> +
>> +static void xenfb_update(struct xenfb_private *xenfb, int x, int y, int 
>> width, int height)
>> +{
>> +    if (xenfb->pub.update)
>> +            xenfb->pub.update(&xenfb->pub, x, y, width, height);
>> +}
> I'm not convinced this wrapper is actually needed, given that it's
> utterly trivial and only called from one place.

It's gone.

>> +
>> +static void xenfb_on_fb_event(struct xenfb_private *xenfb)
>> +{
>> +    uint32_t prod, cons;
>> +    struct xenfb_page *info = xenfb->fb_info;
>> +
>> +    prod = info->out_prod;
>> +    rmb();                  /* ensure we see ring contents up to prod */
>> +    for (cons = info->out_cons; cons != prod; cons++) {
>> +            union xenfb_out_event *event = &XENFB_OUT_RING_REF(info, cons);
>> +
>> +            switch (event->type) {
>> +            case XENFB_TYPE_UPDATE:
>> +                    xenfb_update(xenfb, event->update.x, event->update.y, 
>> event->update.width, event->update.height);
>> +                    break;
>> +            }
>> +    }
>> +    mb();                   /* ensure we're done with ring contents */
>> +    info->out_cons = cons;
>> +    // FIXME need to notify?
> Maybe.  If there's any possibility of the frontend queuing evetns when
> the ring is full, yes.  It doesn't at the moment, but if you want to
> add it in the future and maintain forward compatibility you need it.

Added the notify.

>> +}
>> +
>> +static void xenfb_on_kbd_event(struct xenfb_private *xenfb)
>> +{
>> +    uint32_t prod, cons;
>> +    struct xenkbd_info *info = xenfb->kbd_info;
>> +
>> +    prod = info->out_prod;
>> +    rmb();                  /* ensure we see ring contents up to prod */
>> +    for (cons = info->out_cons; cons != prod; cons++) {
>> +            union xenkbd_out_event *event = &XENKBD_OUT_RING_REF(info, 
>> cons);
>> +
>> +            switch (event->type) {
>> +            default:
>> +                    break;
>> +            }
>> +    }
>> +    mb();                   /* ensure we're done with ring contents */
>> +    info->out_cons = cons;
>> +    // FIXME need to notify?
>> +}
>
> I'd replace this with
>
> +static void xenfb_on_kbd_event(struct xenfb_private *xenfb)
> +{
> +     struct xenkbd_info *info = xenfb->kbd_info;
> +       /* We don't understand any keyboard events, so just ignore them. */
> +     info->out_cons = info->out_prod;
> +}
>
> It's smaller, easier to understand, and more efficient.

Taken.

> As for the FIXME, the protocol spec says you need it, but I'm not sure
> it's actually all that useful.  It will only make any difference if
> the frontend starts queueing keyboard events if it finds the queue to
> be full when it tries to send one.

Added the notify.

>> +
>> +int xenfb_on_incoming(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->fbdev_port) {
>> +            xenfb_on_fb_event(xenfb);
>> +    } else if (port == xenfb->kbd_port) {
>> +            xenfb_on_kbd_event(xenfb);
>> +    }
>> +
>> +    if (xc_evtchn_unmask(xenfb->evt_xch, port) == -1)
>> +            return -1;
>> +
>> +    return 0;
>> +}
>> +
>> +int xenfb_send_key(struct xenfb *xenfb_pub, bool down, int keycode)
>> +{
>> +    struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
>> +    union xenkbd_in_event event;
>> +
>> +    event.type = XENKBD_TYPE_KEY;
>> +    event.key.pressed = down ? 1 : 0;
>> +    event.key.keycode = keycode;
>> +
>> +    return xenfb_kbd_event(xenfb, &event);
>> +}
>> +
>> +int xenfb_send_motion(struct xenfb *xenfb_pub, int rel_x, int rel_y)
> Is this sending XENKBD_TYPE_MOTION or XENFB_TYPE_MOTION?

XENFB_TYPE_MOTION doesn't exist anymore.

>> +{
>> +    struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
>> +    union xenkbd_in_event event;
>> +
>> +    event.type = XENKBD_TYPE_MOTION;
>> +    event.motion.rel_x = rel_x;
>> +    event.motion.rel_y = rel_y;
>> +
>> +    return xenfb_kbd_event(xenfb, &event);
>> +}
>> +
>> +int xenfb_send_button(struct xenfb *xenfb_pub, bool down, int button)
>> +{
>> +    struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
>> +    union xenkbd_in_event event;
>> +
>> +    event.type = XENKBD_TYPE_BUTTON;
>> +    event.button.pressed = down ? 1 : 0;
>> +    event.button.button = button;
>> +
>> +    return xenfb_kbd_event(xenfb, &event);
>> +}
>> --- /dev/null        Thu Jan 01 00:00:00 1970 +0000
>> +++ b/tools/xenfb/xenfb.h    Sat Sep 02 15:19:25 2006 -0400
>> @@ -0,0 +1,33 @@
>> +#ifndef _XENFB_H_
>> +#define _XENFB_H_
>> +
>> +#include <stdbool.h>
>> +#include <stdint.h>
>> +
>> +struct xenfb
>> +{
>> +    uint8_t *pixels;
>> +
>> +    int row_stride;
>> +    int depth;
>> +    int width;
>> +    int height;
>> +
>> +    void *user_data;
>> +
>> +    void (*update)(struct xenfb *xenfb, int x, int y, int width, int 
>> height);
>> +};
>> +
>> +struct xenfb *xenfb_new(void);
>> +void xenfb_delete(struct xenfb *xenfb);
>> +
>> +bool xenfb_attach_dom(struct xenfb *xenfb, int domid);
>> +
>> +int xenfb_get_fileno(struct xenfb *xenfb);
>> +int xenfb_on_incoming(struct xenfb *xenfb);
>> +
>> +int xenfb_send_key(struct xenfb *xenfb, bool down, int keycode);
>> +int xenfb_send_motion(struct xenfb *xenfb, int rel_x, int rel_y);
>> +int xenfb_send_button(struct xenfb *xenfb, bool down, int button);
>> +
>> +#endif
>
> Steven.

Okay, here's the next patch.  It doesn't yet take care of shadow
translate mode, just because I want to get it out of the door.  Next
week, I hope...

Oh, and it also doesn't include Daniel Berrange's locking fixes to
LibVNCServer, which you really, really need:
http://lists.xensource.com/archives/html/xen-devel/2006-09/msg00371.html

diff -r 9977b8785570 tools/Makefile
--- a/tools/Makefile    Fri Sep 29 19:12:15 2006 +0100
+++ b/tools/Makefile    Sat Sep 30 09:29:38 2006 +0200
@@ -18,6 +18,7 @@ SUBDIRS-y += xenstat
 SUBDIRS-y += xenstat
 SUBDIRS-y += libaio
 SUBDIRS-y += blktap
+SUBDIRS-y += xenfb
 
 # These don't cross-compile
 ifeq ($(XEN_COMPILE_ARCH),$(XEN_TARGET_ARCH))
diff -r 9977b8785570 tools/xenfb/Makefile
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/xenfb/Makefile      Sat Sep 30 09:29:38 2006 +0200
@@ -0,0 +1,33 @@
+XEN_ROOT=../..
+include $(XEN_ROOT)/tools/Rules.mk
+
+CFLAGS += -I$(XEN_LIBXC) -I$(XEN_XENSTORE) 
-I$(XEN_ROOT)/linux-2.6-xen-sparse/include
+LDFLAGS += -L$(XEN_LIBXC) -L$(XEN_XENSTORE)
+
+INSTALL         = install
+INSTALL_PROG    = $(INSTALL) -m0755
+INSTALL_DIR     = $(INSTALL) -d -m0755
+
+.PHONY: all
+all: build
+
+.PHONY: build
+build: mk-symlinks
+       $(MAKE) vncfb sdlfb
+
+install: all
+       $(INSTALL_DIR) -p $(DESTDIR)/usr/$(LIBDIR)/xen/bin
+       $(INSTALL_PROG) vncfb $(DESTDIR)/usr/$(LIBDIR)/xen/bin/xen-vncfb
+       $(INSTALL_PROG) sdlfb $(DESTDIR)/usr/$(LIBDIR)/xen/bin/xen-sdlfb
+
+sdlfb: sdlfb.o xenfb.o
+
+sdlfb.o: CFLAGS += $(shell sdl-config --cflags)
+sdlfb: LDLIBS += $(shell sdl-config --libs) -lxenctrl -lxenstore
+
+clean:
+       $(RM) *.o *~ vncfb sdlfb
+
+vncfb: vncfb.o xenfb.o
+vncfb.o: CFLAGS += $(shell libvncserver-config --cflags) $(shell pkg-config 
--cflags gtk+-2.0)
+vncfb: LDLIBS += $(shell libvncserver-config --libs) -lxenctrl -lxenstore
diff -r 9977b8785570 tools/xenfb/sdlfb.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/xenfb/sdlfb.c       Sat Sep 30 09:29:38 2006 +0200
@@ -0,0 +1,216 @@
+#include <SDL.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/select.h>
+#include <stdlib.h>
+#include <linux/input.h>
+#include <getopt.h>
+#include <string.h>
+#include "xenfb.h"
+
+struct SDLFBData
+{
+       SDL_Surface *dst;
+       SDL_Surface *src;
+};
+
+void sdl_update(struct xenfb *xenfb, int x, int y, int width, int height)
+{
+       struct SDLFBData *data = xenfb->user_data;
+       SDL_Rect r = { x, y, width, height };
+       SDL_BlitSurface(data->src, &r, data->dst, &r);
+       SDL_UpdateRect(data->dst, x, y, width, height);
+}
+
+int sdl2linux[1024] = {
+       [SDLK_a] = KEY_A,
+       [SDLK_b] = KEY_B,
+       [SDLK_c] = KEY_C,
+       [SDLK_d] = KEY_D,
+       [SDLK_e] = KEY_E,
+       [SDLK_f] = KEY_F,
+       [SDLK_g] = KEY_G,
+       [SDLK_h] = KEY_H,
+       [SDLK_i] = KEY_I,
+       [SDLK_j] = KEY_J,
+       [SDLK_k] = KEY_K,
+       [SDLK_l] = KEY_L,
+       [SDLK_m] = KEY_M,
+       [SDLK_n] = KEY_N,
+       [SDLK_o] = KEY_O,
+       [SDLK_p] = KEY_P,
+       [SDLK_q] = KEY_Q,
+       [SDLK_r] = KEY_R,
+       [SDLK_s] = KEY_S,
+       [SDLK_t] = KEY_T,
+       [SDLK_u] = KEY_U,
+       [SDLK_v] = KEY_V,
+       [SDLK_w] = KEY_W,
+       [SDLK_x] = KEY_X,
+       [SDLK_y] = KEY_Y,
+       [SDLK_z] = KEY_Z,
+       [SDLK_0] = KEY_0,
+       [SDLK_1] = KEY_1,
+       [SDLK_2] = KEY_2,
+       [SDLK_3] = KEY_3,
+       [SDLK_4] = KEY_4,
+       [SDLK_5] = KEY_5,
+       [SDLK_6] = KEY_6,
+       [SDLK_7] = KEY_7,
+       [SDLK_8] = KEY_8,
+       [SDLK_9] = KEY_9,
+       [SDLK_SPACE] = KEY_SPACE,
+       [SDLK_RETURN] = KEY_ENTER,
+       [SDLK_PERIOD] = KEY_DOT,
+       [SDLK_SLASH] = KEY_SLASH,
+       [SDLK_BACKSPACE] = KEY_BACKSPACE,
+       [SDLK_TAB] = KEY_TAB,
+       [SDLK_LSHIFT] = KEY_LEFTSHIFT,
+       [SDLK_RSHIFT] = KEY_RIGHTSHIFT,
+       [SDLK_LALT] = KEY_LEFTALT,
+       [SDLK_RALT] = KEY_RIGHTALT,
+};
+
+static struct option options[] = {
+       { "domid", 1, NULL, 'd' },
+       { "title", 1, NULL, 't' },
+};
+
+int main(int argc, char **argv)
+{
+       struct xenfb *xenfb;
+       int fd;
+       int domid = -1;
+        char * title = NULL;
+       fd_set readfds;
+       struct SDLFBData data;
+       SDL_Rect r;
+       struct timeval tv;
+       SDL_Event event;
+       int do_quit = 0;
+        int opt;
+        char *endp = NULL;
+
+       while ((opt = getopt_long(argc, argv, "d:t:", options,
+                                 NULL)) != -1) {
+               switch (opt) {
+                case 'd':
+                       domid = strtol(optarg, &endp, 10);
+                       if (endp == optarg || *endp || errno) {
+                               fprintf(stderr, "Invalid domain id 
specified\n");
+                               exit(1);
+                       }
+                       break;
+                case 't':
+                       title = strdup(optarg);
+                       break;
+                }
+        }
+        if (optind != argc) {
+               fprintf(stderr, "Invalid options!\n");
+               exit(1);
+        }
+        if (domid <= 0) {
+               fprintf(stderr, "Domain ID must be specified!\n");
+               exit(1);
+        }
+
+       xenfb = xenfb_new();
+       if (xenfb == NULL) {
+               fprintf(stderr, "Could not create framebuffer (%s)\n",
+                       strerror(errno));
+               exit(1);
+        }
+
+       if (!xenfb_attach_dom(xenfb, domid)) {
+               fprintf(stderr, "Could not connect to domain (%s)\n",
+                       strerror(errno));
+               exit(1);
+        }
+
+       SDL_Init(SDL_INIT_VIDEO);
+
+       fd = xenfb_get_fileno(xenfb);
+
+       data.dst = SDL_SetVideoMode(xenfb->width, xenfb->height, xenfb->depth,
+                                   SDL_SWSURFACE);
+
+       data.src = SDL_CreateRGBSurfaceFrom(xenfb->pixels,
+                                           xenfb->width, xenfb->height,
+                                           xenfb->depth, xenfb->row_stride,
+                                           0xFF0000, 0xFF00, 0xFF, 0);
+
+        if (title == NULL)
+               title = strdup("xen-sdlfb");
+        SDL_WM_SetCaption(title, title);
+
+       r.x = r.y = 0;
+       r.w = xenfb->width;
+       r.h = xenfb->height;
+       SDL_BlitSurface(data.src, &r, data.dst, &r);
+       SDL_UpdateRect(data.dst, 0, 0, xenfb->width, xenfb->height);
+
+       xenfb->update = sdl_update;
+       xenfb->user_data = &data;
+
+       SDL_ShowCursor(0);
+
+       /*
+        * We need to wait for fd becoming ready or SDL events to
+        * arrive.  We time out the select after 10ms to poll for SDL
+        * events.  Clunky, but works.  Could avoid the clunkiness
+        * with a separate thread.
+        */
+       for (;;) {
+               FD_ZERO(&readfds);
+               FD_SET(fd, &readfds);
+               tv = (struct timeval){0, 10000};
+
+               if (select(fd + 1, &readfds, NULL, NULL, &tv) < 0) {
+                       if (errno == EINTR)
+                               continue;
+                       fprintf(stderr, "Connection to domain broke (%s)\n",
+                               strerror(errno));
+                       break;
+               }
+
+               while (SDL_PollEvent(&event)) {
+                       switch (event.type) {
+                       case SDL_KEYDOWN:
+                       case SDL_KEYUP:
+                               xenfb_send_key(xenfb,
+                                       event.type == SDL_KEYDOWN,
+                                       sdl2linux[event.key.keysym.sym]);
+                               break;
+                       case SDL_MOUSEMOTION: {
+                               int x, y;
+                               Uint8 button;
+
+                               button = SDL_GetRelativeMouseState(&x, &y);
+                               xenfb_send_motion(xenfb, x, y);
+                       }       break;
+                       case SDL_MOUSEBUTTONDOWN:
+                       case SDL_MOUSEBUTTONUP:
+                               xenfb_send_button(xenfb,
+                                       event.type == SDL_MOUSEBUTTONDOWN,
+                                       3 - event.button.button);
+                               break;
+                       case SDL_QUIT:
+                               do_quit = 1;
+                               break;
+                       }
+               }
+
+                if (do_quit)
+                       break;
+
+               if (FD_ISSET(fd, &readfds))
+                       xenfb_on_incoming(xenfb);
+       }
+
+       xenfb_delete(xenfb);
+
+       SDL_Quit();
+
+       return 0;
+}
diff -r 9977b8785570 tools/xenfb/vncfb.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/xenfb/vncfb.c       Sat Sep 30 09:29:38 2006 +0200
@@ -0,0 +1,402 @@
+#define _GNU_SOURCE
+#include <errno.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+#include <malloc.h>
+#include <rfb/rfb.h>
+#include <gdk/gdkkeysyms.h>
+#include <linux/input.h>
+#include <xs.h>
+#include "xenfb.h"
+
+static uint32_t gdk_linux_mapping[0x10000] = {
+       [GDK_a] = KEY_A,
+       [GDK_b] = KEY_B,
+       [GDK_c] = KEY_C,
+       [GDK_d] = KEY_D,
+       [GDK_e] = KEY_E,
+       [GDK_f] = KEY_F,
+       [GDK_g] = KEY_G,
+       [GDK_h] = KEY_H,
+       [GDK_i] = KEY_I,
+       [GDK_j] = KEY_J,
+       [GDK_k] = KEY_K,
+       [GDK_l] = KEY_L,
+       [GDK_m] = KEY_M,
+       [GDK_n] = KEY_N,
+       [GDK_o] = KEY_O,
+       [GDK_p] = KEY_P,
+       [GDK_q] = KEY_Q,
+       [GDK_r] = KEY_R,
+       [GDK_s] = KEY_S,
+       [GDK_t] = KEY_T,
+       [GDK_u] = KEY_U,
+       [GDK_v] = KEY_V,
+       [GDK_w] = KEY_W,
+       [GDK_x] = KEY_X,
+       [GDK_y] = KEY_Y,
+       [GDK_z] = KEY_Z,
+       [GDK_A] = KEY_A,
+       [GDK_B] = KEY_B,
+       [GDK_C] = KEY_C,
+       [GDK_D] = KEY_D,
+       [GDK_E] = KEY_E,
+       [GDK_F] = KEY_F,
+       [GDK_G] = KEY_G,
+       [GDK_H] = KEY_H,
+       [GDK_I] = KEY_I,
+       [GDK_J] = KEY_J,
+       [GDK_K] = KEY_K,
+       [GDK_L] = KEY_L,
+       [GDK_M] = KEY_M,
+       [GDK_N] = KEY_N,
+       [GDK_O] = KEY_O,
+       [GDK_P] = KEY_P,
+       [GDK_Q] = KEY_Q,
+       [GDK_R] = KEY_R,
+       [GDK_S] = KEY_S,
+       [GDK_T] = KEY_T,
+       [GDK_U] = KEY_U,
+       [GDK_V] = KEY_V,
+       [GDK_W] = KEY_W,
+       [GDK_X] = KEY_X,
+       [GDK_Y] = KEY_Y,
+       [GDK_Z] = KEY_Z,
+       [GDK_0] = KEY_0,
+       [GDK_1] = KEY_1,
+       [GDK_2] = KEY_2,
+       [GDK_3] = KEY_3,
+       [GDK_4] = KEY_4,
+       [GDK_5] = KEY_5,
+       [GDK_6] = KEY_6,
+       [GDK_7] = KEY_7,
+       [GDK_8] = KEY_8,
+       [GDK_9] = KEY_9,
+       [GDK_Return] = KEY_ENTER,
+       [GDK_BackSpace] = KEY_BACKSPACE,
+       [GDK_Tab] = KEY_TAB,
+       [GDK_Pause] = KEY_PAUSE,
+       [GDK_Delete] = KEY_DELETE,
+       [GDK_slash] = KEY_SLASH,
+       [GDK_minus] = KEY_MINUS,
+       [GDK_equal] = KEY_EQUAL,
+       [GDK_Escape] = KEY_ESC,
+       [GDK_braceleft] = KEY_LEFTBRACE,
+       [GDK_braceright] = KEY_RIGHTBRACE,
+       [GDK_bracketleft] = KEY_LEFTMETA,
+       [GDK_bracketright] = KEY_RIGHTMETA,
+       [GDK_Control_L] = KEY_LEFTCTRL,
+       [GDK_Control_R] = KEY_RIGHTCTRL,
+       [GDK_Shift_L] = KEY_LEFTSHIFT,
+       [GDK_Shift_R] = KEY_RIGHTSHIFT,
+       [GDK_Alt_L] = KEY_LEFTALT,
+       [GDK_Alt_R] = KEY_RIGHTALT,
+       [GDK_semicolon] = KEY_SEMICOLON, 
+       [GDK_apostrophe] = KEY_APOSTROPHE,
+       [GDK_grave] = KEY_GRAVE,
+       [GDK_backslash] = KEY_BACKSLASH,
+       [GDK_comma] = KEY_COMMA,
+       [GDK_period] = KEY_DOT,
+       [GDK_space] = KEY_SPACE,
+       [GDK_Caps_Lock] = KEY_CAPSLOCK,
+       [GDK_Num_Lock] = KEY_NUMLOCK,
+       [GDK_Scroll_Lock] = KEY_SCROLLLOCK,
+       [GDK_Sys_Req] = KEY_SYSRQ,
+       [GDK_Linefeed] = KEY_LINEFEED,
+       [GDK_Home] = KEY_HOME,
+       [GDK_Pause] = KEY_PAUSE,
+       [GDK_F1] = KEY_F1,
+       [GDK_F2] = KEY_F2,
+       [GDK_F3] = KEY_F3,
+       [GDK_F4] = KEY_F4,
+       [GDK_F5] = KEY_F5,
+       [GDK_F6] = KEY_F6,
+       [GDK_F7] = KEY_F7,
+       [GDK_F8] = KEY_F8,
+       [GDK_F9] = KEY_F9,
+       [GDK_F10] = KEY_F10,
+       [GDK_F11] = KEY_F11,
+       [GDK_F12] = KEY_F12,
+       [GDK_Up] = KEY_UP,
+       [GDK_Page_Up] = KEY_PAGEUP,
+       [GDK_Left] = KEY_LEFT,
+       [GDK_Right] = KEY_RIGHT,
+       [GDK_End] = KEY_END,
+       [GDK_Down] = KEY_DOWN,
+       [GDK_Page_Down] = KEY_PAGEDOWN,
+       [GDK_Insert] = KEY_INSERT, 
+       [GDK_colon] = KEY_SEMICOLON,
+       [GDK_quotedbl] = KEY_APOSTROPHE,
+       [GDK_less] = KEY_COMMA,
+       [GDK_greater] = KEY_DOT,
+       [GDK_question] = KEY_SLASH,
+       [GDK_bar] = KEY_BACKSLASH,
+       [GDK_asciitilde] = KEY_GRAVE,
+       [GDK_exclam] = KEY_1,
+       [GDK_at] = KEY_2,
+       [GDK_numbersign] = KEY_3,
+       [GDK_dollar] = KEY_4,
+       [GDK_percent] = KEY_5,
+       [GDK_asciicircum] = KEY_6,
+       [GDK_ampersand] = KEY_7,
+       [GDK_asterisk] = KEY_8,
+       [GDK_parenleft] = KEY_9,
+       [GDK_parenright] = KEY_0,
+       [GDK_underscore] = KEY_MINUS,
+       [GDK_plus] = KEY_EQUAL,
+};
+
+static void on_kbd_event(rfbBool down, rfbKeySym keycode, rfbClientPtr cl)
+{
+       rfbScreenInfoPtr server = cl->screen;
+       struct xenfb *xenfb = server->screenData;
+       xenfb_send_key(xenfb, down, gdk_linux_mapping[keycode & 0xFFFF]);
+}
+
+static void on_ptr_event(int buttonMask, int x, int y, rfbClientPtr cl)
+{
+       static int last_x = -1, last_y = -1;
+       static int last_button = -1;
+       rfbScreenInfoPtr server = cl->screen;
+       struct xenfb *xenfb = server->screenData;
+
+       if (last_button != -1) {
+               int i;
+
+               for (i = 0; i < 8; i++) {
+                       if ((last_button & (1 << i)) !=
+                           (buttonMask & (1 << i))) {
+                               xenfb_send_button(xenfb, buttonMask & (1 << i),
+                                                 2 - i);
+                       }
+               }
+       }
+
+       if (last_x != -1)
+               xenfb_send_motion(xenfb, x - last_x, y - last_y);
+
+       last_button = buttonMask;
+
+       last_x = x;
+       last_y = y;
+}
+
+static void xenstore_write_vncport(int port, int domid)
+{
+       char *buf = NULL, *path;
+       char portstr[10];
+       struct xs_handle *xsh = NULL;
+
+       xsh = xs_daemon_open();
+       if (xsh == NULL)
+               return;
+
+       path = xs_get_domain_path(xsh, domid);
+       if (path == NULL) {
+               fprintf(stderr, "Can't get domain path (%s)\n",
+                       strerror(errno));
+               goto out;
+       }
+
+       if (asprintf(&buf, "%s/console/vnc-port", path) == -1) {
+               fprintf(stderr, "Can't make vncport path\n");
+               goto out;
+       }
+
+       if (snprintf(portstr, sizeof(portstr), "%d", port) == -1) {
+               fprintf(stderr, "Can't make vncport value\n");
+               goto out;
+       }
+
+       if (!xs_write(xsh, XBT_NULL, buf, portstr, strlen(portstr)))
+               fprintf(stderr, "Can't set vncport (%s)\n",
+                       strerror(errno));
+
+out:
+       free(buf);
+}
+
+
+static void vnc_update(struct xenfb *xenfb, int x, int y, int w, int h)
+{
+       rfbScreenInfoPtr server = xenfb->user_data;
+       rfbMarkRectAsModified(server, x, y, x + w, y + h);
+}
+
+static int vnc_start_viewer(int port) 
+{
+       int pid;
+       char s[16];
+
+       snprintf(s, sizeof(s), ":%d", port);
+       switch (pid = fork()) {
+       case -1:
+               fprintf(stderr, "vncviewer failed fork\n");
+               exit(1);
+
+       case 0: /* child */
+               execlp("vncviewer", "vncviewer", s, NULL);
+               fprintf(stderr, "vncviewer execlp failed\n");
+               exit(1);
+
+       default:
+               return pid;
+       }
+}
+
+static struct option options[] = {
+       { "domid", 1, NULL, 'd' },
+       { "vncport", 1, NULL, 'p' },
+       { "title", 1, NULL, 't' },
+       { "unused", 0, NULL, 'u' },
+       { "listen", 1, NULL, 'l' },
+       { "vncviewer", 0, NULL, 'v' },
+};
+
+int main(int argc, char **argv)
+{
+       rfbScreenInfoPtr server;
+       char *fake_argv[7] = { "vncfb", "-rfbport", "5901", 
+                               "-desktop", "xen-vncfb", 
+                               "-listen", "0.0.0.0" };
+       int fake_argc = sizeof(fake_argv) / sizeof(fake_argv[0]);
+       int domid = -1, port = -1;
+        char *title = NULL;
+        char *listen = NULL;
+       struct xenfb *xenfb;
+       fd_set readfds;
+       int fd;
+       char portstr[10];
+        int opt;
+        bool unused = false;
+        bool viewer = false;
+        char *endp = NULL;
+
+       while ((opt = getopt_long(argc, argv, "d:p:t:u", options,
+                                 NULL)) != -1) {
+               switch (opt) {
+                case 'd':
+                       errno = 0;
+                       domid = strtol(optarg, &endp, 10);
+                       if (endp == optarg || *endp || errno) {
+                               fprintf(stderr, "Invalid domain id 
specified\n");
+                               exit(1);
+                       }
+                       break;
+                case 'p':
+                       errno = 0;
+                       port = strtol(optarg, &endp, 10);
+                       if (endp == optarg || *endp || errno) {
+                               fprintf(stderr, "Invalid port specified\n");
+                               exit(1);
+                       }
+                       break;
+                case 't':
+                       title = strdup(optarg);
+                       break;
+                case 'u':
+                       unused = true;
+                       break;
+                case 'l':
+                       listen = strdup(optarg);
+                       break;
+                case 'v':
+                       viewer = true;
+                       break;
+                }
+        }
+        if (optind != argc) {
+               fprintf(stderr, "Invalid options!\n");
+               exit(1);
+        }
+        if (domid <= 0) {
+               fprintf(stderr, "Domain ID must be specified!\n");
+               exit(1);
+        }
+            
+        if (port <= 0)
+               port = 5900 + domid;
+       if (snprintf(portstr, sizeof(portstr), "%d", port) == -1) {
+               fprintf(stderr, "Invalid port specified\n");
+               exit(1);
+        }
+            
+       fake_argv[2] = portstr;
+
+        if (title != NULL)
+               fake_argv[4] = title;
+
+        if (listen != NULL)
+               fake_argv[6] = listen;
+
+       signal(SIGPIPE, SIG_IGN);
+
+       xenfb = xenfb_new();
+       if (xenfb == NULL) {
+               fprintf(stderr, "Could not create framebuffer (%s)\n",
+                       strerror(errno));
+               exit(1);
+       }
+
+       if (!xenfb_attach_dom(xenfb, domid)) {
+               fprintf(stderr, "Could not connect to domain (%s)\n",
+                       strerror(errno));
+               exit(1);
+       }
+
+       server = rfbGetScreen(&fake_argc, fake_argv, 
+                             xenfb->width, xenfb->height,
+                             8, 3, xenfb->depth / 8);
+       if (server == NULL) {
+               fprintf(stderr, "Could not create VNC server\n");
+               exit(1);
+       }
+
+       xenfb->user_data = server;
+       xenfb->update = vnc_update;
+
+        if (unused)
+               server->autoPort = true;
+
+       server->serverFormat.redShift = 16;
+       server->serverFormat.greenShift = 8;
+       server->serverFormat.blueShift = 0;
+       server->kbdAddEvent = on_kbd_event;
+       server->ptrAddEvent = on_ptr_event;
+       server->frameBuffer = (char *)xenfb->pixels;
+       server->screenData = xenfb;
+       server->cursor = NULL;
+       rfbInitServer(server);
+
+       rfbRunEventLoop(server, -1, true);
+
+       fd = xenfb_get_fileno(xenfb);
+
+        xenstore_write_vncport(server->port, domid);
+
+        if (viewer)
+               vnc_start_viewer(server->port);
+
+       for (;;) {
+               FD_ZERO(&readfds);
+               FD_SET(fd, &readfds);
+
+               if (select(fd + 1, &readfds, NULL, NULL, NULL) < 0) {
+                       if (errno == EINTR)
+                               continue;
+                       fprintf(stderr, "Connection to domain broke (%s)\n",
+                               strerror(errno));
+                       break;
+               }
+
+               if (FD_ISSET(fd, &readfds))
+                       xenfb_on_incoming(xenfb);
+       }
+
+       rfbScreenCleanup(server);
+       xenfb_delete(xenfb);
+
+       return 0;
+}
diff -r 9977b8785570 tools/xenfb/xenfb.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/xenfb/xenfb.c       Sat Sep 30 09:29:38 2006 +0200
@@ -0,0 +1,404 @@
+#include <malloc.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <xenctrl.h>
+#include <linux/xenfb.h>
+#include <linux/xenkbd.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"
+
+// FIXME defend against malicous frontend?
+
+struct xenfb_private
+{
+       struct xenfb pub;
+       int domid;
+       evtchn_port_t fbdev_port, kbd_port;
+       int evt_xch;
+       int xc;
+       unsigned char *fb;
+       struct xenfb_page *fb_info;
+       struct xenkbd_info *kbd_info;
+};
+
+struct xenfb *xenfb_new(void)
+{
+       struct xenfb_private *xenfb = malloc(sizeof(*xenfb));
+
+       if (xenfb == NULL)
+               return NULL;
+
+       memset(xenfb, 0, sizeof(*xenfb));
+
+       xenfb->domid = -1;
+
+       xenfb->evt_xch = xc_evtchn_open();
+       if (xenfb->evt_xch == -1) {
+               int serrno = errno;
+               free(xenfb);
+               errno = serrno;
+               return NULL;
+       }
+
+       xenfb->xc = xc_interface_open();
+       if (xenfb->xc == -1) {
+               int serrno = errno;
+               xc_evtchn_close(xenfb->evt_xch);
+               free(xenfb);
+               errno = serrno;
+               return NULL;
+       }
+
+       return &xenfb->pub;
+}
+
+int xenfb_get_fileno(struct xenfb *xenfb_pub)
+{
+       struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
+
+       return xc_evtchn_fd(xenfb->evt_xch);
+}
+
+static void xenfb_detach_dom(struct xenfb_private *xenfb)
+{
+       xenfb->domid = -1;
+       munmap(xenfb->fb, xenfb->fb_info->mem_length);
+       munmap(xenfb->fb_info, XC_PAGE_SIZE);
+       munmap(xenfb->kbd_info, XC_PAGE_SIZE);
+       xc_evtchn_unbind(xenfb->evt_xch, xenfb->fbdev_port);
+       xc_evtchn_unbind(xenfb->evt_xch, xenfb->kbd_port);
+}
+
+void xenfb_delete(struct xenfb *xenfb_pub)
+{
+       struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
+       if (xenfb->domid != -1)
+               xenfb_detach_dom(xenfb);
+       free(xenfb);
+}
+
+static int xenfb_fb_event(struct xenfb_private *xenfb, union xenfb_in_event 
*event)
+{
+       uint32_t prod;
+       struct xenfb_page *info = xenfb->fb_info;
+
+       prod = info->in_prod;
+       if (prod - info->in_cons == XENFB_IN_RING_LEN) {
+           errno = EAGAIN;
+           return -1;
+       }
+
+       mb();                   /* ensure ring space available */
+       XENFB_IN_RING_REF(info, prod) = *event;
+       wmb();                  /* ensure ring contents visible */
+       info->in_prod = prod + 1;
+       return xc_evtchn_notify(xenfb->evt_xch, xenfb->fbdev_port);
+}
+
+static int xenfb_kbd_event(struct xenfb_private *xenfb, union xenkbd_in_event 
*event)
+{
+       uint32_t prod;
+       struct xenkbd_info *info = xenfb->kbd_info;
+
+       prod = info->in_prod;
+       if (prod - info->in_cons == XENKBD_IN_RING_LEN) {
+               errno = EAGAIN;
+               return -1;
+       }
+
+       mb();                   /* ensure ring space available */
+       XENKBD_IN_RING_REF(info, prod) = *event;
+       wmb();                  /* ensure ring contents visible */
+       info->in_prod = prod + 1;
+       return xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd_port);
+}
+
+static char *xenfb_path_in_dom(struct xs_handle *h,
+                        unsigned domid, const char *path,
+                        char *buffer, size_t size)
+{
+       char *domp = xs_get_domain_path(h, domid);
+       int n;
+
+        if (domp == NULL)
+               return NULL;
+        n = snprintf(buffer, size, "%s/%s", domp, path);
+       free(domp);
+       if (n >= size)
+               return NULL;
+       return buffer;
+}
+
+static int xenfb_xs_scanf1(struct xs_handle *xsh, unsigned domid,
+                          const char *path, const char *fmt,
+                          void *dest)
+{
+       char buffer[1024];
+       char *p;
+       int ret;
+
+       p = xenfb_path_in_dom(xsh, domid, path, buffer, sizeof(buffer));
+        if (!p) {
+               errno = -ENOENT;
+               return -1;
+        }
+       p = xs_read(xsh, XBT_NULL, p, NULL);
+       if (!p) {
+               errno = -ENOENT;
+               return -1;
+        }
+       ret = sscanf(p, fmt, dest);
+       free(p);
+       if (ret != 1) {
+               errno = -EDOM;
+               return -1;
+        }
+       return 0;
+}
+
+bool xenfb_attach_dom(struct xenfb *xenfb_pub, int domid)
+{
+       struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
+       char buffer[1024];
+       struct xs_handle *xsh;
+       unsigned dummy;
+       int ret;
+       char *p, **vec;
+       union xenfb_in_event event;
+       unsigned long *fbmfns = NULL;
+       int n_fbmfns, n_fbdirs;
+        int serrno;
+        int fbdev_evtchn, kbd_evtchn;
+       unsigned long fbdev_mfn, kbd_mfn;
+
+       if (xenfb->domid != -1) {
+               xenfb_detach_dom(xenfb);
+               if (domid == -1)
+                       return true;
+       }
+
+       xsh = xs_daemon_open_readonly();
+       if (!xsh)
+               goto error;
+
+       p = xenfb_path_in_dom(xsh, domid, "vfb", buffer, sizeof(buffer));
+       if (!p)
+               goto error;
+       if (!xs_watch(xsh, p, ""))
+               goto error;
+       p = xenfb_path_in_dom(xsh, domid, "vkbd", buffer, sizeof(buffer));
+       if (!p)
+               goto error;
+       if (!xs_watch(xsh, p, ""))
+               goto error;
+
+       for (;;) {
+               ret = xenfb_xs_scanf1(xsh, domid, "vfb/0/page-ref", "%lu",
+                                     &fbdev_mfn);
+               if (ret == -1 && errno == -ENOENT)
+                       goto wait;
+               if (ret < 0)
+                       goto error;
+               ret = xenfb_xs_scanf1(xsh, domid, "vfb/0/event-channel", "%u",
+                                     &fbdev_evtchn);
+               if (ret == -1 && errno == -ENOENT)
+                       goto wait;
+               if (ret < 0)
+                       goto error;
+               ret = xenfb_xs_scanf1(xsh, domid, "vkbd/0/page-ref", "%lu",
+                                     &kbd_mfn);
+               if (ret == -1 && errno == -ENOENT)
+                       goto wait;
+               if (ret < 0)
+                       goto error;
+               ret = xenfb_xs_scanf1(xsh, domid, "vkbd/0/event-channel", "%u",
+                                     &kbd_evtchn);
+               if (ret == -1 && errno == -ENOENT)
+                       goto wait;
+               if (ret < 0)
+                       goto error;
+               break;
+
+       wait:
+               printf("Waiting for guest framebuffer to connect...\n");
+               vec = xs_read_watch(xsh, &dummy);
+               if (!vec)
+                       goto error;
+               free(vec);
+       }
+       xs_daemon_close(xsh);
+       xsh = NULL;
+
+       xenfb->fbdev_port = xc_evtchn_bind_interdomain(xenfb->evt_xch, domid,
+                                                      fbdev_evtchn);
+       if (xenfb->fbdev_port == -1)
+               goto error;
+
+       xenfb->kbd_port = xc_evtchn_bind_interdomain(xenfb->evt_xch, domid,
+                                                    kbd_evtchn);
+       if (xenfb->kbd_port == -1) 
+               goto error;
+
+       xenfb->fb_info = xc_map_foreign_range(xenfb->xc, domid, XC_PAGE_SIZE,
+                                             PROT_READ | PROT_WRITE,
+                                             fbdev_mfn);
+       if (xenfb->fb_info == NULL)
+               goto error;
+
+       xenfb->kbd_info = xc_map_foreign_range(xenfb->xc, domid, XC_PAGE_SIZE,
+                                              PROT_READ | PROT_WRITE,
+                                              kbd_mfn);
+       if (xenfb->kbd_info == NULL)
+               goto error;
+
+       n_fbmfns = (xenfb->fb_info->mem_length + (XC_PAGE_SIZE - 1)) / 
XC_PAGE_SIZE;
+       n_fbdirs = n_fbmfns * sizeof(unsigned long);
+       n_fbdirs = (n_fbdirs + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
+
+       fbmfns = xc_map_foreign_batch(xenfb->xc, domid, PROT_READ, 
xenfb->fb_info->pd, n_fbdirs);
+       if (fbmfns == NULL)
+               goto error;
+
+       xenfb->fb = xc_map_foreign_batch(xenfb->xc, domid, PROT_READ | 
PROT_WRITE, fbmfns, n_fbmfns);
+       if (xenfb->fb == NULL)
+               goto error;
+
+       event.type = XENFB_TYPE_SET_EVENTS;
+       event.set_events.flags = XENFB_FLAG_UPDATE;
+       if (xenfb_fb_event(xenfb, &event))
+               goto error;
+
+       munmap(fbmfns, n_fbdirs * XC_PAGE_SIZE);
+
+       xenfb->domid = domid;
+
+       xenfb->pub.pixels = xenfb->fb;
+
+       xenfb->pub.row_stride = xenfb->fb_info->line_length;
+       xenfb->pub.depth = xenfb->fb_info->depth;
+       xenfb->pub.width = xenfb->fb_info->width;
+       xenfb->pub.height = xenfb->fb_info->height;
+
+       return true;
+
+error:        
+       serrno = errno;
+       if (xenfb->fb)
+               munmap(xenfb->fb, xenfb->fb_info->mem_length);
+       if (fbmfns)
+               munmap(fbmfns, xenfb->fb_info->mem_length);
+        if (xenfb->kbd_info)
+               munmap(xenfb->kbd_info, XC_PAGE_SIZE);
+        if (xenfb->fb_info)
+               munmap(xenfb->fb_info, XC_PAGE_SIZE);
+        if (xenfb->kbd_port);
+       xc_evtchn_unbind(xenfb->evt_xch, xenfb->kbd_port);
+        if (xenfb->fbdev_port)
+               xc_evtchn_unbind(xenfb->evt_xch, xenfb->fbdev_port);
+        if (xsh) 
+               xs_daemon_close(xsh);
+        errno = serrno;
+        return false;
+}
+
+static void xenfb_on_fb_event(struct xenfb_private *xenfb)
+{
+       uint32_t prod, cons;
+       struct xenfb_page *info = xenfb->fb_info;
+
+       prod = info->out_prod;
+       rmb();                  /* ensure we see ring contents up to prod */
+       for (cons = info->out_cons; cons != prod; cons++) {
+               union xenfb_out_event *event = &XENFB_OUT_RING_REF(info, 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 */
+       info->out_cons = cons;
+       xc_evtchn_notify(xenfb->evt_xch, xenfb->fbdev_port);
+}
+
+static void xenfb_on_kbd_event(struct xenfb_private *xenfb)
+{
+       struct xenkbd_info *info = xenfb->kbd_info;
+
+       /* We don't understand any keyboard events, so just ignore them. */
+       info->out_cons = info->out_prod;
+       xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd_port);
+}
+
+int xenfb_on_incoming(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->fbdev_port) {
+               xenfb_on_fb_event(xenfb);
+       } else if (port == xenfb->kbd_port) {
+               xenfb_on_kbd_event(xenfb);
+       }
+
+       if (xc_evtchn_unmask(xenfb->evt_xch, port) == -1)
+               return -1;
+
+       return 0;
+}
+
+int xenfb_send_key(struct xenfb *xenfb_pub, bool down, int keycode)
+{
+       struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
+       union xenkbd_in_event event;
+
+       event.type = XENKBD_TYPE_KEY;
+       event.key.pressed = down ? 1 : 0;
+       event.key.keycode = keycode;
+
+       return xenfb_kbd_event(xenfb, &event);
+}
+
+int xenfb_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;
+
+       event.type = XENKBD_TYPE_MOTION;
+       event.motion.rel_x = rel_x;
+       event.motion.rel_y = rel_y;
+
+       return xenfb_kbd_event(xenfb, &event);
+}
+
+int xenfb_send_button(struct xenfb *xenfb_pub, bool down, int button)
+{
+       struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
+       union xenkbd_in_event event;
+
+       event.type = XENKBD_TYPE_BUTTON;
+       event.button.pressed = down ? 1 : 0;
+       event.button.button = button;
+
+       return xenfb_kbd_event(xenfb, &event);
+}
diff -r 9977b8785570 tools/xenfb/xenfb.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/xenfb/xenfb.h       Sat Sep 30 09:29:38 2006 +0200
@@ -0,0 +1,33 @@
+#ifndef _XENFB_H_
+#define _XENFB_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+
+struct xenfb
+{
+       uint8_t *pixels;
+
+       int row_stride;
+       int depth;
+       int width;
+       int height;
+
+       void *user_data;
+
+       void (*update)(struct xenfb *xenfb, int x, int y, int width, int 
height);
+};
+
+struct xenfb *xenfb_new(void);
+void xenfb_delete(struct xenfb *xenfb);
+
+bool xenfb_attach_dom(struct xenfb *xenfb, int domid);
+
+int xenfb_get_fileno(struct xenfb *xenfb);
+int xenfb_on_incoming(struct xenfb *xenfb);
+
+int xenfb_send_key(struct xenfb *xenfb, bool down, int keycode);
+int xenfb_send_motion(struct xenfb *xenfb, int rel_x, int rel_y);
+int xenfb_send_button(struct xenfb *xenfb, bool down, int button);
+
+#endif

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel