[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

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



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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.