* [Qemu-devel] [PATCH] VNC display support for QEMU
@ 2006-04-29 21:34 Anthony Liguori
2006-04-30 1:03 ` Johannes Schindelin
` (2 more replies)
0 siblings, 3 replies; 14+ messages in thread
From: Anthony Liguori @ 2006-04-29 21:34 UTC (permalink / raw)
To: qemu-devel
[-- Attachment #1: Type: text/plain, Size: 1666 bytes --]
Hi,
The attach patch adds VNC display support for QEMU. It does not use
libvncserver but was rather written from scratch. libvncserver is a
really neat project and I've used it in a number of other projects but I
think QEMU really requires a custom implementation.
First, to enable vnc support, you use the -vnc option like:
qemu -vnc 1
Where 1 is the first display (port 5901). This syntax may change in the
near future to support binding to a particular interface. It's very
useful to use an absolute mouse with VNC as the relative support is
quite poor. It may be useful to adapt the libvncserver patch's
calibration code here but I've not attempted to do that yet.
This patch is still experimental. I've tested it with RealVNC and
TightVNC under a variety of depths but I won't be suprised if there are
still problems. I only implement Raw, CopyRect, and Hextile encodings
too. Any sort of palette color mode or pixel format that QEMU doesn't
support will not work either.
One thing you may notice is that RealVNC has some issues with being
disconnected. This is because it likes to switch from 8bit to 32bit
depths automatically at startup. Unfortunately, there is a race
condition in the VNC protocol and since this implementation is
asynchronous, we seem to be much more prone to exposing this.
A short near-term TODO list is:
1) More testing
2) Support switching between monitor/serial
3) Support a better encoding (like TightEncoding or ZRLE)
4) Support a vnc password (and perhaps stuff like TLS)
Any feedback is greatly appreciated (especially with how it works with
clients I've not tested).
Regards,
Anthony Liguori
[-- Attachment #2: qemu-vnc.diff --]
[-- Type: text/plain, Size: 43361 bytes --]
diff -urN -x '*.[di]' a.hg/hw/cirrus_vga.c vnc.hg/hw/cirrus_vga.c
--- a.hg/hw/cirrus_vga.c 2006-04-29 16:01:36.000000000 -0500
+++ vnc.hg/hw/cirrus_vga.c 2006-04-29 16:18:46.000000000 -0500
@@ -644,15 +644,90 @@
(s->cirrus_blt_srcaddr & ~7));
}
-static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s)
+static void cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
{
+ int sx, sy;
+ int dx, dy;
+ int width, height;
+ int depth;
+ int notify = 0;
+
+ depth = s->get_bpp((VGAState *)s) / 8;
+ s->get_resolution((VGAState *)s, &width, &height);
+
+ /* extra x, y */
+ sx = (src % (width * depth)) / depth;
+ sy = (src / (width * depth));
+ dx = (dst % (width *depth)) / depth;
+ dy = (dst / (width * depth));
+
+ /* normalize width */
+ w /= depth;
+
+ /* if we're doing a backward copy, we have to adjust
+ our x/y to be the upper left corner (instead of the lower
+ right corner) */
+ if (s->cirrus_blt_dstpitch < 0) {
+ sx -= (s->cirrus_blt_width / depth) - 1;
+ dx -= (s->cirrus_blt_width / depth) - 1;
+ sy -= s->cirrus_blt_height - 1;
+ dy -= s->cirrus_blt_height - 1;
+ }
+
+ /* are we in the visible portion of memory? */
+ if (sx >= 0 && sy >= 0 && dx >= 0 && dy >= 0 &&
+ (sx + w) <= width && (sy + h) <= height &&
+ (dx + w) <= width && (dy + h) <= height) {
+ notify = 1;
+ }
+
+ /* make to sure only copy if it's a plain copy ROP */
+ if (*s->cirrus_rop != cirrus_bitblt_rop_fwd_src &&
+ *s->cirrus_rop != cirrus_bitblt_rop_bkwd_src)
+ notify = 0;
+
+ /* we have to flush all pending changes so that the copy
+ is generated at the appropriate moment in time */
+ if (notify)
+ vga_hw_update();
+
(*s->cirrus_rop) (s, s->vram_ptr + s->cirrus_blt_dstaddr,
s->vram_ptr + s->cirrus_blt_srcaddr,
s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch,
s->cirrus_blt_width, s->cirrus_blt_height);
- cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
- s->cirrus_blt_dstpitch, s->cirrus_blt_width,
- s->cirrus_blt_height);
+
+ if (notify)
+ s->ds->dpy_copy(s->ds,
+ sx, sy, dx, dy,
+ s->cirrus_blt_width / depth,
+ s->cirrus_blt_height);
+
+ /* we don't have to notify the display that this portion has
+ changed since dpy_copy implies this */
+
+ if (!notify)
+ cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
+ s->cirrus_blt_dstpitch, s->cirrus_blt_width,
+ s->cirrus_blt_height);
+}
+
+static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s)
+{
+ if (s->ds->dpy_copy) {
+ cirrus_do_copy(s, s->cirrus_blt_dstaddr - s->start_addr,
+ s->cirrus_blt_srcaddr - s->start_addr,
+ s->cirrus_blt_width, s->cirrus_blt_height);
+ } else {
+ (*s->cirrus_rop) (s, s->vram_ptr + s->cirrus_blt_dstaddr,
+ s->vram_ptr + s->cirrus_blt_srcaddr,
+ s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch,
+ s->cirrus_blt_width, s->cirrus_blt_height);
+
+ cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
+ s->cirrus_blt_dstpitch, s->cirrus_blt_width,
+ s->cirrus_blt_height);
+ }
+
return 1;
}
diff -urN -x '*.[di]' a.hg/Makefile.target vnc.hg/Makefile.target
--- a.hg/Makefile.target 2006-04-29 16:01:34.000000000 -0500
+++ vnc.hg/Makefile.target 2006-04-29 16:20:17.000000000 -0500
@@ -357,6 +357,7 @@
ifdef CONFIG_SDL
VL_OBJS+=sdl.o
endif
+VL_OBJS+=vnc.o
ifdef CONFIG_COCOA
VL_OBJS+=cocoa.o
COCOA_LIBS=-F/System/Library/Frameworks -framework Cocoa -framework IOKit
@@ -409,6 +410,9 @@
sdl.o: sdl.c keymaps.c sdl_keysym.h
$(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
+vnc.o: vnc.c keymaps.c sdl_keysym.h vnchextile.h
+ $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
+
sdlaudio.o: sdlaudio.c
$(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
diff -urN -x '*.[di]' a.hg/qemu-doc.texi vnc.hg/qemu-doc.texi
--- a.hg/qemu-doc.texi 2006-04-29 16:01:38.000000000 -0500
+++ vnc.hg/qemu-doc.texi 2006-04-29 15:55:58.000000000 -0500
@@ -185,6 +185,13 @@
the console. Therefore, you can still use QEMU to debug a Linux kernel
with a serial console.
+@item -vnc d
+
+Normally, QEMU uses SDL to display the VGA output. With this option,
+you can have QEMU listen on VNC display d and redirect the VGA display
+over the VNC session. It is very useful to enable the usb tablet device
+when using this option.
+
@item -k language
Use keyboard layout @var{language} (for example @code{fr} for
diff -urN -x '*.[di]' a.hg/vl.c vnc.hg/vl.c
--- a.hg/vl.c 2006-04-29 16:01:43.000000000 -0500
+++ vnc.hg/vl.c 2006-04-27 23:44:41.000000000 -0500
@@ -149,6 +149,7 @@
USBDevice *vm_usb_hub;
static VLANState *first_vlan;
int smp_cpus = 1;
+int vnc_display = -1;
#if defined(TARGET_SPARC)
#define MAX_CPUS 16
#elif defined(TARGET_I386)
@@ -4638,6 +4639,7 @@
" (default is CL-GD5446 PCI VGA)\n"
#endif
"-loadvm file start right away with a saved state (loadvm in monitor)\n"
+ "-vnc display start a VNC server on display\n"
"\n"
"During emulation, the following keys are useful:\n"
"ctrl-alt-f toggle full screen\n"
@@ -4721,6 +4723,7 @@
QEMU_OPTION_usb,
QEMU_OPTION_usbdevice,
QEMU_OPTION_smp,
+ QEMU_OPTION_vnc,
};
typedef struct QEMUOption {
@@ -4788,6 +4791,7 @@
{ "win2k-hack", 0, QEMU_OPTION_win2k_hack },
{ "usbdevice", HAS_ARG, QEMU_OPTION_usbdevice },
{ "smp", HAS_ARG, QEMU_OPTION_smp },
+ { "vnc", HAS_ARG, QEMU_OPTION_vnc },
/* temporary options */
{ "usb", 0, QEMU_OPTION_usb },
@@ -5386,6 +5390,13 @@
exit(1);
}
break;
+ case QEMU_OPTION_vnc:
+ vnc_display = atoi(optarg);
+ if (vnc_display < 0) {
+ fprintf(stderr, "Invalid VNC display\n");
+ exit(1);
+ }
+ break;
}
}
}
@@ -5551,6 +5562,8 @@
/* terminal init */
if (nographic) {
dumb_display_init(ds);
+ } if (vnc_display != -1) {
+ vnc_display_init(ds, vnc_display);
} else {
#if defined(CONFIG_SDL)
sdl_display_init(ds, full_screen);
diff -urN -x '*.[di]' a.hg/vl.h vnc.hg/vl.h
--- a.hg/vl.h 2006-04-29 16:01:43.000000000 -0500
+++ vnc.hg/vl.h 2006-04-29 15:17:16.000000000 -0500
@@ -82,6 +82,13 @@
#define tostring(s) #s
#endif
+#ifndef MIN
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#endif
+#ifndef MAX
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+#endif
+
/* vl.c */
uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c);
@@ -672,9 +679,12 @@
int depth;
int width;
int height;
+ void *opaque;
+
void (*dpy_update)(struct DisplayState *s, int x, int y, int w, int h);
void (*dpy_resize)(struct DisplayState *s, int w, int h);
void (*dpy_refresh)(struct DisplayState *s);
+ void (*dpy_copy)(struct DisplayState *s, int src_x, int src_y, int dst_x, int dst_y, int w, int h);
};
static inline void dpy_update(DisplayState *s, int x, int y, int w, int h)
@@ -703,6 +713,9 @@
/* cocoa.m */
void cocoa_display_init(DisplayState *ds, int full_screen);
+/* vnc.c */
+void vnc_display_init(DisplayState *ds, int display);
+
/* ide.c */
#define MAX_DISKS 4
diff -urN -x '*.[di]' a.hg/vnc.c vnc.hg/vnc.c
--- a.hg/vnc.c 1969-12-31 18:00:00.000000000 -0600
+++ vnc.hg/vnc.c 2006-04-29 16:15:02.000000000 -0500
@@ -0,0 +1,894 @@
+#include "vl.h"
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <fcntl.h>
+
+#define VNC_REFRESH_INTERVAL (1000 / 30)
+
+#include "vnc_keysym.h"
+#include "keymaps.c"
+
+typedef struct Buffer
+{
+ size_t capacity;
+ size_t offset;
+ char *buffer;
+} Buffer;
+
+typedef struct VncState VncState;
+
+typedef int VncReadEvent(VncState *vs, char *data, size_t len);
+
+struct VncState
+{
+ QEMUTimer *timer;
+ int lsock;
+ int csock;
+ DisplayState *ds;
+ int need_update;
+ int width;
+ int height;
+ uint64_t dirty_row[768];
+ char *old_data;
+ int depth;
+ int has_resize;
+ int has_hextile;
+ Buffer output;
+ Buffer input;
+ kbd_layout_t *kbd_layout;
+
+ VncReadEvent *read_handler;
+ size_t read_handler_expect;
+};
+
+/* TODO
+ 1) Get the queue working for IO.
+ 2) there is some weirdness when using the -S option (the screen is grey
+ and not totally invalidated
+ 3) resolutions > 1024
+*/
+
+static void vnc_write(VncState *vs, const void *data, size_t len);
+static void vnc_write_u32(VncState *vs, uint32_t value);
+static void vnc_write_s32(VncState *vs, int32_t value);
+static void vnc_write_u16(VncState *vs, uint16_t value);
+static void vnc_write_u8(VncState *vs, uint8_t value);
+static void vnc_flush(VncState *vs);
+static void vnc_update_client(void *opaque);
+static void vnc_client_read(void *opaque);
+
+static void vnc_dpy_update(DisplayState *ds, int x, int y, int w, int h)
+{
+ VncState *vs = ds->opaque;
+ int i;
+
+ h += y;
+
+ for (; y < h; y++)
+ for (i = 0; i < w; i += 16)
+ vs->dirty_row[y] |= (1ULL << ((x + i) / 16));
+}
+
+static void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
+ int32_t encoding)
+{
+ vnc_write_u16(vs, x);
+ vnc_write_u16(vs, y);
+ vnc_write_u16(vs, w);
+ vnc_write_u16(vs, h);
+
+ vnc_write_s32(vs, encoding);
+}
+
+static void vnc_dpy_resize(DisplayState *ds, int w, int h)
+{
+ VncState *vs = ds->opaque;
+
+ ds->data = realloc(ds->data, w * h * vs->depth);
+ vs->old_data = realloc(vs->old_data, w * h * vs->depth);
+
+ if (ds->data == NULL || vs->old_data == NULL) {
+ fprintf(stderr, "vnc: memory allocation failed\n");
+ exit(1);
+ }
+
+ ds->depth = vs->depth * 8;
+ ds->width = w;
+ ds->height = h;
+ ds->linesize = w * vs->depth;
+ if (vs->csock != -1 && vs->has_resize) {
+ vnc_write_u8(vs, 0); /* msg id */
+ vnc_write_u8(vs, 0);
+ vnc_write_u16(vs, 1); /* number of rects */
+ vnc_framebuffer_update(vs, 0, 0, ds->width, ds->height, -223);
+ vnc_flush(vs);
+ vs->width = ds->width;
+ vs->height = ds->height;
+ }
+}
+
+static void send_framebuffer_update_raw(VncState *vs, int x, int y, int w, int h)
+{
+ int i;
+ char *row;
+
+ vnc_framebuffer_update(vs, x, y, w, h, 0);
+
+ row = vs->ds->data + y * vs->ds->linesize + x * vs->depth;
+ for (i = 0; i < h; i++) {
+ vnc_write(vs, row, w * vs->depth);
+ row += vs->ds->linesize;
+ }
+}
+
+static void hextile_enc_cord(uint8_t *ptr, int x, int y, int w, int h)
+{
+ ptr[0] = ((x & 0x0F) << 4) | (y & 0x0F);
+ ptr[1] = (((w - 1) & 0x0F) << 4) | ((h - 1) & 0x0F);
+}
+
+#define BPP 8
+#include "vnchextile.h"
+#undef BPP
+
+#define BPP 16
+#include "vnchextile.h"
+#undef BPP
+
+#define BPP 32
+#include "vnchextile.h"
+#undef BPP
+
+static void send_framebuffer_update_hextile(VncState *vs, int x, int y, int w, int h)
+{
+ int i, j;
+ int has_fg, has_bg;
+ uint32_t last_fg32, last_bg32;
+ uint16_t last_fg16, last_bg16;
+ uint8_t last_fg8, last_bg8;
+
+ vnc_framebuffer_update(vs, x, y, w, h, 5);
+
+ has_fg = has_bg = 0;
+ for (j = y; j < (y + h); j += 16) {
+ for (i = x; i < (x + w); i += 16) {
+ switch (vs->depth) {
+ case 1:
+ send_hextile_tile_8(vs, i, j, MIN(16, x + w - i), MIN(16, y + h - j),
+ &last_bg8, &last_fg8, &has_bg, &has_fg);
+ break;
+ case 2:
+ send_hextile_tile_16(vs, i, j, MIN(16, x + w - i), MIN(16, y + h - j),
+ &last_bg16, &last_fg16, &has_bg, &has_fg);
+ break;
+ case 4:
+ send_hextile_tile_32(vs, i, j, MIN(16, x + w - i), MIN(16, y + h - j),
+ &last_bg32, &last_fg32, &has_bg, &has_fg);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
+
+static void send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
+{
+ if (vs->has_hextile)
+ send_framebuffer_update_hextile(vs, x, y, w, h);
+ else
+ send_framebuffer_update_raw(vs, x, y, w, h);
+}
+
+static void vnc_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int dst_y, int w, int h)
+{
+ int src, dst;
+ char *src_row;
+ char *dst_row;
+ char *old_row;
+ int y = 0;
+ int pitch = ds->linesize;
+ VncState *vs = ds->opaque;
+
+ vnc_update_client(vs);
+
+ if (dst_y > src_y) {
+ y = h - 1;
+ pitch = -pitch;
+ }
+
+ src = (ds->linesize * (src_y + y) + vs->depth * src_x);
+ dst = (ds->linesize * (dst_y + y) + vs->depth * dst_x);
+
+ src_row = ds->data + src;
+ dst_row = ds->data + dst;
+ old_row = vs->old_data + dst;
+
+ for (y = 0; y < h; y++) {
+ memmove(old_row, src_row, w * vs->depth);
+ memmove(dst_row, src_row, w * vs->depth);
+ src_row += pitch;
+ dst_row += pitch;
+ old_row += pitch;
+ }
+
+ vnc_write_u8(vs, 0); /* msg id */
+ vnc_write_u8(vs, 0);
+ vnc_write_u16(vs, 1); /* number of rects */
+ vnc_framebuffer_update(vs, dst_x, dst_y, w, h, 1);
+ vnc_write_u16(vs, src_x);
+ vnc_write_u16(vs, src_y);
+ vnc_flush(vs);
+}
+
+static int find_dirty_height(VncState *vs, int y, int last_x, int x)
+{
+ int h;
+
+ for (h = 1; h < (vs->height - y); h++) {
+ int tmp_x;
+ if (!(vs->dirty_row[y + h] & (1ULL << last_x)))
+ break;
+ for (tmp_x = last_x; tmp_x < x; tmp_x++)
+ vs->dirty_row[y + h] &= ~(1ULL << tmp_x);
+ }
+
+ return h;
+}
+
+static void vnc_update_client(void *opaque)
+{
+ VncState *vs = opaque;
+
+ if (vs->need_update && vs->csock != -1) {
+ int y;
+ char *row;
+ char *old_row;
+ uint64_t width_mask;
+ int n_rectangles;
+ int saved_offset;
+ int has_dirty = 0;
+
+ width_mask = (1ULL << (vs->width / 16)) - 1;
+
+ if (vs->width == 1024)
+ width_mask = ~(0ULL);
+
+ /* Walk through the dirty map and eliminate tiles that
+ really aren't dirty */
+ row = vs->ds->data;
+ old_row = vs->old_data;
+
+ for (y = 0; y < vs->height; y++) {
+ if (vs->dirty_row[y] & width_mask) {
+ int x;
+ char *ptr, *old_ptr;
+
+ ptr = row;
+ old_ptr = old_row;
+
+ for (x = 0; x < vs->ds->width; x += 16) {
+ if (memcmp(old_ptr, ptr, 16 * vs->depth) == 0) {
+ vs->dirty_row[y] &= ~(1ULL << (x / 16));
+ } else {
+ has_dirty = 1;
+ memcpy(old_ptr, ptr, 16 * vs->depth);
+ }
+
+ ptr += 16 * vs->depth;
+ old_ptr += 16 * vs->depth;
+ }
+ }
+
+ row += vs->ds->linesize;
+ old_row += vs->ds->linesize;
+ }
+
+ if (!has_dirty) {
+ qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock) + VNC_REFRESH_INTERVAL);
+ return;
+ }
+
+ /* Count rectangles */
+ n_rectangles = 0;
+ vnc_write_u8(vs, 0); /* msg id */
+ vnc_write_u8(vs, 0);
+ saved_offset = vs->output.offset;
+ vnc_write_u16(vs, 0);
+
+ for (y = 0; y < vs->height; y++) {
+ int x;
+ int last_x = -1;
+ for (x = 0; x < vs->width / 16; x++) {
+ if (vs->dirty_row[y] & (1ULL << x)) {
+ if (last_x == -1) {
+ last_x = x;
+ }
+ vs->dirty_row[y] &= ~(1ULL << x);
+ } else {
+ if (last_x != -1) {
+ int h = find_dirty_height(vs, y, last_x, x);
+ send_framebuffer_update(vs, last_x * 16, y, (x - last_x) * 16, h);
+ n_rectangles++;
+ }
+ last_x = -1;
+ }
+ }
+ if (last_x != -1) {
+ int h = find_dirty_height(vs, y, last_x, x);
+ send_framebuffer_update(vs, last_x * 16, y, (x - last_x) * 16, h);
+ n_rectangles++;
+ }
+ }
+ vs->output.buffer[saved_offset] = (n_rectangles >> 8) & 0xFF;
+ vs->output.buffer[saved_offset + 1] = n_rectangles & 0xFF;
+ vnc_flush(vs);
+
+ }
+ qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock) + VNC_REFRESH_INTERVAL);
+}
+
+static void vnc_timer_init(VncState *vs)
+{
+ if (vs->timer == NULL) {
+ vs->timer = qemu_new_timer(rt_clock, vnc_update_client, vs);
+ qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock));
+ }
+}
+
+static void vnc_dpy_refresh(DisplayState *ds)
+{
+ VncState *vs = ds->opaque;
+ vnc_timer_init(vs);
+ vga_hw_update();
+}
+
+static int vnc_listen_poll(void *opaque)
+{
+ VncState *vs = opaque;
+ if (vs->csock == -1)
+ return 1;
+ return 0;
+}
+
+static void buffer_reserve(Buffer *buffer, size_t len)
+{
+ if ((buffer->capacity - buffer->offset) < len) {
+ buffer->capacity += (len + 1024);
+ buffer->buffer = realloc(buffer->buffer, buffer->capacity);
+ if (buffer->buffer == NULL) {
+ fprintf(stderr, "vnc: out of memory\n");
+ exit(1);
+ }
+ }
+}
+
+static int buffer_empty(Buffer *buffer)
+{
+ return buffer->offset == 0;
+}
+
+static char *buffer_end(Buffer *buffer)
+{
+ return buffer->buffer + buffer->offset;
+}
+
+static void buffer_reset(Buffer *buffer)
+{
+ buffer->offset = 0;
+}
+
+static void buffer_append(Buffer *buffer, const void *data, size_t len)
+{
+ memcpy(buffer->buffer + buffer->offset, data, len);
+ buffer->offset += len;
+}
+
+static int vnc_client_io_error(VncState *vs, int ret)
+{
+ if (ret == 0 || ret == -1) {
+ if (ret == -1 && (errno == EINTR || errno == EAGAIN))
+ return 0;
+
+ qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL);
+ close(vs->csock);
+ vs->csock = -1;
+ buffer_reset(&vs->input);
+ buffer_reset(&vs->output);
+ vs->need_update = 0;
+ return 0;
+ }
+ return ret;
+}
+
+static void vnc_client_error(VncState *vs)
+{
+ errno = EINVAL;
+ vnc_client_io_error(vs, -1);
+}
+
+static void vnc_client_write(void *opaque)
+{
+ ssize_t ret;
+ VncState *vs = opaque;
+
+ ret = write(vs->csock, vs->output.buffer, vs->output.offset);
+ ret = vnc_client_io_error(vs, ret);
+ if (!ret)
+ return;
+
+ memmove(vs->output.buffer, vs->output.buffer + ret, (vs->output.offset - ret));
+ vs->output.offset -= ret;
+
+ if (vs->output.offset == 0) {
+ qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
+ }
+}
+
+static void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting)
+{
+ vs->read_handler = func;
+ vs->read_handler_expect = expecting;
+}
+
+static void vnc_client_read(void *opaque)
+{
+ VncState *vs = opaque;
+ ssize_t ret;
+
+ buffer_reserve(&vs->input, 4096);
+
+ ret = read(vs->csock, buffer_end(&vs->input), 4096);
+ ret = vnc_client_io_error(vs, ret);
+ if (!ret)
+ return;
+
+ vs->input.offset += ret;
+
+ while (vs->read_handler && vs->input.offset >= vs->read_handler_expect) {
+ size_t len = vs->read_handler_expect;
+ int ret;
+
+ ret = vs->read_handler(vs, vs->input.buffer, len);
+ if (vs->csock == -1)
+ return;
+
+ if (!ret) {
+ memmove(vs->input.buffer, vs->input.buffer + len, (vs->input.offset - len));
+ vs->input.offset -= len;
+ } else {
+ vs->read_handler_expect = ret;
+ }
+ }
+}
+
+static void vnc_write(VncState *vs, const void *data, size_t len)
+{
+ buffer_reserve(&vs->output, len);
+
+ if (buffer_empty(&vs->output)) {
+ qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs);
+ }
+
+ buffer_append(&vs->output, data, len);
+}
+
+static void vnc_write_s32(VncState *vs, int32_t value)
+{
+ vnc_write_u32(vs, *(uint32_t *)&value);
+}
+
+static void vnc_write_u32(VncState *vs, uint32_t value)
+{
+ uint8_t buf[4];
+
+ buf[0] = (value >> 24) & 0xFF;
+ buf[1] = (value >> 16) & 0xFF;
+ buf[2] = (value >> 8) & 0xFF;
+ buf[3] = value & 0xFF;
+
+ vnc_write(vs, buf, 4);
+}
+
+static void vnc_write_u16(VncState *vs, uint16_t value)
+{
+ char buf[2];
+
+ buf[0] = (value >> 8) & 0xFF;
+ buf[1] = value & 0xFF;
+
+ vnc_write(vs, buf, 2);
+}
+
+static void vnc_write_u8(VncState *vs, uint8_t value)
+{
+ vnc_write(vs, (char *)&value, 1);
+}
+
+static void vnc_flush(VncState *vs)
+{
+ if (vs->output.offset)
+ vnc_client_write(vs);
+}
+
+static uint8_t read_u8(char *data, size_t offset)
+{
+ return data[offset];
+}
+
+static uint16_t read_u16(char *data, size_t offset)
+{
+ return ((data[offset] & 0xFF) << 8) | (data[offset + 1] & 0xFF);
+}
+
+static int32_t read_s32(char *data, size_t offset)
+{
+ return (int32_t)((data[offset] << 24) | (data[offset + 1] << 16) |
+ (data[offset + 2] << 8) | data[offset + 3]);
+}
+
+static uint32_t read_u32(char *data, size_t offset)
+{
+ return ((data[offset] << 24) | (data[offset + 1] << 16) |
+ (data[offset + 2] << 8) | data[offset + 3]);
+}
+
+static void client_cut_text(VncState *vs, size_t len, char *text)
+{
+}
+
+static void pointer_event(VncState *vs, int button_mask, int x, int y)
+{
+ int buttons = 0;
+ int dz = 0;
+
+ if (button_mask & 0x01)
+ buttons |= MOUSE_EVENT_LBUTTON;
+ if (button_mask & 0x02)
+ buttons |= MOUSE_EVENT_MBUTTON;
+ if (button_mask & 0x04)
+ buttons |= MOUSE_EVENT_RBUTTON;
+ if (button_mask & 0x08)
+ dz = -1;
+ if (button_mask & 0x10)
+ dz = 1;
+
+ if (kbd_mouse_is_absolute()) {
+ kbd_mouse_event(x * 0x7FFF / vs->ds->width,
+ y * 0x7FFF / vs->ds->height,
+ dz, buttons);
+ } else {
+ static int last_x = -1;
+ static int last_y = -1;
+
+ if (last_x != -1)
+ kbd_mouse_event(x - last_x, y - last_y, dz, buttons);
+
+ last_x = x;
+ last_y = y;
+ }
+}
+
+static void key_event(VncState *vs, int down, uint32_t sym)
+{
+ int keycode;
+
+ keycode = keysym2scancode(vs->kbd_layout, sym & 0xFFFF);
+
+ if (keycode & 0x80)
+ kbd_put_keycode(0xe0);
+ if (down)
+ kbd_put_keycode(keycode & 0x7f);
+ else
+ kbd_put_keycode(keycode | 0x80);
+}
+
+static void framebuffer_update_request(VncState *vs, int incremental,
+ int x_position, int y_position,
+ int w, int h)
+{
+ int i;
+ vs->need_update = 1;
+ if (!incremental) {
+ char *old_row = vs->old_data + y_position * vs->ds->linesize;
+
+ for (i = 0; i < h; i++) {
+ vs->dirty_row[y_position + i] = (1ULL << (vs->ds->width / 16)) - 1;
+ if (vs->ds->width == 1024) {
+ vs->dirty_row[y_position + i] = ~(0ULL);
+ }
+ memset(old_row, 42, vs->ds->width * vs->depth);
+ old_row += vs->ds->linesize;
+ }
+ }
+}
+
+static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
+{
+ int i;
+
+ vs->has_hextile = 0;
+ vs->has_resize = 0;
+ vs->ds->dpy_copy = NULL;
+
+ for (i = n_encodings - 1; i >= 0; i--) {
+ switch (encodings[i]) {
+ case 0: /* Raw */
+ vs->has_hextile = 0;
+ break;
+ case 1: /* CopyRect */
+ vs->ds->dpy_copy = vnc_copy;
+ break;
+ case 5: /* Hextile */
+ vs->has_hextile = 1;
+ break;
+ case -223: /* DesktopResize */
+ vs->has_resize = 1;
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static void set_pixel_format(VncState *vs,
+ int bits_per_pixel, int depth,
+ int big_endian_flag, int true_color_flag,
+ int red_max, int green_max, int blue_max,
+ int red_shift, int green_shift, int blue_shift)
+{
+ switch (bits_per_pixel) {
+ case 32:
+ case 24:
+ vs->depth = 4;
+ break;
+ case 16:
+ vs->depth = 2;
+ break;
+ case 8:
+ vs->depth = 1;
+ break;
+ default:
+ vnc_client_error(vs);
+ break;
+ }
+
+ if (!true_color_flag)
+ vnc_client_error(vs);
+
+ vnc_dpy_resize(vs->ds, vs->ds->width, vs->ds->height);
+ memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row));
+ memset(vs->old_data, 42, vs->ds->linesize * vs->ds->height);
+
+ vga_hw_invalidate();
+ vga_hw_update();
+}
+
+static int protocol_client_msg(VncState *vs, char *data, size_t len)
+{
+ int i;
+ uint16_t limit;
+
+ switch (data[0]) {
+ case 0:
+ if (len == 1)
+ return 20;
+
+ set_pixel_format(vs, read_u8(data, 4), read_u8(data, 5),
+ read_u8(data, 6), read_u8(data, 7),
+ read_u16(data, 8), read_u16(data, 10),
+ read_u16(data, 12), read_u8(data, 14),
+ read_u8(data, 15), read_u8(data, 16));
+ break;
+ case 2:
+ if (len == 1)
+ return 4;
+
+ if (len == 4)
+ return 4 + (read_u16(data, 2) * 4);
+
+ limit = read_u16(data, 2);
+ for (i = 0; i < limit; i++) {
+ int32_t val = read_s32(data, 4 + (i * 4));
+ memcpy(data + 4 + (i * 4), &val, sizeof(val));
+ }
+
+ set_encodings(vs, (int32_t *)(data + 4), limit);
+ break;
+ case 3:
+ if (len == 1)
+ return 10;
+
+ framebuffer_update_request(vs,
+ read_u8(data, 1), read_u16(data, 2), read_u16(data, 4),
+ read_u16(data, 6), read_u16(data, 8));
+ break;
+ case 4:
+ if (len == 1)
+ return 8;
+
+ key_event(vs, read_u8(data, 1), read_u32(data, 4));
+ break;
+ case 5:
+ if (len == 1)
+ return 6;
+
+ pointer_event(vs, read_u8(data, 1), read_u16(data, 2), read_u16(data, 4));
+ break;
+ case 6:
+ if (len == 1)
+ return 8;
+
+ if (len == 8)
+ return 8 + read_u32(data, 4);
+
+ client_cut_text(vs, read_u32(data, 4), data + 8);
+ break;
+ default:
+ printf("Msg: %d\n", data[0]);
+ vnc_client_error(vs);
+ break;
+ }
+
+ vnc_read_when(vs, protocol_client_msg, 1);
+ return 0;
+}
+
+static int protocol_client_init(VncState *vs, char *data, size_t len)
+{
+ char pad[3] = { 0, 0, 0 };
+
+ vs->width = vs->ds->width;
+ vs->height = vs->ds->height;
+ vnc_write_u16(vs, vs->ds->width);
+ vnc_write_u16(vs, vs->ds->height);
+
+ vnc_write_u8(vs, vs->depth * 8); /* bits-per-pixel */
+ vnc_write_u8(vs, vs->depth * 8); /* depth */
+ vnc_write_u8(vs, 0); /* big-endian-flag */
+ vnc_write_u8(vs, 1); /* true-color-flag */
+ if (vs->depth == 4) {
+ vnc_write_u16(vs, 0xFF); /* red-max */
+ vnc_write_u16(vs, 0xFF); /* green-max */
+ vnc_write_u16(vs, 0xFF); /* blue-max */
+ vnc_write_u8(vs, 16); /* red-shift */
+ vnc_write_u8(vs, 8); /* green-shift */
+ vnc_write_u8(vs, 0); /* blue-shift */
+ } else if (vs->depth == 2) {
+ vnc_write_u16(vs, 31); /* red-max */
+ vnc_write_u16(vs, 63); /* green-max */
+ vnc_write_u16(vs, 31); /* blue-max */
+ vnc_write_u8(vs, 11); /* red-shift */
+ vnc_write_u8(vs, 5); /* green-shift */
+ vnc_write_u8(vs, 0); /* blue-shift */
+ } else if (vs->depth == 1) {
+ vnc_write_u16(vs, 3); /* red-max */
+ vnc_write_u16(vs, 7); /* green-max */
+ vnc_write_u16(vs, 3); /* blue-max */
+ vnc_write_u8(vs, 5); /* red-shift */
+ vnc_write_u8(vs, 2); /* green-shift */
+ vnc_write_u8(vs, 0); /* blue-shift */
+ }
+
+ vnc_write(vs, pad, 3); /* padding */
+
+ vnc_write_u32(vs, 4);
+ vnc_write(vs, "QEMU", 4);
+ vnc_flush(vs);
+
+ vnc_read_when(vs, protocol_client_msg, 1);
+
+ return 0;
+}
+
+static int protocol_version(VncState *vs, char *version, size_t len)
+{
+ char local[13];
+ int maj, min;
+
+ memcpy(local, version, 12);
+ local[12] = 0;
+
+ if (sscanf(local, "RFB %03d.%03d\n", &maj, &min) != 2) {
+ vnc_client_error(vs);
+ return 0;
+ }
+
+ vnc_write_u32(vs, 1); /* None */
+ vnc_flush(vs);
+
+ vnc_read_when(vs, protocol_client_init, 1);
+
+ return 0;
+}
+
+static void vnc_listen_read(void *opaque)
+{
+ VncState *vs = opaque;
+ struct sockaddr_in addr;
+ socklen_t addrlen = sizeof(addr);
+
+ vs->csock = accept(vs->lsock, (struct sockaddr *)&addr, &addrlen);
+ if (vs->csock != -1) {
+ fcntl(vs->csock, F_SETFL, O_NONBLOCK);
+ qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, opaque);
+ vnc_write(vs, "RFB 003.003\n", 12);
+ vnc_flush(vs);
+ vnc_read_when(vs, protocol_version, 12);
+ memset(vs->old_data, 0, vs->ds->linesize * vs->ds->height);
+ memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row));
+ vs->has_resize = 0;
+ vs->has_hextile = 0;
+ vs->ds->dpy_copy = NULL;
+ }
+}
+
+void vnc_display_init(DisplayState *ds, int display)
+{
+ struct sockaddr_in addr;
+ int reuse_addr, ret;
+ VncState *vs;
+
+ vs = qemu_mallocz(sizeof(VncState));
+ if (!vs)
+ exit(1);
+
+ ds->opaque = vs;
+
+ vs->lsock = -1;
+ vs->csock = -1;
+ vs->depth = 4;
+
+ vs->ds = ds;
+
+ if (!keyboard_layout)
+ keyboard_layout = "en-us";
+
+ vs->kbd_layout = init_keyboard_layout(keyboard_layout);
+ if (!vs->kbd_layout)
+ exit(1);
+
+ vs->lsock = socket(PF_INET, SOCK_STREAM, 0);
+ if (vs->lsock == -1) {
+ fprintf(stderr, "Could not create socket\n");
+ exit(1);
+ }
+
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(5900 + display);
+ memset(&addr.sin_addr, 0, sizeof(addr.sin_addr));
+
+ reuse_addr = 1;
+ ret = setsockopt(vs->lsock, SOL_SOCKET, SO_REUSEADDR,
+ &reuse_addr, sizeof(reuse_addr));
+ if (ret == -1) {
+ fprintf(stderr, "setsockopt() failed\n");
+ exit(1);
+ }
+
+ if (bind(vs->lsock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+ fprintf(stderr, "bind() failed\n");
+ exit(1);
+ }
+
+ if (listen(vs->lsock, 1) == -1) {
+ fprintf(stderr, "listen() failed\n");
+ exit(1);
+ }
+
+ ret = qemu_set_fd_handler2(vs->lsock, vnc_listen_poll, vnc_listen_read, NULL, vs);
+ if (ret == -1) {
+ exit(1);
+ }
+
+ vs->ds->data = NULL;
+ vs->ds->dpy_update = vnc_dpy_update;
+ vs->ds->dpy_resize = vnc_dpy_resize;
+ vs->ds->dpy_refresh = vnc_dpy_refresh;
+
+ memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row));
+
+ vnc_dpy_resize(vs->ds, 640, 400);
+}
diff -urN -x '*.[di]' a.hg/vnchextile.h vnc.hg/vnchextile.h
--- a.hg/vnchextile.h 1969-12-31 18:00:00.000000000 -0600
+++ vnc.hg/vnchextile.h 2006-04-28 00:58:59.000000000 -0500
@@ -0,0 +1,189 @@
+#define CONCAT_I(a, b) a ## b
+#define CONCAT(a, b) CONCAT_I(a, b)
+#define pixel_t CONCAT(uint, CONCAT(BPP, _t))
+
+static void CONCAT(send_hextile_tile_, BPP)(VncState *vs,
+ int x, int y, int w, int h,
+ pixel_t *last_bg, pixel_t *last_fg,
+ int *has_bg, int *has_fg)
+{
+ char *row = (vs->ds->data + y * vs->ds->linesize + x * vs->depth);
+ pixel_t *irow = (pixel_t *)row;
+ int j, i;
+ pixel_t bg = 0;
+ pixel_t fg = 0;
+ int n_colors = 0;
+ int bg_count = 0;
+ int fg_count = 0;
+ int flags = 0;
+ uint8_t data[(sizeof(pixel_t) + 2) * 16 * 16];
+ int n_data = 0;
+ int n_subtiles = 0;
+
+ for (j = 0; j < h; j++) {
+ for (i = 0; i < w; i++) {
+ switch (n_colors) {
+ case 0:
+ bg = irow[i];
+ n_colors = 1;
+ break;
+ case 1:
+ if (irow[i] != bg) {
+ fg = irow[i];
+ n_colors = 2;
+ }
+ break;
+ case 2:
+ if (irow[i] != bg && irow[i] != fg) {
+ n_colors = 3;
+ } else {
+ if (irow[i] == bg)
+ bg_count++;
+ else if (irow[i] == fg)
+ fg_count++;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ if (n_colors > 2)
+ break;
+ irow += vs->ds->linesize / sizeof(pixel_t);
+ }
+
+ if (n_colors > 1 && fg_count > bg_count) {
+ pixel_t tmp = fg;
+ fg = bg;
+ bg = tmp;
+ }
+
+ if (!*has_bg || *last_bg != bg) {
+ flags |= 0x02;
+ *has_bg = 1;
+ *last_bg = bg;
+ }
+
+ if (!*has_fg || *last_fg != fg) {
+ flags |= 0x04;
+ *has_fg = 1;
+ *last_fg = fg;
+ }
+
+ switch (n_colors) {
+ case 1:
+ n_data = 0;
+ break;
+ case 2:
+ flags |= 0x08;
+
+ irow = (pixel_t *)row;
+
+ for (j = 0; j < h; j++) {
+ int min_x = -1;
+ for (i = 0; i < w; i++) {
+ if (irow[i] == fg) {
+ if (min_x == -1)
+ min_x = i;
+ } else if (min_x != -1) {
+ hextile_enc_cord(data + n_data, min_x, j, i - min_x, 1);
+ n_data += 2;
+ n_subtiles++;
+ min_x = -1;
+ }
+ }
+ if (min_x != -1) {
+ hextile_enc_cord(data + n_data, min_x, j, i - min_x, 1);
+ n_data += 2;
+ n_subtiles++;
+ }
+ irow += vs->ds->linesize / sizeof(pixel_t);
+ }
+ break;
+ case 3:
+ flags |= 0x18;
+
+ irow = (pixel_t *)row;
+
+ if (!*has_bg || *last_bg != bg)
+ flags |= 0x02;
+
+ for (j = 0; j < h; j++) {
+ int has_color = 0;
+ int min_x = -1;
+ pixel_t color;
+
+ for (i = 0; i < w; i++) {
+ if (!has_color) {
+ if (irow[i] == bg)
+ continue;
+ color = irow[i];
+ min_x = i;
+ has_color = 1;
+ } else if (irow[i] != color) {
+ has_color = 0;
+
+ memcpy(data + n_data, &color, sizeof(color));
+ hextile_enc_cord(data + n_data + sizeof(pixel_t), min_x, j, i - min_x, 1);
+ n_data += 2 + sizeof(pixel_t);
+ n_subtiles++;
+
+ min_x = -1;
+ if (irow[i] != bg) {
+ color = irow[i];
+ min_x = i;
+ has_color = 1;
+ }
+ }
+ }
+ if (has_color) {
+ memcpy(data + n_data, &color, sizeof(color));
+ hextile_enc_cord(data + n_data + sizeof(pixel_t), min_x, j, i - min_x, 1);
+ n_data += 2 + sizeof(pixel_t);
+ n_subtiles++;
+ }
+ irow += vs->ds->linesize / sizeof(pixel_t);
+ }
+
+ /* A SubrectsColoured subtile invalidates the foreground color */
+ *has_fg = 0;
+ if (n_data > (w * h * sizeof(pixel_t))) {
+ n_colors = 4;
+ flags = 0x01;
+ *has_bg = 0;
+
+ /* we really don't have to invalidate either the bg or fg
+ but we've lost the old values. oh well. */
+ }
+ default:
+ break;
+ }
+
+ if (n_colors > 3) {
+ flags = 0x01;
+ *has_fg = 0;
+ *has_bg = 0;
+ n_colors = 4;
+ }
+
+ vnc_write_u8(vs, flags);
+ if (n_colors < 4) {
+ if (flags & 0x02)
+ vnc_write(vs, last_bg, sizeof(pixel_t));
+ if (flags & 0x04)
+ vnc_write(vs, last_fg, sizeof(pixel_t));
+ if (n_subtiles) {
+ vnc_write_u8(vs, n_subtiles);
+ vnc_write(vs, data, n_data);
+ }
+ } else {
+ for (j = 0; j < h; j++) {
+ vnc_write(vs, row, w * vs->depth);
+ row += vs->ds->linesize;
+ }
+ }
+}
+
+#undef pixel_t
+#undef CONCAT_I
+#undef CONCAT
diff -urN -x '*.[di]' a.hg/vnc_keysym.h vnc.hg/vnc_keysym.h
--- a.hg/vnc_keysym.h 1969-12-31 18:00:00.000000000 -0600
+++ vnc.hg/vnc_keysym.h 2006-04-23 12:31:00.000000000 -0500
@@ -0,0 +1,275 @@
+typedef struct {
+ const char* name;
+ int keysym;
+} name2keysym_t;
+static name2keysym_t name2keysym[]={
+/* ascii */
+ { "space", 0x020},
+ { "exclam", 0x021},
+ { "quotedbl", 0x022},
+ { "numbersign", 0x023},
+ { "dollar", 0x024},
+ { "percent", 0x025},
+ { "ampersand", 0x026},
+ { "apostrophe", 0x027},
+ { "parenleft", 0x028},
+ { "parenright", 0x029},
+ { "asterisk", 0x02a},
+ { "plus", 0x02b},
+ { "comma", 0x02c},
+ { "minus", 0x02d},
+ { "period", 0x02e},
+ { "slash", 0x02f},
+ { "0", 0x030},
+ { "1", 0x031},
+ { "2", 0x032},
+ { "3", 0x033},
+ { "4", 0x034},
+ { "5", 0x035},
+ { "6", 0x036},
+ { "7", 0x037},
+ { "8", 0x038},
+ { "9", 0x039},
+ { "colon", 0x03a},
+ { "semicolon", 0x03b},
+ { "less", 0x03c},
+ { "equal", 0x03d},
+ { "greater", 0x03e},
+ { "question", 0x03f},
+ { "at", 0x040},
+ { "A", 0x041},
+ { "B", 0x042},
+ { "C", 0x043},
+ { "D", 0x044},
+ { "E", 0x045},
+ { "F", 0x046},
+ { "G", 0x047},
+ { "H", 0x048},
+ { "I", 0x049},
+ { "J", 0x04a},
+ { "K", 0x04b},
+ { "L", 0x04c},
+ { "M", 0x04d},
+ { "N", 0x04e},
+ { "O", 0x04f},
+ { "P", 0x050},
+ { "Q", 0x051},
+ { "R", 0x052},
+ { "S", 0x053},
+ { "T", 0x054},
+ { "U", 0x055},
+ { "V", 0x056},
+ { "W", 0x057},
+ { "X", 0x058},
+ { "Y", 0x059},
+ { "Z", 0x05a},
+ { "bracketleft", 0x05b},
+ { "backslash", 0x05c},
+ { "bracketright", 0x05d},
+ { "asciicircum", 0x05e},
+ { "underscore", 0x05f},
+ { "grave", 0x060},
+ { "a", 0x061},
+ { "b", 0x062},
+ { "c", 0x063},
+ { "d", 0x064},
+ { "e", 0x065},
+ { "f", 0x066},
+ { "g", 0x067},
+ { "h", 0x068},
+ { "i", 0x069},
+ { "j", 0x06a},
+ { "k", 0x06b},
+ { "l", 0x06c},
+ { "m", 0x06d},
+ { "n", 0x06e},
+ { "o", 0x06f},
+ { "p", 0x070},
+ { "q", 0x071},
+ { "r", 0x072},
+ { "s", 0x073},
+ { "t", 0x074},
+ { "u", 0x075},
+ { "v", 0x076},
+ { "w", 0x077},
+ { "x", 0x078},
+ { "y", 0x079},
+ { "z", 0x07a},
+ { "braceleft", 0x07b},
+ { "bar", 0x07c},
+ { "braceright", 0x07d},
+ { "asciitilde", 0x07e},
+
+/* latin 1 extensions */
+{ "nobreakspace", 0x0a0},
+{ "exclamdown", 0x0a1},
+{ "cent", 0x0a2},
+{ "sterling", 0x0a3},
+{ "currency", 0x0a4},
+{ "yen", 0x0a5},
+{ "brokenbar", 0x0a6},
+{ "section", 0x0a7},
+{ "diaeresis", 0x0a8},
+{ "copyright", 0x0a9},
+{ "ordfeminine", 0x0aa},
+{ "guillemotleft", 0x0ab},
+{ "notsign", 0x0ac},
+{ "hyphen", 0x0ad},
+{ "registered", 0x0ae},
+{ "macron", 0x0af},
+{ "degree", 0x0b0},
+{ "plusminus", 0x0b1},
+{ "twosuperior", 0x0b2},
+{ "threesuperior", 0x0b3},
+{ "acute", 0x0b4},
+{ "mu", 0x0b5},
+{ "paragraph", 0x0b6},
+{ "periodcentered", 0x0b7},
+{ "cedilla", 0x0b8},
+{ "onesuperior", 0x0b9},
+{ "masculine", 0x0ba},
+{ "guillemotright", 0x0bb},
+{ "onequarter", 0x0bc},
+{ "onehalf", 0x0bd},
+{ "threequarters", 0x0be},
+{ "questiondown", 0x0bf},
+{ "Agrave", 0x0c0},
+{ "Aacute", 0x0c1},
+{ "Acircumflex", 0x0c2},
+{ "Atilde", 0x0c3},
+{ "Adiaeresis", 0x0c4},
+{ "Aring", 0x0c5},
+{ "AE", 0x0c6},
+{ "Ccedilla", 0x0c7},
+{ "Egrave", 0x0c8},
+{ "Eacute", 0x0c9},
+{ "Ecircumflex", 0x0ca},
+{ "Ediaeresis", 0x0cb},
+{ "Igrave", 0x0cc},
+{ "Iacute", 0x0cd},
+{ "Icircumflex", 0x0ce},
+{ "Idiaeresis", 0x0cf},
+{ "ETH", 0x0d0},
+{ "Eth", 0x0d0},
+{ "Ntilde", 0x0d1},
+{ "Ograve", 0x0d2},
+{ "Oacute", 0x0d3},
+{ "Ocircumflex", 0x0d4},
+{ "Otilde", 0x0d5},
+{ "Odiaeresis", 0x0d6},
+{ "multiply", 0x0d7},
+{ "Ooblique", 0x0d8},
+{ "Oslash", 0x0d8},
+{ "Ugrave", 0x0d9},
+{ "Uacute", 0x0da},
+{ "Ucircumflex", 0x0db},
+{ "Udiaeresis", 0x0dc},
+{ "Yacute", 0x0dd},
+{ "THORN", 0x0de},
+{ "Thorn", 0x0de},
+{ "ssharp", 0x0df},
+{ "agrave", 0x0e0},
+{ "aacute", 0x0e1},
+{ "acircumflex", 0x0e2},
+{ "atilde", 0x0e3},
+{ "adiaeresis", 0x0e4},
+{ "aring", 0x0e5},
+{ "ae", 0x0e6},
+{ "ccedilla", 0x0e7},
+{ "egrave", 0x0e8},
+{ "eacute", 0x0e9},
+{ "ecircumflex", 0x0ea},
+{ "ediaeresis", 0x0eb},
+{ "igrave", 0x0ec},
+{ "iacute", 0x0ed},
+{ "icircumflex", 0x0ee},
+{ "idiaeresis", 0x0ef},
+{ "eth", 0x0f0},
+{ "ntilde", 0x0f1},
+{ "ograve", 0x0f2},
+{ "oacute", 0x0f3},
+{ "ocircumflex", 0x0f4},
+{ "otilde", 0x0f5},
+{ "odiaeresis", 0x0f6},
+{ "division", 0x0f7},
+{ "oslash", 0x0f8},
+{ "ooblique", 0x0f8},
+{ "ugrave", 0x0f9},
+{ "uacute", 0x0fa},
+{ "ucircumflex", 0x0fb},
+{ "udiaeresis", 0x0fc},
+{ "yacute", 0x0fd},
+{ "thorn", 0x0fe},
+{ "ydiaeresis", 0x0ff},
+{"EuroSign", 0x20ac}, /* XK_EuroSign */
+
+ /* modifiers */
+{"Control_L", 0xffe3}, /* XK_Control_L */
+{"Control_R", 0xffe4}, /* XK_Control_R */
+{"Alt_L", 0xffe9}, /* XK_Alt_L */
+{"Alt_R", 0xffea}, /* XK_Alt_R */
+{"Caps_Lock", 0xffe5}, /* XK_Caps_Lock */
+{"Meta_L", 0xffe7}, /* XK_Meta_L */
+{"Meta_R", 0xffe8}, /* XK_Meta_R */
+{"Shift_L", 0xffe1}, /* XK_Shift_L */
+{"Shift_R", 0xffe2}, /* XK_Shift_R */
+{"Super_L", 0xffeb}, /* XK_Super_L */
+{"Super_R", 0xffec}, /* XK_Super_R */
+
+ /* special keys */
+{"BackSpace", 0xff08}, /* XK_BackSpace */
+{"Tab", 0xff09}, /* XK_Tab */
+{"Return", 0xff0d}, /* XK_Return */
+{"Right", 0xff53}, /* XK_Right */
+{"Left", 0xff51}, /* XK_Left */
+{"Up", 0xff52}, /* XK_Up */
+{"Down", 0xff54}, /* XK_Down */
+{"Page_Down", 0xff56}, /* XK_Page_Down */
+{"Page_Up", 0xff55}, /* XK_Page_Up */
+{"Insert", 0xff63}, /* XK_Insert */
+{"Delete", 0xffff}, /* XK_Delete */
+{"Home", 0xff50}, /* XK_Home */
+{"End", 0xff57}, /* XK_End */
+{"Scroll_Lock", 0xff14}, /* XK_Scroll_Lock */
+{"F1", 0xffbe}, /* XK_F1 */
+{"F2", 0xffbf}, /* XK_F2 */
+{"F3", 0xffc0}, /* XK_F3 */
+{"F4", 0xffc1}, /* XK_F4 */
+{"F5", 0xffc2}, /* XK_F5 */
+{"F6", 0xffc3}, /* XK_F6 */
+{"F7", 0xffc4}, /* XK_F7 */
+{"F8", 0xffc5}, /* XK_F8 */
+{"F9", 0xffc6}, /* XK_F9 */
+{"F10", 0xffc7}, /* XK_F10 */
+{"F11", 0xffc8}, /* XK_F11 */
+{"F12", 0xffc9}, /* XK_F12 */
+{"F13", 0xffca}, /* XK_F13 */
+{"F14", 0xffcb}, /* XK_F14 */
+{"F15", 0xffcc}, /* XK_F15 */
+{"Sys_Req", 0xff15}, /* XK_Sys_Req */
+{"KP_0", 0xffb0}, /* XK_KP_0 */
+{"KP_1", 0xffb1}, /* XK_KP_1 */
+{"KP_2", 0xffb2}, /* XK_KP_2 */
+{"KP_3", 0xffb3}, /* XK_KP_3 */
+{"KP_4", 0xffb4}, /* XK_KP_4 */
+{"KP_5", 0xffb5}, /* XK_KP_5 */
+{"KP_6", 0xffb6}, /* XK_KP_6 */
+{"KP_7", 0xffb7}, /* XK_KP_7 */
+{"KP_8", 0xffb8}, /* XK_KP_8 */
+{"KP_9", 0xffb9}, /* XK_KP_9 */
+{"KP_Add", 0xffab}, /* XK_KP_Add */
+{"KP_Decimal", 0xffae}, /* XK_KP_Decimal */
+{"KP_Divide", 0xffaf}, /* XK_KP_Divide */
+{"KP_Enter", 0xff8d}, /* XK_KP_Enter */
+{"KP_Equal", 0xffbd}, /* XK_KP_Equal */
+{"KP_Multiply", 0xffaa}, /* XK_KP_Multiply */
+{"KP_Subtract", 0xffad}, /* XK_KP_Subtract */
+{"help", 0xff6a}, /* XK_Help */
+{"Menu", 0xff67}, /* XK_Menu */
+{"Print", 0xff61}, /* XK_Print */
+{"Mode_switch", 0xff7e}, /* XK_Mode_switch */
+{"Num_Lock", 0xff7f}, /* XK_Num_Lock */
+{"Pause", 0xff13}, /* XK_Pause */
+{"Escape", 0xff1b}, /* XK_Escape */
+{0,0},
+};
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [Qemu-devel] [PATCH] VNC display support for QEMU
2006-04-29 21:34 [Qemu-devel] [PATCH] VNC display support for QEMU Anthony Liguori
@ 2006-04-30 1:03 ` Johannes Schindelin
2006-04-30 4:24 ` Anthony Liguori
2006-05-01 5:02 ` [Qemu-devel] [PATCH] VNC display support for QEMU Troy Benjegerdes
2006-05-01 5:29 ` Troy Benjegerdes
2006-05-01 6:01 ` Brad Campbell
2 siblings, 2 replies; 14+ messages in thread
From: Johannes Schindelin @ 2006-04-30 1:03 UTC (permalink / raw)
To: qemu-devel
Hi,
On Sat, 29 Apr 2006, Anthony Liguori wrote:
> One thing you may notice is that RealVNC has some issues with being
> disconnected. This is because it likes to switch from 8bit to 32bit depths
> automatically at startup. Unfortunately, there is a race condition in the VNC
> protocol and since this implementation is asynchronous, we seem to be much
> more prone to exposing this.
This, along with other problems, has been solved with LibVNCServer. But of
course, you are welcome to solve them again.
Ciao,
Dscho
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [Qemu-devel] [PATCH] VNC display support for QEMU
2006-04-30 1:03 ` Johannes Schindelin
@ 2006-04-30 4:24 ` Anthony Liguori
2006-04-30 10:43 ` Johannes Schindelin
2006-05-01 5:02 ` [Qemu-devel] [PATCH] VNC display support for QEMU Troy Benjegerdes
1 sibling, 1 reply; 14+ messages in thread
From: Anthony Liguori @ 2006-04-30 4:24 UTC (permalink / raw)
To: qemu-devel
Hi Johannes,
Johannes Schindelin wrote:
> Hi,
>
> On Sat, 29 Apr 2006, Anthony Liguori wrote:
>
>
>> One thing you may notice is that RealVNC has some issues with being
>> disconnected. This is because it likes to switch from 8bit to 32bit depths
>> automatically at startup. Unfortunately, there is a race condition in the VNC
>> protocol and since this implementation is asynchronous, we seem to be much
>> more prone to exposing this.
>>
>
> This, along with other problems, has been solved with LibVNCServer. But of
> course, you are welcome to solve them again.
>
I should mention, the majority of the "smarts" of this patch are QEMU
specific optimizations. The first one maintains a separate copy of the
client's framebuffer to use to reduce the size of the updates generated
by the VGA code. The second one hooks the Cirrus 2d video-to-video copy
to generate VNC CopyRect updates.
The actual VNC side of the code is pretty trivial.
I would have been more inclined to use LibVNCServer if it wasn't based
on threading. I really wanted an asynchronous implementation of a VNC
server that didn't depend on threads.
Regards,
Anthony Liguori
> Ciao,
> Dscho
>
>
>
> _______________________________________________
> Qemu-devel mailing list
> Qemu-devel@nongnu.org
> http://lists.nongnu.org/mailman/listinfo/qemu-devel
>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [Qemu-devel] [PATCH] VNC display support for QEMU
2006-04-30 4:24 ` Anthony Liguori
@ 2006-04-30 10:43 ` Johannes Schindelin
2006-04-30 20:14 ` Anthony Liguori
2006-04-30 20:57 ` [Qemu-devel] [PATCH] Enhanced Documentation Stefan Weil
0 siblings, 2 replies; 14+ messages in thread
From: Johannes Schindelin @ 2006-04-30 10:43 UTC (permalink / raw)
To: qemu-devel
Hi,
On Sat, 29 Apr 2006, Anthony Liguori wrote:
> I would have been more inclined to use LibVNCServer if it wasn't based
> on threading. I really wanted an asynchronous implementation of a VNC
> server that didn't depend on threads.
AFAICT it does not. In vnc_refresh(), there is a call to rfbProcessEvents,
which says to select() the socket(s) for 0 microseconds. Same thread.
Now, there is a facility in LibVNCServer to take advantage of pthreads,
and in some applications it is actually better to run a background thread
to handle all the VNC stuff. But it is not used in QEmu.
Ciao,
Dscho
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [Qemu-devel] [PATCH] VNC display support for QEMU
2006-04-30 10:43 ` Johannes Schindelin
@ 2006-04-30 20:14 ` Anthony Liguori
2006-04-30 22:14 ` Christian MICHON
2006-04-30 20:57 ` [Qemu-devel] [PATCH] Enhanced Documentation Stefan Weil
1 sibling, 1 reply; 14+ messages in thread
From: Anthony Liguori @ 2006-04-30 20:14 UTC (permalink / raw)
To: qemu-devel
Johannes Schindelin wrote:
> Hi,
>
> On Sat, 29 Apr 2006, Anthony Liguori wrote:
>
>
>> I would have been more inclined to use LibVNCServer if it wasn't based
>> on threading. I really wanted an asynchronous implementation of a VNC
>> server that didn't depend on threads.
>>
>
> AFAICT it does not. In vnc_refresh(), there is a call to rfbProcessEvents,
> which says to select() the socket(s) for 0 microseconds. Same thread.
>
There is a fundamental design in the LibVNCServer code (which I believe
was inherited from the various RealVNC derivatives) that all IO is done
through some derivation of rfbReadExact. rfbReadExact is semantically
synchronous (it uses select to enforce that).
You could, perhaps, not begin an iteration of the server message process
loop until the socket becomes readable but that only gives you a
semi-asynchronous interface. As soon as you get 1 byte of message data,
you are now handling things synchronously until that message is complete.
Since QEMU is single threaded, this means everything blocks (including
progress of the guest). This theoretical problem is why I implemented a
true asynchronous VNC implementation. You'll notice that I use a state
machine to handle the message dispatch (which is practical for the
server side of the VNC protocol at least). My VNC will never (assuming
it's working correctly :-)) block guest progress because of outstanding IO.
There is a practical problem too with a semi-asynchronous approach.
It's entirely possible to get serious congestion in odd places during a
message transmission (or even a loss that requires timeout). This means
you could end up blocking the guest for a prolonged period of time (and
if the guest is doing serious work--like hosting some sort of network
service--this is catastrophic).
So, in a multithreaded application or a single-threaded application that
doesn't have to worry about these things, LibVNCServer is a great
solution. I just don't think it's the right solution for QEMU for the
reasons outlined above.
Regards,
Anthony Liguori
> Now, there is a facility in LibVNCServer to take advantage of pthreads,
> and in some applications it is actually better to run a background thread
> to handle all the VNC stuff. But it is not used in QEmu.
>
> Ciao,
> Dscho
>
>
>
> _______________________________________________
> Qemu-devel mailing list
> Qemu-devel@nongnu.org
> http://lists.nongnu.org/mailman/listinfo/qemu-devel
>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [Qemu-devel] [PATCH] VNC display support for QEMU
2006-04-30 20:14 ` Anthony Liguori
@ 2006-04-30 22:14 ` Christian MICHON
2006-04-30 23:11 ` Christian MICHON
0 siblings, 1 reply; 14+ messages in thread
From: Christian MICHON @ 2006-04-30 22:14 UTC (permalink / raw)
To: qemu-devel
just a quick note: your patch breaks the mingw32 build on winXP.
Christian
for d in i386-softmmu; do \
make -C $d all || exit 1 ; \
done
make[1]: Entering directory `/home/root/qemu/i386-softmmu'
gcc -Wall -O2 -g -fno-strict-aliasing -fomit-frame-pointer -I. -I..
-I/home/root/qemu/target-i386 -I/home/root/qemu -D_GNU_SOURCE
-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -I/home/root/qemu/fpu
-DHAS_AUDIO -I/home/root/qemu/slirp -c -o vnc.o /home/root/qemu/vnc.c
c:/qemu/mingw/home/root/qemu/vnc.c:3:24: sys/socket.h: No such file or directory
c:/qemu/mingw/home/root/qemu/vnc.c:4:24: netinet/in.h: No such file or directory
c:/qemu/mingw/home/root/qemu/vnc.c:5:25: netinet/tcp.h: No such file
or directory
c:/qemu/mingw/home/root/qemu/vnc.c: In function `vnc_client_write':
c:/qemu/mingw/home/root/qemu/vnc.c:414: error: `ssize_t' undeclared
(first use in this function)
c:/qemu/mingw/home/root/qemu/vnc.c:414: error: (Each undeclared
identifier is reported only once
c:/qemu/mingw/home/root/qemu/vnc.c:414: error: for each function it appears in.)
c:/qemu/mingw/home/root/qemu/vnc.c:414: error: syntax error before "ret"
c:/qemu/mingw/home/root/qemu/vnc.c:417: error: `ret' undeclared (first
use in this function)
c:/qemu/mingw/home/root/qemu/vnc.c: In function `vnc_client_read':
c:/qemu/mingw/home/root/qemu/vnc.c:439: error: `ssize_t' undeclared
(first use in this function)
c:/qemu/mingw/home/root/qemu/vnc.c:439: error: syntax error before "ret"
c:/qemu/mingw/home/root/qemu/vnc.c:443: error: `ret' undeclared (first
use in this function)
c:/qemu/mingw/home/root/qemu/vnc.c: In function `vnc_listen_read':
c:/qemu/mingw/home/root/qemu/vnc.c:810: error: storage size of `addr'
isn't known
c:/qemu/mingw/home/root/qemu/vnc.c:811: error: `socklen_t' undeclared
(first use in this function)
c:/qemu/mingw/home/root/qemu/vnc.c:811: error: syntax error before "addrlen"
c:/qemu/mingw/home/root/qemu/vnc.c:813: warning: implicit declaration
of function `accept'
c:/qemu/mingw/home/root/qemu/vnc.c:813: error: `addrlen' undeclared
(first use in this function)
c:/qemu/mingw/home/root/qemu/vnc.c:815: warning: implicit declaration
of function `fcntl'
c:/qemu/mingw/home/root/qemu/vnc.c:815: error: `F_SETFL' undeclared
(first use in this function)
c:/qemu/mingw/home/root/qemu/vnc.c:815: error: `O_NONBLOCK' undeclared
(first use in this function)
c:/qemu/mingw/home/root/qemu/vnc.c:810: warning: unused variable `addr'
c:/qemu/mingw/home/root/qemu/vnc.c: In function `vnc_display_init':
c:/qemu/mingw/home/root/qemu/vnc.c:830: error: storage size of `addr'
isn't known
c:/qemu/mingw/home/root/qemu/vnc.c:853: warning: implicit declaration
of function `socket'
c:/qemu/mingw/home/root/qemu/vnc.c:853: error: `PF_INET' undeclared
(first use in this function)
c:/qemu/mingw/home/root/qemu/vnc.c:853: error: `SOCK_STREAM'
undeclared (first use in this function)
c:/qemu/mingw/home/root/qemu/vnc.c:859: error: `AF_INET' undeclared
(first use in this function)
c:/qemu/mingw/home/root/qemu/vnc.c:860: warning: implicit declaration
of function `htons'
c:/qemu/mingw/home/root/qemu/vnc.c:864: warning: implicit declaration
of function `setsockopt'
c:/qemu/mingw/home/root/qemu/vnc.c:864: error: `SOL_SOCKET' undeclared
(first use in this function)
c:/qemu/mingw/home/root/qemu/vnc.c:864: error: `SO_REUSEADDR'
undeclared (first use in this function)
c:/qemu/mingw/home/root/qemu/vnc.c:871: warning: implicit declaration
of function `bind'
c:/qemu/mingw/home/root/qemu/vnc.c:876: warning: implicit declaration
of function `listen'
c:/qemu/mingw/home/root/qemu/vnc.c:830: warning: unused variable `addr'
make[1]: *** [vnc.o] Error 1
make[1]: Leaving directory `/home/root/qemu/i386-softmmu'
make: *** [all] Error 1
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [Qemu-devel] [PATCH] VNC display support for QEMU
2006-04-30 22:14 ` Christian MICHON
@ 2006-04-30 23:11 ` Christian MICHON
2006-04-30 23:46 ` [Qemu-devel] " Anthony Liguori
0 siblings, 1 reply; 14+ messages in thread
From: Christian MICHON @ 2006-04-30 23:11 UTC (permalink / raw)
To: qemu-devel
neat! it is working on windows 3.0 guest (no acceleration) on a winXP host.
Fabrice fixed it live while I was trying it (he's fast!).
old mouse sync problem is still here, as you mentionned no
calibration is done. You mention "absolute mouse". how to do it ?
On 5/1/06, Christian MICHON <christian.michon@gmail.com> wrote:
> just a quick note: your patch breaks the mingw32 build on winXP.
> Christian
^ permalink raw reply [flat|nested] 14+ messages in thread
* [Qemu-devel] Re: [PATCH] VNC display support for QEMU
2006-04-30 23:11 ` Christian MICHON
@ 2006-04-30 23:46 ` Anthony Liguori
0 siblings, 0 replies; 14+ messages in thread
From: Anthony Liguori @ 2006-04-30 23:46 UTC (permalink / raw)
To: qemu-devel
On Mon, 01 May 2006 01:11:04 +0200, Christian MICHON wrote:
> neat! it is working on windows 3.0 guest (no acceleration) on a winXP
> host. Fabrice fixed it live while I was trying it (he's fast!).
Yeah, sorry about that. Fortunately, Fabrice rocks :-)
> old mouse sync problem is still here, as you mentionned no calibration is
> done. You mention "absolute mouse". how to do it ?
You would need at least a win98 guest. You then have to add '-usb
-usbdevice tablet' to the qemu command line.
Regards,
Anthony Liguori
> On 5/1/06, Christian MICHON <christian.michon@gmail.com> wrote:
>> just a quick note: your patch breaks the mingw32 build on winXP.
>> Christian
^ permalink raw reply [flat|nested] 14+ messages in thread
* [Qemu-devel] [PATCH] Enhanced Documentation
2006-04-30 10:43 ` Johannes Schindelin
2006-04-30 20:14 ` Anthony Liguori
@ 2006-04-30 20:57 ` Stefan Weil
1 sibling, 0 replies; 14+ messages in thread
From: Stefan Weil @ 2006-04-30 20:57 UTC (permalink / raw)
To: qemu-devel
[-- Attachment #1: Type: text/plain, Size: 795 bytes --]
Here are three patches which enhance and fix the existing QEMU
documentation.
1. Makefile: added rules to build qemu-doc and qemu-tech in info and dvi
format.
I did not add a dependency which calls these rules automatically, so run
make qemu-doc.info qemu-tech.info qemu-doc.dvi qemu-tech.dvi
to build the new targets.
2. qemu-doc.texi, qemu-tech.texi:
* fixed for generation of info files
* fixed long lines for generation of dvi / ps / pdf files
* fixed html title
* added menus for html and info
* added table of contents for html and dvi
* added index (still empty) for html, info and dvi
* fixed minor spelling bug (reasonnable)
All documentation formats should build now without error messages
(my test on Debian Linux passed).
Regards
Stefan Weil
[-- Attachment #2: qemu-doc.patch --]
[-- Type: text/plain, Size: 15926 bytes --]
Index: qemu-doc.texi
===================================================================
RCS file: /sources/qemu/qemu/qemu-doc.texi,v
retrieving revision 1.85
diff -u -b -B -u -r1.85 qemu-doc.texi
--- qemu-doc.texi 23 Apr 2006 21:57:03 -0000 1.85
+++ qemu-doc.texi 30 Apr 2006 20:38:33 -0000
@@ -1,16 +1,46 @@
\input texinfo @c -*- texinfo -*-
+@c %**start of header
+@setfilename qemu-doc.info
+@settitle QEMU CPU Emulator User Documentation
+@exampleindent 0
+@paragraphindent 0
+@c %**end of header
@iftex
-@settitle QEMU CPU Emulator User Documentation
@titlepage
@sp 7
-@center @titlefont{QEMU CPU Emulator User Documentation}
+@center @titlefont{QEMU CPU Emulator}
+@sp 1
+@center @titlefont{User Documentation}
@sp 3
@end titlepage
@end iftex
+@ifnottex
+@node Top
+@top
+
+@menu
+* Introduction::
+* Installation::
+* QEMU PC System emulator::
+* QEMU System emulator for non PC targets::
+* QEMU Linux User space emulator::
+* compilation:: Compilation from the sources
+* Index::
+@end menu
+@end ifnottex
+
+@contents
+
+@node Introduction
@chapter Introduction
+@menu
+* intro_features:: Features
+@end menu
+
+@node intro_features
@section Features
QEMU is a FAST! processor emulator using dynamic translation to
@@ -52,27 +82,53 @@
For user emulation, x86, PowerPC, ARM, MIPS, and Sparc32/64 CPUs are supported.
+@node Installation
@chapter Installation
If you want to compile QEMU yourself, see @ref{compilation}.
+@menu
+* install_linux:: Linux
+* install_windows:: Windows
+* install_mac:: Macintosh
+@end menu
+
+@node install_linux
@section Linux
If a precompiled package is available for your distribution - you just
have to install it. Otherwise, see @ref{compilation}.
+@node install_windows
@section Windows
Download the experimental binary installer at
-@url{http://www.free.oszoo.org/download.html}.
+@url{http://www.free.oszoo.org/@/download.html}.
+@node install_mac
@section Mac OS X
Download the experimental binary installer at
-@url{http://www.free.oszoo.org/download.html}.
+@url{http://www.free.oszoo.org/@/download.html}.
+@node QEMU PC System emulator
@chapter QEMU PC System emulator
+@menu
+* pcsys_introduction:: Introduction
+* pcsys_quickstart:: Quick Start
+* sec_invocation:: Invocation
+* pcsys_keys:: Keys
+* pcsys_monitor:: QEMU Monitor
+* disk_images:: Disk Images
+* pcsys_network:: Network emulation
+* direct_linux_boot:: Direct Linux Boot
+* pcsys_usb:: USB emulation
+* gdb_usage:: GDB usage
+* pcsys_os_specific:: Target OS specific information
+@end menu
+
+@node pcsys_introduction
@section Introduction
@c man begin DESCRIPTION
@@ -118,6 +174,7 @@
@c man end
+@node pcsys_quickstart
@section Quick Start
Download and uncompress the linux image (@file{linux.img}) and type:
@@ -147,14 +204,14 @@
@item -fda file
@item -fdb file
-Use @var{file} as floppy disk 0/1 image (@xref{disk_images}). You can
+Use @var{file} as floppy disk 0/1 image (@pxref{disk_images}). You can
use the host floppy by using @file{/dev/fd0} as filename.
@item -hda file
@item -hdb file
@item -hdc file
@item -hdd file
-Use @var{file} as hard disk 0, 1, 2 or 3 image (@xref{disk_images}).
+Use @var{file} as hard disk 0, 1, 2 or 3 image (@pxref{disk_images}).
@item -cdrom file
Use @var{file} as CD-ROM image (you cannot use @option{-hdc} and and
@@ -168,7 +225,7 @@
@item -snapshot
Write to temporary files instead of disk image files. In this case,
the raw disk image you use is not written back. You can however force
-the write back by pressing @key{C-a s} (@xref{disk_images}).
+the write back by pressing @key{C-a s} (@pxref{disk_images}).
@item -m megs
Set virtual RAM size to @var{megs} megabytes. Default is 128 MB.
@@ -297,9 +354,12 @@
Example:
@example
# launch a first QEMU instance
-qemu linux.img -net nic,macaddr=52:54:00:12:34:56 -net socket,listen=:1234
-# connect the VLAN 0 of this instance to the VLAN 0 of the first instance
-qemu linux.img -net nic,macaddr=52:54:00:12:34:57 -net socket,connect=127.0.0.1:1234
+qemu linux.img -net nic,macaddr=52:54:00:12:34:56 \
+ -net socket,listen=:1234
+# connect the VLAN 0 of this instance to the VLAN 0
+# of the first instance
+qemu linux.img -net nic,macaddr=52:54:00:12:34:57 \
+ -net socket,connect=127.0.0.1:1234
@end example
@item -net socket[,vlan=n][,fd=h][,mcast=maddr:port]
@@ -321,17 +381,22 @@
Example:
@example
# launch one QEMU instance
-qemu linux.img -net nic,macaddr=52:54:00:12:34:56 -net socket,mcast=230.0.0.1:1234
+qemu linux.img -net nic,macaddr=52:54:00:12:34:56 \
+ -net socket,mcast=230.0.0.1:1234
# launch another QEMU instance on same "bus"
-qemu linux.img -net nic,macaddr=52:54:00:12:34:57 -net socket,mcast=230.0.0.1:1234
+qemu linux.img -net nic,macaddr=52:54:00:12:34:57 \
+ -net socket,mcast=230.0.0.1:1234
# launch yet another QEMU instance on same "bus"
-qemu linux.img -net nic,macaddr=52:54:00:12:34:58 -net socket,mcast=230.0.0.1:1234
+qemu linux.img -net nic,macaddr=52:54:00:12:34:58 \
+ -net socket,mcast=230.0.0.1:1234
@end example
Example (User Mode Linux compat.):
@example
-# launch QEMU instance (note mcast address selected is UML's default)
-qemu linux.img -net nic,macaddr=52:54:00:12:34:56 -net socket,mcast=239.192.168.1:1102
+# launch QEMU instance (note mcast address selected
+# is UML's default)
+qemu linux.img -net nic,macaddr=52:54:00:12:34:56 \
+ -net socket,mcast=239.192.168.1:1102
# launch UML
/path/to/linux ubd0=/path/to/root_fs eth0=mcast
@end example
@@ -464,7 +529,7 @@
non graphical mode.
@item -s
-Wait gdb connection to port 1234 (@xref{gdb_usage}).
+Wait gdb connection to port 1234 (@pxref{gdb_usage}).
@item -p port
Change gdb connection port.
@item -S
@@ -487,6 +552,7 @@
@c man end
+@node pcsys_keys
@section Keys
@c man begin OPTIONS
@@ -535,9 +601,6 @@
@ignore
-@setfilename qemu
-@settitle QEMU System Emulator
-
@c man begin SEEALSO
The HTML documentation of QEMU for more precise information and Linux
user mode emulator invocation.
@@ -549,8 +612,7 @@
@end ignore
-@end ignore
-
+@node pcsys_monitor
@section QEMU Monitor
The QEMU monitor is used to give complex commands to the QEMU
@@ -676,7 +738,7 @@
@item
Dump 80 16 bit values at the start of the video memory.
-@example
+@smallexample
(qemu) xp/80hx 0xb8000
0x000b8000: 0x0b50 0x0b6c 0x0b65 0x0b78 0x0b38 0x0b36 0x0b2f 0x0b42
0x000b8010: 0x0b6f 0x0b63 0x0b68 0x0b73 0x0b20 0x0b56 0x0b47 0x0b41
@@ -688,7 +750,7 @@
0x000b8070: 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720
0x000b8080: 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720
0x000b8090: 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720
-@end example
+@end smallexample
@end itemize
@item p or print/fmt expr
@@ -739,6 +801,14 @@
growable disk images (their size increase as non empty sectors are
written), compressed and encrypted disk images.
+@menu
+* disk_images_quickstart:: Quick start for disk image creation
+* disk_images_snapshot_mode:: Snapshot mode
+* qemu_img_invocation:: qemu-img Invocation
+* disk_images_fat_images:: Virtual FAT disk images
+@end menu
+
+@node disk_images_quickstart
@subsection Quick start for disk image creation
You can create a disk image with the command:
@@ -749,8 +819,9 @@
size in kilobytes. You can add an @code{M} suffix to give the size in
megabytes and a @code{G} suffix for gigabytes.
-@xref{qemu_img_invocation} for more information.
+See @ref{qemu_img_invocation} for more information.
+@node disk_images_snapshot_mode
@subsection Snapshot mode
If you use the option @option{-snapshot}, all disk images are
@@ -764,6 +835,7 @@
@include qemu-img.texi
+@node disk_images_fat_images
@subsection Virtual FAT disk images
QEMU can automatically create a virtual FAT disk image from a
@@ -798,6 +870,7 @@
@item write to the FAT directory on the host system while accessing it with the guest system.
@end itemize
+@node pcsys_network
@section Network emulation
QEMU can simulate several networks cards (NE2000 boards on the PC
@@ -901,10 +974,10 @@
@item Launch @code{qemu.sh}. You should have the following output:
-@example
+@smallexample
> ./qemu.sh
Connected to host network interface: tun0
-Linux version 2.4.21 (bellard@@voyager.localdomain) (gcc version 3.2.2 20030222 (Red Hat Linux 3.2.2-5)) #5 Tue Nov 11 18:18:53 CET 2003
+Linux version 2.4.21 (bellard@@voyager.localdomain) (gcc version 3.2.2 20030222 @/(Red Hat @/Linux 3.2.2-5)) #5 Tue Nov 11 18:18:53 CET 2003
BIOS-provided physical RAM map:
BIOS-e801: 0000000000000000 - 000000000009f000 (usable)
BIOS-e801: 0000000000100000 - 0000000002000000 (usable)
@@ -913,7 +986,7 @@
zone(0): 4096 pages.
zone(1): 4096 pages.
zone(2): 0 pages.
-Kernel command line: root=/dev/hda sb=0x220,5,1,5 ide2=noprobe ide3=noprobe ide4=noprobe ide5=noprobe console=ttyS0
+Kernel command line: root=/dev/hda sb=0x220,5,1,5 ide2=noprobe ide3=noprobe ide4=noprobe @/ide5=noprobe console=ttyS0
ide_setup: ide2=noprobe
ide_setup: ide3=noprobe
ide_setup: ide4=noprobe
@@ -922,7 +995,7 @@
Detected 2399.621 MHz processor.
Console: colour EGA 80x25
Calibrating delay loop... 4744.80 BogoMIPS
-Memory: 28872k/32768k available (1210k kernel code, 3508k reserved, 266k data, 64k init, 0k highmem)
+Memory: 28872k/32768k available (1210k kernel code, 3508k reserved, 266k data, 64k init, @/0k highmem)
Dentry cache hash table entries: 4096 (order: 3, 32768 bytes)
Inode cache hash table entries: 2048 (order: 2, 16384 bytes)
Mount cache hash table entries: 512 (order: 0, 4096 bytes)
@@ -964,14 +1037,14 @@
VFS: Mounted root (ext2 filesystem).
Freeing unused kernel memory: 64k freed
-Linux version 2.4.21 (bellard@@voyager.localdomain) (gcc version 3.2.2 20030222 (Red Hat Linux 3.2.2-5)) #5 Tue Nov 11 18:18:53 CET 2003
+Linux version 2.4.21 (bellard@@voyager.localdomain) (gcc version 3.2.2 20030222 @/(Red Hat @/Linux 3.2.2-5)) #5 Tue Nov 11 18:18:53 CET 2003
QEMU Linux test distribution (based on Redhat 9)
Type 'exit' to halt the system
sh-2.05b#
-@end example
+@end smallexample
@item
Then you can play with the kernel inside the virtual serial console. You
@@ -1021,6 +1094,7 @@
@end enumerate
+@node pcsys_usb
@section USB emulation
QEMU emulates a PCI UHCI USB controller and a 8 port USB hub connected
@@ -1104,7 +1178,8 @@
In order to use gdb, launch qemu with the '-s' option. It will wait for a
gdb connection:
@example
-> qemu -s -kernel arch/i386/boot/bzImage -hda root-2.4.20.img -append "root=/dev/hda"
+> qemu -s -kernel arch/i386/boot/bzImage -hda root-2.4.20.img \
+ -append "root=/dev/hda"
Connected to host network interface: tun0
Waiting gdb connection on port 1234
@end example
@@ -1136,6 +1211,7 @@
@code{x/10i $cs*16+*eip} to dump the code at the PC position.
@end enumerate
+@node pcsys_os_specific
@section Target OS specific information
@subsection Linux
@@ -1222,12 +1298,22 @@
from @url{http://www.vmware.com/software/dosidle210.zip} to solve this
problem.
+@node QEMU System emulator for non PC targets
@chapter QEMU System emulator for non PC targets
QEMU is a generic emulator and it emulates many non PC
machines. Most of the options are similar to the PC emulator. The
differences are mentionned in the following sections.
+@menu
+* QEMU PowerPC System emulator::
+* Sparc32 System emulator invocation::
+* Sparc64 System emulator invocation::
+* MIPS System emulator invocation::
+* ARM System emulator invocation::
+@end menu
+
+@node QEMU PowerPC System emulator
@section QEMU PowerPC System emulator
Use the executable @file{qemu-system-ppc} to simulate a complete PREP
@@ -1292,6 +1378,7 @@
More information is available at
@url{http://perso.magic.fr/l_indien/qemu-ppc/}.
+@node Sparc32 System emulator invocation
@section Sparc32 System emulator invocation
Use the executable @file{qemu-system-sparc} to simulate a JavaStation
@@ -1320,7 +1407,7 @@
The number of peripherals is fixed in the architecture.
QEMU uses the Proll, a PROM replacement available at
-@url{http://people.redhat.com/zaitcev/linux/}. The required
+@url{http://people.redhat.com/@/zaitcev/linux/}. The required
QEMU-specific patches are included with the sources.
A sample Linux 2.6 series kernel and ram disk image are available on
@@ -1341,6 +1428,7 @@
@c man end
+@node Sparc64 System emulator invocation
@section Sparc64 System emulator invocation
Use the executable @file{qemu-system-sparc64} to simulate a Sun4u machine.
@@ -1359,6 +1447,7 @@
PC-compatible serial ports
@end itemize
+@node MIPS System emulator invocation
@section MIPS System emulator invocation
Use the executable @file{qemu-system-mips} to simulate a MIPS machine.
@@ -1376,6 +1465,7 @@
More information is available in the QEMU mailing-list archive.
+@node ARM System emulator invocation
@section ARM System emulator invocation
Use the executable @file{qemu-system-arm} to simulate a ARM
@@ -1394,8 +1484,16 @@
A Linux 2.6 test image is available on the QEMU web site. More
information is available in the QEMU mailing-list archive.
+@node QEMU Linux User space emulator
@chapter QEMU Linux User space emulator
+@menu
+* Quick Start::
+* Wine launch::
+* Command line options::
+@end menu
+
+@node Quick Start
@section Quick Start
In order to launch a Linux process, QEMU needs the process executable
@@ -1439,11 +1537,13 @@
@item The x86 version of QEMU is also included. You can try weird things such as:
@example
-qemu-i386 /usr/local/qemu-i386/bin/qemu-i386 /usr/local/qemu-i386/bin/ls-i386
+qemu-i386 /usr/local/qemu-i386/bin/qemu-i386 \
+ /usr/local/qemu-i386/bin/ls-i386
@end example
@end itemize
+@node Wine launch
@section Wine launch
@itemize
@@ -1460,17 +1560,19 @@
(@file{qemu-XXX-i386-wine.tar.gz} on the QEMU web page).
@item Configure Wine on your account. Look at the provided script
-@file{/usr/local/qemu-i386/bin/wine-conf.sh}. Your previous
+@file{/usr/local/qemu-i386/@/bin/wine-conf.sh}. Your previous
@code{$@{HOME@}/.wine} directory is saved to @code{$@{HOME@}/.wine.org}.
@item Then you can try the example @file{putty.exe}:
@example
-qemu-i386 /usr/local/qemu-i386/wine/bin/wine /usr/local/qemu-i386/wine/c/Program\ Files/putty.exe
+qemu-i386 /usr/local/qemu-i386/wine/bin/wine \
+ /usr/local/qemu-i386/wine/c/Program\ Files/putty.exe
@end example
@end itemize
+@node Command line options
@section Command line options
@example
@@ -1498,6 +1600,14 @@
@node compilation
@chapter Compilation from the sources
+@menu
+* Linux/Unix::
+* Windows::
+* Cross compilation for Windows with Linux::
+* Mac OS X::
+@end menu
+
+@node Linux/Unix
@section Linux/Unix
@subsection Compilation
@@ -1555,6 +1665,7 @@
variables. You must use gcc 3.x on PowerPC.
@end example
+@node Windows
@section Windows
@itemize
@@ -1564,7 +1675,7 @@
@item Download
the MinGW development library of SDL 1.2.x
-(@file{SDL-devel-1.2.x-mingw32.tar.gz}) from
+(@file{SDL-devel-1.2.x-@/mingw32.tar.gz}) from
@url{http://www.libsdl.org}. Unpack it in a temporary place, and
unpack the archive @file{i386-mingw32msvc.tar.gz} in the MinGW tool
directory. Edit the @file{sdl-config} script so that it gives the
@@ -1584,6 +1695,7 @@
@end itemize
+@node Cross compilation for Windows with Linux
@section Cross compilation for Windows with Linux
@itemize
@@ -1615,9 +1727,15 @@
Note: Currently, Wine does not seem able to launch
QEMU for Win32.
+@node Mac OS X
@section Mac OS X
The Mac OS X patches are not fully merged in QEMU, so you should look
at the QEMU mailing list archive to have all the necessary
information.
+@node Index
+@chapter Index
+@printindex cp
+
+@bye
[-- Attachment #3: qemu-tech.patch --]
[-- Type: text/plain, Size: 7203 bytes --]
Index: qemu-tech.texi
===================================================================
RCS file: /sources/qemu/qemu/qemu-tech.texi,v
retrieving revision 1.8
diff -u -b -B -u -r1.8 qemu-tech.texi
--- qemu-tech.texi 23 Jul 2005 14:27:54 -0000 1.8
+++ qemu-tech.texi 30 Apr 2006 20:38:23 -0000
@@ -1,7 +1,12 @@
\input texinfo @c -*- texinfo -*-
+@c %**start of header
+@setfilename qemu-tech.info
+@settitle QEMU Internals
+@exampleindent 0
+@paragraphindent 0
+@c %**end of header
@iftex
-@settitle QEMU Internals
@titlepage
@sp 7
@center @titlefont{QEMU Internals}
@@ -9,8 +14,32 @@
@end titlepage
@end iftex
+@ifnottex
+@node Top
+@top
+
+@menu
+* Introduction::
+* QEMU Internals::
+* Regression Tests::
+* Index::
+@end menu
+@end ifnottex
+
+@contents
+
+@node Introduction
@chapter Introduction
+@menu
+* intro_features:: Features
+* intro_x86_emulation:: x86 emulation
+* intro_arm_emulation:: ARM emulation
+* intro_ppc_emulation:: PowerPC emulation
+* intro_sparc_emulation:: SPARC emulation
+@end menu
+
+@node intro_features
@section Features
QEMU is a FAST! processor emulator using a portable dynamic
@@ -43,7 +72,7 @@
@item User space only or full system emulation.
-@item Using dynamic translation to native code for reasonnable speed.
+@item Using dynamic translation to native code for reasonable speed.
@item Working on x86 and PowerPC hosts. Being tested on ARM, Sparc32, Alpha and S390.
@@ -65,13 +94,13 @@
@item Accurate signal handling by remapping host signals to target signals.
@end itemize
-@end itemize
QEMU full system emulation features:
@itemize
@item QEMU can either use a full software MMU for maximum portability or use the host system call mmap() to simulate the target MMU.
@end itemize
+@node intro_x86_emulation
@section x86 emulation
QEMU x86 target features:
@@ -110,6 +139,7 @@
@end itemize
+@node intro_arm_emulation
@section ARM emulation
@itemize
@@ -122,6 +152,7 @@
@end itemize
+@node intro_ppc_emulation
@section PowerPC emulation
@itemize
@@ -133,6 +164,7 @@
@end itemize
+@node intro_sparc_emulation
@section SPARC emulation
@itemize
@@ -166,8 +198,26 @@
@end itemize
+@node QEMU Internals
@chapter QEMU Internals
+@menu
+* QEMU compared to other emulators::
+* Portable dynamic translation::
+* Register allocation::
+* Condition code optimisations::
+* CPU state optimisations::
+* Translation cache::
+* Direct block chaining::
+* Self-modifying code and translated code invalidation::
+* Exception support::
+* MMU emulation::
+* Hardware interrupts::
+* User emulation specific details::
+* Bibliography::
+@end menu
+
+@node QEMU compared to other emulators
@section QEMU compared to other emulators
Like bochs [3], QEMU emulates an x86 CPU. But QEMU is much faster than
@@ -214,6 +264,7 @@
and potentially unsafe host drivers. Moreover, they are unable to
provide cycle exact simulation as an emulator can.
+@node Portable dynamic translation
@section Portable dynamic translation
QEMU is a dynamic translator. When it first encounters a piece of code,
@@ -243,6 +294,7 @@
To go even faster, GCC static register variables are used to keep the
state of the virtual CPU.
+@node Register allocation
@section Register allocation
Since QEMU uses fixed simple instructions, no efficient register
@@ -250,6 +302,7 @@
register, most of the virtual CPU state can be put in registers without
doing complicated register allocation.
+@node Condition code optimisations
@section Condition code optimisations
Good CPU condition codes emulation (@code{EFLAGS} register on x86) is a
@@ -268,6 +321,7 @@
the condition codes are not needed by the next instructions, no
condition codes are computed at all.
+@node CPU state optimisations
@section CPU state optimisations
The x86 CPU has many internal states which change the way it evaluates
@@ -279,6 +333,7 @@
[The FPU stack pointer register is not handled that way yet].
+@node Translation cache
@section Translation cache
A 16 MByte cache holds the most recently used translations. For
@@ -287,6 +342,7 @@
terminated by a jump or by a virtual CPU state change which the
translator cannot deduce statically).
+@node Direct block chaining
@section Direct block chaining
After each translated basic block is executed, QEMU uses the simulated
@@ -302,6 +358,7 @@
architectures (such as x86 or PowerPC), the @code{JUMP} opcode is
directly patched so that the block chaining has no overhead.
+@node Self-modifying code and translated code invalidation
@section Self-modifying code and translated code invalidation
Self-modifying code is a special challenge in x86 emulation because no
@@ -332,6 +389,7 @@
really needs to be invalidated. It avoids invalidating the code when
only data is modified in the page.
+@node Exception support
@section Exception support
longjmp() is used when an exception such as division by zero is
@@ -348,6 +406,7 @@
optimisations. It is not a big concern because the emulated code can
still be restarted in any cases.
+@node MMU emulation
@section MMU emulation
For system emulation, QEMU uses the mmap() system call to emulate the
@@ -367,6 +426,7 @@
When MMU mappings change, only the chaining of the basic blocks is
reset (i.e. a basic block can no longer jump directly to another one).
+@node Hardware interrupts
@section Hardware interrupts
In order to be faster, QEMU does not check at every basic block if an
@@ -377,6 +437,7 @@
of the CPU emulator. Then the main loop can test if the interrupt is
pending and handle it.
+@node User emulation specific details
@section User emulation specific details
@subsection Linux system call translation
@@ -434,6 +495,7 @@
shared object as the ld-linux.so ELF interpreter. That way, it can be
relocated at load time.
+@node Bibliography
@section Bibliography
@table @asis
@@ -456,7 +518,7 @@
x86 emulator on Alpha-Linux.
@item [5]
-@url{http://www.usenix.org/publications/library/proceedings/usenix-nt97/full_papers/chernoff/chernoff.pdf},
+@url{http://www.usenix.org/publications/library/proceedings/usenix-nt97/@/full_papers/chernoff/chernoff.pdf},
DIGITAL FX!32: Running 32-Bit x86 Applications on Alpha NT, by Anton
Chernoff and Ray Hookway.
@@ -486,11 +548,19 @@
@end table
+@node Regression Tests
@chapter Regression Tests
In the directory @file{tests/}, various interesting testing programs
are available. There are used for regression testing.
+@menu
+* test-i386::
+* linux-test::
+* qruncom.c::
+@end menu
+
+@node test-i386
@section @file{test-i386}
This program executes most of the 16 bit and 32 bit x86 instructions and
@@ -506,12 +576,20 @@
Various exceptions are raised to test most of the x86 user space
exception reporting.
+@node linux-test
@section @file{linux-test}
This program tests various Linux system calls. It is used to verify
that the system call parameters are correctly converted between target
and host CPUs.
+@node qruncom.c
@section @file{qruncom.c}
Example of usage of @code{libqemu} to emulate a user mode i386 CPU.
+
+@node Index
+@chapter Index
+@printindex cp
+
+@bye
[-- Attachment #4: Makefile.patch --]
[-- Type: text/plain, Size: 532 bytes --]
Index: Makefile
===================================================================
RCS file: /sources/qemu/qemu/Makefile,v
retrieving revision 1.97
diff -u -b -B -u -r1.97 Makefile
--- Makefile 23 Apr 2006 17:57:59 -0000 1.97
+++ Makefile 30 Apr 2006 20:39:40 -0000
@@ -85,6 +85,12 @@
%.html: %.texi
texi2html -monolithic -number $<
+%.info: %.texi
+ makeinfo $< -o $@
+
+%.dvi: %.texi
+ texi2dvi $<
+
qemu.1: qemu-doc.texi
$(SRC_PATH)/texi2pod.pl $< qemu.pod
pod2man --section=1 --center=" " --release=" " qemu.pod > $@
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [Qemu-devel] [PATCH] VNC display support for QEMU
2006-04-30 1:03 ` Johannes Schindelin
2006-04-30 4:24 ` Anthony Liguori
@ 2006-05-01 5:02 ` Troy Benjegerdes
1 sibling, 0 replies; 14+ messages in thread
From: Troy Benjegerdes @ 2006-05-01 5:02 UTC (permalink / raw)
To: qemu-devel
On Sun, Apr 30, 2006 at 03:03:55AM +0200, Johannes Schindelin wrote:
> Hi,
>
> On Sat, 29 Apr 2006, Anthony Liguori wrote:
>
> > One thing you may notice is that RealVNC has some issues with being
> > disconnected. This is because it likes to switch from 8bit to 32bit depths
> > automatically at startup. Unfortunately, there is a race condition in the VNC
> > protocol and since this implementation is asynchronous, we seem to be much
> > more prone to exposing this.
>
> This, along with other problems, has been solved with LibVNCServer. But of
> course, you are welcome to solve them again.
I have noticed that interactive performance with the current libvncserver
based patches is quite bad compared to doing the same thing on SDL.
Maybe re-implementing vnc will uncover why it is slow.
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [Qemu-devel] [PATCH] VNC display support for QEMU
2006-04-29 21:34 [Qemu-devel] [PATCH] VNC display support for QEMU Anthony Liguori
2006-04-30 1:03 ` Johannes Schindelin
@ 2006-05-01 5:29 ` Troy Benjegerdes
2006-05-01 6:01 ` Brad Campbell
2 siblings, 0 replies; 14+ messages in thread
From: Troy Benjegerdes @ 2006-05-01 5:29 UTC (permalink / raw)
To: qemu-devel
> Where 1 is the first display (port 5901). This syntax may change in the
> near future to support binding to a particular interface. It's very
> useful to use an absolute mouse with VNC as the relative support is
> quite poor. It may be useful to adapt the libvncserver patch's
> calibration code here but I've not attempted to do that yet.
>
> This patch is still experimental. I've tested it with RealVNC and
> TightVNC under a variety of depths but I won't be suprised if there are
> still problems. I only implement Raw, CopyRect, and Hextile encodings
> too. Any sort of palette color mode or pixel format that QEMU doesn't
> support will not work either.
>
> One thing you may notice is that RealVNC has some issues with being
> disconnected. This is because it likes to switch from 8bit to 32bit
> depths automatically at startup. Unfortunately, there is a race
> condition in the VNC protocol and since this implementation is
> asynchronous, we seem to be much more prone to exposing this.
>
> A short near-term TODO list is:
>
> 1) More testing
> 2) Support switching between monitor/serial
> 3) Support a better encoding (like TightEncoding or ZRLE)
> 4) Support a vnc password (and perhaps stuff like TLS)
>
> Any feedback is greatly appreciated (especially with how it works with
> clients I've not tested).
realvnc on debian-ppc (xvncviewer-3.3.7) has endian issues (the colors
are wrong). However, mouse tracking and dragging windows actually
*works*. (This is with the version currently in cvs)
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [Qemu-devel] [PATCH] VNC display support for QEMU
2006-04-29 21:34 [Qemu-devel] [PATCH] VNC display support for QEMU Anthony Liguori
2006-04-30 1:03 ` Johannes Schindelin
2006-05-01 5:29 ` Troy Benjegerdes
@ 2006-05-01 6:01 ` Brad Campbell
2006-05-01 6:03 ` Brad Campbell
2006-05-01 9:08 ` Johannes Schindelin
2 siblings, 2 replies; 14+ messages in thread
From: Brad Campbell @ 2006-05-01 6:01 UTC (permalink / raw)
To: qemu-devel
Anthony Liguori wrote:
> Hi,
>
> The attach patch adds VNC display support for QEMU. It does not use
> libvncserver but was rather written from scratch. libvncserver is a
> really neat project and I've used it in a number of other projects but I
> think QEMU really requires a custom implementation.
>
Nice job.. Improves VNC interactivity nicely..
I use xtightvncviewer with the -bgr option to cut down network bandwidth quite a bit. This generates
funky colours with the current patch but works with the old implementation.
I'll take a look when I get the chance..
Also I can't access the monitor (which I can with the other vnc patch) ... again, when I get a chance.
I need to look at the protocol and see if there is a way to instruct the client to change its size
on the fly also.. at the moment booting win2k I have three different client sizes and need to
close/reopen the client for each change.
Nice work. The optimisations to the qemu portion speed up the display refreshes significantly.
Brad
--
"Human beings, who are almost unique in having the ability
to learn from the experience of others, are also remarkable
for their apparent disinclination to do so." -- Douglas Adams
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2006-05-01 9:08 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-04-29 21:34 [Qemu-devel] [PATCH] VNC display support for QEMU Anthony Liguori
2006-04-30 1:03 ` Johannes Schindelin
2006-04-30 4:24 ` Anthony Liguori
2006-04-30 10:43 ` Johannes Schindelin
2006-04-30 20:14 ` Anthony Liguori
2006-04-30 22:14 ` Christian MICHON
2006-04-30 23:11 ` Christian MICHON
2006-04-30 23:46 ` [Qemu-devel] " Anthony Liguori
2006-04-30 20:57 ` [Qemu-devel] [PATCH] Enhanced Documentation Stefan Weil
2006-05-01 5:02 ` [Qemu-devel] [PATCH] VNC display support for QEMU Troy Benjegerdes
2006-05-01 5:29 ` Troy Benjegerdes
2006-05-01 6:01 ` Brad Campbell
2006-05-01 6:03 ` Brad Campbell
2006-05-01 9:08 ` Johannes Schindelin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).