From mboxrd@z Thu Jan 1 00:00:00 1970 From: Samuel Thibault Subject: [PATCH] stubdom: use PVFB so as to e.g. permit SDL display Date: Wed, 27 Feb 2008 18:42:19 +0000 Message-ID: <20080227184219.GB10230@implementation.uk.xensource.com> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Return-path: Content-Disposition: inline List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Sender: xen-devel-bounces@lists.xensource.com Errors-To: xen-devel-bounces@lists.xensource.com To: xen-devel@lists.xensource.com List-Id: xen-devel@lists.xenproject.org This adds support in ioemu for PVFB frontend as stubdomain display. This permits for instance to use SDL in dom0 to perform the eventual display. Signed-off-by: Samuel Thibault diff -r 2a8eaba24bf0 extras/mini-os/fbfront.c --- a/extras/mini-os/fbfront.c Tue Feb 26 15:11:51 2008 +0000 +++ b/extras/mini-os/fbfront.c Wed Feb 27 18:30:05 2008 +0000 @@ -30,13 +30,6 @@ struct kbdfront_dev { char *nodename; char *backend; - - char *data; - int width; - int height; - int depth; - int line_length; - int mem_length; #ifdef HAVE_LIBC int fd; @@ -316,7 +309,10 @@ struct fbfront_dev *init_fbfront(char *n for (i = 0; mapped < mem_length && i < max_pd; i++) { unsigned long *pd = (unsigned long *) alloc_page(); for (j = 0; mapped < mem_length && j < PAGE_SIZE / sizeof(unsigned long); j++) { - pd[j] = virt_to_mfn((unsigned long) data + mapped); + /* Trigger CoW */ + * ((char *)data + mapped) = 0; + barrier(); + pd[j] = virtual_to_mfn((unsigned long) data + mapped); mapped += PAGE_SIZE; } for ( ; j < PAGE_SIZE / sizeof(unsigned long); j++) diff -r 2a8eaba24bf0 extras/mini-os/include/fbfront.h --- a/extras/mini-os/include/fbfront.h Tue Feb 26 15:11:51 2008 +0000 +++ b/extras/mini-os/include/fbfront.h Wed Feb 27 18:30:05 2008 +0000 @@ -14,6 +14,9 @@ #ifndef KEY_Q #define KEY_Q 16 #endif +#ifndef KEY_MAX +#define KEY_MAX 0x1ff +#endif struct kbdfront_dev; diff -r 2a8eaba24bf0 stubdom/README --- a/stubdom/README Tue Feb 26 15:11:51 2008 +0000 +++ b/stubdom/README Wed Feb 27 18:30:05 2008 +0000 @@ -6,6 +6,73 @@ Then make install to install the result. Also, run make and make install in $XEN_ROOT/tools/fs-back +General Configuration +===================== + +In your HVM config "hvmconfig", + +- use /usr/lib/xen/bin/stubdom-dm as dm script + +device_model = '/usr/lib/xen/bin/stubdom-dm' + +- comment the disk statement: + +#disk = [ 'file:/tmp/install.iso,hdc:cdrom,r', 'phy:/dev/sda6,hda,w', 'file:/tmp/test,hdb,r' ] + + +Create /etc/xen/stubdom-hvmconfig (where "hvmconfig" is the name of your HVM +guest) with + +kernel = "/usr/lib/xen/boot/stubdom.gz" +vif = [ '', 'ip=10.0.1.1,mac=aa:00:00:12:23:34'] +disk = [ 'file:/tmp/install.iso,hdc:cdrom,r', 'phy:/dev/sda6,hda,w', 'file:/tmp/test,hdb,r' ] + +where +- the first vif ('') is reserved for VNC (see below) +- 'ip=10.0.1.1,mac= etc...' is the same net configuration as in the hvmconfig +script, +- and disk = is the same block configuration as in the hvmconfig script. + +Display Configuration +===================== + +There are three posibilities + +* Using SDL + +In hvmconfig, disable vnc: + +vnc = 0 + +In stubdom-hvmconfig, set a vfb: + +vfb = [ 'type=sdl' ] + +* Using a VNC server in the stub domain + +In hvmconfig, set vnclisten to "172.30.206.1" for instance. Do not use a host +name as Mini-OS does not have a name resolver. Do not use 127.0.0.1 since then +you will not be able to connect to it. + +vnc = 1 +vnclisten = "172.30.206.1" + +In stubdom-hvmconfig, fill the reserved vif with the same IP, for instance: + +vif = [ 'ip=172.30.206.1', 'ip=10.0.1.1,mac=aa:00:00:12:23:34'] + +* Using a VNC server in dom0 + +In hvmconfig, disable vnc: + +vnc = 0 + +In stubdom-hvmconfig, set a vfb: + +vfb = [ 'type=vnc' ] + +and any other parameter as wished. + To run ====== @@ -13,32 +80,4 @@ ln -s /usr/share/qemu/keymaps /exports/u ln -s /usr/share/qemu/keymaps /exports/usr/share/qemu /usr/sbin/fs-backend & - -In your HVM config "hvmconfig", - -- use VNC, set vnclisten to "172.30.206.1" for instance. Do not use a host name -as Mini-OS does not have a name resolver. Do not use 127.0.0.1 since then you -will not be able to connect to it. - -vnc = 1 -vnclisten = "172.30.206.1" - -- use /usr/lib/xen/bin/stubdom-dm as dm script - -device_model = '/usr/lib/xen/bin/stubdom-dm' - -- comment the disk statement: -#disk = [ 'file:/tmp/install.iso,hdc:cdrom,r', 'phy:/dev/sda6,hda,w', 'file:/tmp/test,hdb,r' ] - -Create /etc/xen/stubdom-hvmconfig (where "hvmconfig" is your HVM guest domain -name) with - -kernel = "/usr/lib/xen/boot/stubdom.gz" -vif = [ 'ip=172.30.206.1', 'ip=10.0.1.1,mac=aa:00:00:12:23:34'] -disk = [ 'file:/tmp/install.iso,hdc:cdrom,r', 'phy:/dev/sda6,hda,w', 'file:/tmp/test,hdb,r' ] - -where -- 172.30.206.1 is the IP for vnc, -- 'ip=10.0.1.1,mac= etc...' is the same net configuration as in the hvmconfig -script, -- and disk = is the same block configuration as in the hvmconfig script. +xm create hvmconfig diff -r 2a8eaba24bf0 tools/ioemu/hw/xenfb.c --- a/tools/ioemu/hw/xenfb.c Tue Feb 26 15:11:51 2008 +0000 +++ b/tools/ioemu/hw/xenfb.c Wed Feb 27 18:30:05 2008 +0000 @@ -18,6 +18,12 @@ #include #include "xenfb.h" + +#ifdef CONFIG_STUBDOM +#include +#include +#include +#endif #ifndef BTN_LEFT #define BTN_LEFT 0x110 /* from */ @@ -1124,12 +1130,10 @@ static void xenfb_guest_copy(struct xenf dpy_update(xenfb->ds, x, y, w, h); } -/* QEMU display state changed, so refresh the framebuffer copy */ -/* XXX - can we optimize this, or the next func at all ? */ +/* Periodic update of display, no need for any in our case */ static void xenfb_update(void *opaque) { struct xenfb *xenfb = opaque; - xenfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height); } /* QEMU display state changed, so refresh the framebuffer copy */ @@ -1169,6 +1173,206 @@ static int xenfb_register_console(struct return 0; } +#ifdef CONFIG_STUBDOM +static struct semaphore kbd_sem = __SEMAPHORE_INITIALIZER(kbd_sem, 0); +static struct kbdfront_dev *kbd_dev; +static char *kbd_path, *fb_path; + +static unsigned char linux2scancode[KEY_MAX + 1]; + +#define WIDTH 1024 +#define HEIGHT 768 +#define DEPTH 32 +#define LINESIZE (1280 * (DEPTH / 8)) +#define MEMSIZE (LINESIZE * HEIGHT) + +int xenfb_connect_vkbd(const char *path) +{ + kbd_path = strdup(path); + return 0; +} + +int xenfb_connect_vfb(const char *path) +{ + fb_path = strdup(path); + return 0; +} + +static void xenfb_pv_update(DisplayState *s, int x, int y, int w, int h) +{ + struct fbfront_dev *fb_dev = s->opaque; + fbfront_update(fb_dev, x, y, w, h); +} + +static void xenfb_pv_resize(DisplayState *s, int w, int h) +{ + struct fbfront_dev *fb_dev = s->opaque; + fprintf(stderr,"resize to %dx%d required\n", w, h); + s->width = w; + s->height = h; + /* TODO: send resize event if supported */ + memset(s->data, 0, MEMSIZE); + fbfront_update(fb_dev, 0, 0, WIDTH, HEIGHT); +} + +static void xenfb_pv_colourdepth(DisplayState *s, int depth) +{ + /* TODO: send redepth event if supported */ + fprintf(stderr,"redepth to %d required\n", depth); +} + +static void xenfb_kbd_handler(void *opaque) +{ +#define KBD_NUM_BATCH 64 + union xenkbd_in_event buf[KBD_NUM_BATCH]; + int n, i; + DisplayState *s = opaque; + static int buttons; + static int x, y, z; + + n = kbdfront_receive(kbd_dev, buf, KBD_NUM_BATCH); + for (i = 0; i < n; i++) { + switch (buf[i].type) { + + case XENKBD_TYPE_MOTION: + fprintf(stderr, "FB backend sent us relative mouse motion event!\n"); + break; + + case XENKBD_TYPE_POS: + { + int new_x = buf[i].pos.abs_x; + int new_y = buf[i].pos.abs_y; + int new_z = buf[i].pos.abs_z; + if (new_x >= s->width) + new_x = s->width - 1; + if (new_y >= s->height) + new_y = s->height - 1; + if (kbd_mouse_is_absolute()) { + kbd_mouse_event( + new_x * 0x7FFF / (s->width - 1), + new_y * 0x7FFF / (s->height - 1), + new_z, + buttons); + } else { + kbd_mouse_event( + new_x - x, + new_y - y, + new_z - z, + buttons); + } + x = new_x; + y = new_y; + z = new_z; + break; + } + + case XENKBD_TYPE_KEY: + { + int keycode = buf[i].key.keycode; + int button = 0; + + if (keycode == BTN_LEFT) + button = MOUSE_EVENT_LBUTTON; + else if (keycode == BTN_RIGHT) + button = MOUSE_EVENT_RBUTTON; + else if (keycode == BTN_MIDDLE) + button = MOUSE_EVENT_MBUTTON; + + if (button) { + if (buf[i].key.pressed) + buttons |= button; + else + buttons &= ~button; + if (kbd_mouse_is_absolute()) + kbd_mouse_event( + x * 0x7FFF / s->width, + y * 0x7FFF / s->height, + z, + buttons); + else + kbd_mouse_event(0, 0, 0, buttons); + } else { + int scancode = linux2scancode[keycode]; + if (!scancode) { + fprintf(stderr, "Can't convert keycode %x to scancode\n", keycode); + break; + } + if (scancode & 0x80) { + kbd_put_keycode(0xe0); + scancode &= 0x7f; + } + if (!buf[i].key.pressed) + scancode |= 0x80; + kbd_put_keycode(scancode); + } + break; + } + } + } +} + +static void xenfb_pv_refresh(DisplayState *ds) +{ + vga_hw_update(); +} + +static void kbdfront_thread(void *p) +{ + int scancode, keycode; + kbd_dev = init_kbdfront(p, 1); + if (!kbd_dev) { + fprintf(stderr,"can't open keyboard\n"); + exit(1); + } + up(&kbd_sem); + for (scancode = 0; scancode < 128; scancode++) { + keycode = atkbd_set2_keycode[atkbd_unxlate_table[scancode]]; + linux2scancode[keycode] = scancode; + keycode = atkbd_set2_keycode[atkbd_unxlate_table[scancode] | 0x80]; + linux2scancode[keycode] = scancode | 0x80; + } +} + +int xenfb_pv_display_init(DisplayState *ds) +{ + void *data; + struct fbfront_dev *fb_dev; + int kbd_fd; + + if (!fb_path || !kbd_path) + return -1; + + create_thread("kbdfront", kbdfront_thread, (void*) kbd_path); + + data = qemu_memalign(PAGE_SIZE, VGA_RAM_SIZE); + fb_dev = init_fbfront(fb_path, data, WIDTH, HEIGHT, DEPTH, LINESIZE, MEMSIZE); + if (!fb_dev) { + fprintf(stderr,"can't open frame buffer\n"); + exit(1); + } + free(fb_path); + + down(&kbd_sem); + free(kbd_path); + + kbd_fd = kbdfront_open(kbd_dev); + qemu_set_fd_handler(kbd_fd, xenfb_kbd_handler, NULL, ds); + + ds->data = data; + ds->linesize = LINESIZE; + ds->depth = DEPTH; + ds->bgr = 0; + ds->width = WIDTH; + ds->height = HEIGHT; + ds->dpy_update = xenfb_pv_update; + ds->dpy_resize = xenfb_pv_resize; + ds->dpy_colourdepth = NULL; //xenfb_pv_colourdepth; + ds->dpy_refresh = xenfb_pv_refresh; + ds->opaque = fb_dev; + return 0; +} +#endif + /* * Local variables: * c-indent-level: 8 diff -r 2a8eaba24bf0 tools/ioemu/vl.c --- a/tools/ioemu/vl.c Tue Feb 26 15:11:51 2008 +0000 +++ b/tools/ioemu/vl.c Wed Feb 27 18:30:05 2008 +0000 @@ -7831,6 +7831,10 @@ int main(int argc, char **argv) init_ioports(); /* terminal init */ +#ifdef CONFIG_STUBDOM + if (xenfb_pv_display_init(ds) == 0) { + } else +#endif if (nographic) { dumb_display_init(ds); } else if (vnc_display != NULL || vncunused != 0) { diff -r 2a8eaba24bf0 tools/ioemu/vl.h --- a/tools/ioemu/vl.h Tue Feb 26 15:11:51 2008 +0000 +++ b/tools/ioemu/vl.h Wed Feb 27 18:30:05 2008 +0000 @@ -1525,6 +1525,11 @@ int xenstore_vm_write(int domid, char *k int xenstore_vm_write(int domid, char *key, char *val); char *xenstore_vm_read(int domid, char *key, unsigned int *len); +/* xenfb.c */ +int xenfb_pv_display_init(DisplayState *ds); +int xenfb_connect_vkbd(const char *path); +int xenfb_connect_vfb(const char *path); + /* helper2.c */ extern long time_offset; void timeoffset_get(void); diff -r 2a8eaba24bf0 tools/ioemu/xenstore.c --- a/tools/ioemu/xenstore.c Tue Feb 26 15:11:51 2008 +0000 +++ b/tools/ioemu/xenstore.c Wed Feb 27 18:30:05 2008 +0000 @@ -238,6 +238,37 @@ void xenstore_parse_domain_config(int do } } +#ifdef CONFIG_STUBDOM + if (pasprintf(&buf, "%s/device/vkbd", path) == -1) + goto out; + + free(e); + e = xs_directory(xsh, XBT_NULL, buf, &num); + + if (e) { + for (i = 0; i < num; i++) { + if (pasprintf(&buf, "%s/device/vkbd/%s", path, e[i]) == -1) + continue; + xenfb_connect_vkbd(buf); + } + } + + if (pasprintf(&buf, "%s/device/vfb", path) == -1) + goto out; + + free(e); + e = xs_directory(xsh, XBT_NULL, buf, &num); + + if (e) { + for (i = 0; i < num; i++) { + if (pasprintf(&buf, "%s/device/vfb/%s", path, e[i]) == -1) + continue; + xenfb_connect_vfb(buf); + } + } +#endif + + /* Set a watch for log-dirty requests from the migration tools */ if (pasprintf(&buf, "/local/domain/0/device-model/%u/logdirty/next-active", domid) != -1) {