]> xenbits.xensource.com Git - qemu-xen-3.4-testing.git/commitdiff
Merge branch 'qemu'
authorIan Jackson <ian.jackson@eu.citrix.com>
Thu, 12 Mar 2009 17:29:18 +0000 (17:29 +0000)
committerIan Jackson <Ian.Jackson@eu.citrix.com>
Thu, 12 Mar 2009 17:29:18 +0000 (17:29 +0000)
Conflicts:

.gitignore
Makefile
Makefile.target
block-raw-posix.c
bswap.h
console.c
hw/cirrus_vga.c
hw/ide.c
hw/iommu.c
hw/lsi53c895a.c
hw/ne2000.c
hw/pc.c
hw/pc.h
hw/pci.c
hw/ppc_chrp.c
hw/ppc_oldworld.c
hw/ppc_prep.c
hw/rtl8139.c
hw/scsi-disk.c
hw/usb-hid.c
hw/vga.c
hw/vga_int.h
sdl.c
sysemu.h
vl.c
vnc.c

54 files changed:
1  2 
.gitignore
Makefile
Makefile.target
audio/mixeng.c
block-qcow.c
block-raw-posix.c
block.c
configure
console.c
console.h
cutils.c
exec-all.h
hw/boards.h
hw/cirrus_vga.c
hw/dma.c
hw/eepro100.c
hw/ide.c
hw/iommu.c
hw/lsi53c895a.c
hw/mips_mipssim.c
hw/mips_r4k.c
hw/ne2000.c
hw/pc.c
hw/pc.h
hw/pci.c
hw/pci.h
hw/pcnet.c
hw/piix_pci.c
hw/rtl8139.c
hw/scsi-disk.c
hw/serial.c
hw/sun4u.c
hw/usb-hid.c
hw/vga.c
hw/vga_int.h
hw/vmware_vga.c
loader.c
monitor.c
nbd.c
net.c
net.h
osdep.c
qemu-char.c
qemu-char.h
qemu-common.h
qemu-lock.h
savevm.c
sdl.c
sysemu.h
usb-linux.c
vl.c
vnc.c
vnchextile.h
xen-vl-extra.c

diff --cc .gitignore
index 9e3690a81a66e9b4c4bfa8fb1c2309e91dfe61dd,3407943384cbe29573d006245fe4eab72bf1b580..fb0617cfdfd4d64084b9b0dfd20ac68b8a798913
@@@ -32,15 -31,8 +31,18 @@@ qemu-nbd.po
  *.vr
  *.d
  *.o
 +*.orig
  *~
- dyngen-xen
 +
+ .pc
+ patches
+ pc-bios/bios-pq/status
+ pc-bios/vgabios-pq/status
++
 +i386-dm/Makefile
 +i386-dm/config.mak
 +i386-dm/qemu-dm
++i386-dm/gdbstub-xml.c
 +qemu-img-xen
 +qemu-nbd-xen
- i386-dm/gdbstub-xml.c
 +dist
diff --cc Makefile
index e31fe822b125871cc847ef95d5aace044f807bc9,4db9dcc89f3ca1d0cbf578888d2786e58fa8141c..c8314c6943a44855f3b19508fdef9d615138fff8
+++ b/Makefile
@@@ -200,10 -198,6 +207,7 @@@ qemu-img$(EXESUF): qemu-img.o qemu-tool
  qemu-nbd$(EXESUF):  qemu-nbd.o qemu-tool.o osdep.o $(BLOCK_OBJS)
        $(CC) $(LDFLAGS) -o $@ $^ -lz $(LIBS)
  
- # dyngen host tool
- dyngen$(EXESUF): dyngen.o osdep.o
-       $(HOST_CC) $(CFLAGS) $(CPPFLAGS) -o $@ $^
 +
  clean:
  # avoid old build problems by removing potentially incorrect old files
        rm -f config.mak config.h op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
diff --cc Makefile.target
index 0d1ea15dd2122d1ae02a8c66fdb1df776d55005a,a97edd7b95c9bc47723d71dfaa221f7271a91795..7e9cbda6b7cfa327767ada5d4dadb15105c7486f
@@@ -183,8 -171,11 +171,13 @@@ CFLAGS+=-I/opt/SUNWspro/prod/include/c
  endif
  endif
  
 +default: all
 +
+ kvm.o: CFLAGS+=$(KVM_CFLAGS)
+ kvm-all.o: CFLAGS+=$(KVM_CFLAGS)
+ all: $(PROGS)
  #########################################################
  # cpu emulator library
  LIBOBJS=exec.o kqemu.o translate-all.o cpu-exec.o\
@@@ -264,13 -251,6 +253,9 @@@ endi
  
  # libqemu
  
- ifdef CONFIG_DYNGEN_OP
- OPC_H = gen-op.h dyngen-opc.h op.h
- endif
 +-include hookslib.mak
 +-include hookstarget.mak
 +
  libqemu.a: $(LIBOBJS)
        rm -f $@
        $(AR) rcs $@ $(LIBOBJS)
@@@ -545,14 -627,11 +632,14 @@@ OBJS += e1000.
  
  ifeq ($(TARGET_BASE_ARCH), i386)
  # Hardware support
 -OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o
 -OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pcspk.o pc.o
 +ifdef CONFIG_AUDIO
 +OBJS+= $(SOUND_HW) pcspk.o
 +CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE
 +endif
 +OBJS+= ide.o pckbd.o ps2.o vga.o dma.o
 +OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o
  OBJS+= cirrus_vga.o apic.o parallel.o acpi.o piix_pci.o
- OBJS+= usb-uhci.o vmmouse.o vmport.o vmware_vga.o
+ OBJS+= usb-uhci.o vmmouse.o vmport.o vmware_vga.o hpet.o
 -CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE
  endif
  ifeq ($(TARGET_BASE_ARCH), ppc)
  CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE
@@@ -698,10 -788,10 +799,10 @@@ endi
        $(CC) $(CPPFLAGS) -c -o $@ $<
  
  clean:
-       rm -f *.o *.a *~ $(PROGS) gen-op.h dyngen-opc.h op.h nwfpe/*.o fpu/*.o
+       rm -f *.o *.a *~ $(PROGS) nwfpe/*.o fpu/*.o
        rm -f *.d */*.d tcg/*.o
  
 -install: all
 +install: all install-hook
  ifneq ($(PROGS),)
        $(INSTALL) -m 755 -s $(PROGS) "$(DESTDIR)$(bindir)"
  endif
diff --cc audio/mixeng.c
Simple merge
diff --cc block-qcow.c
Simple merge
index 0237039a6ba70a7b230bbc3063b528a6bfeed9f1,7a895b457ef53beeea3b8c5b94a1be40b2ddff6a..4c1fec4c57bd74181b964555dabfc3de372a0ce0
@@@ -571,9 -525,9 +526,10 @@@ static void aio_signal_handler(int sign
  static int posix_aio_init(void)
  {
      struct sigaction act;
 +    sigset_t enable;
      PosixAioState *s;
      int fds[2];
+     struct qemu_paioinit ai;
    
      if (posix_aio_state)
          return 0;
diff --cc block.c
Simple merge
diff --cc configure
Simple merge
diff --cc console.c
index 859454916e07eac0c4588d43a120bc0d480e4091,4e088d7a6f4e114f11d2d5843339808a201074e3..147daf16d2949fe775fe19744e5e528c15770fe8
+++ b/console.c
@@@ -139,6 -139,6 +139,11 @@@ struct TextConsole 
      TextCell *cells;
      int text_x[2], text_y[2], cursor_invalidate;
  
++    int update_x0;
++    int update_y0;
++    int update_x1;
++    int update_y1;
++
      enum TTYState state;
      int esc_params[MAX_ESC_PARAMS];
      int nb_esc_params;
@@@ -184,7 -190,8 +189,7 @@@ static unsigned int vga_get_color(Displ
  {
      unsigned int r, g, b, color;
  
-     switch(ds->depth) {
+     switch(ds_get_bits_per_pixel(ds)) {
 -#if 0
      case 8:
          r = (rgba >> 16) & 0xff;
          g = (rgba >> 8) & 0xff;
@@@ -519,6 -529,14 +524,18 @@@ static void text_console_resize(TextCon
      s->cells = cells;
  }
  
 -static inline void text_update_xy(TextConsole *s, int x, int y)
++static void invalidate_xy(TextConsole *s, int x, int y)
+ {
 -    s->text_x[0] = MIN(s->text_x[0], x);
 -    s->text_x[1] = MAX(s->text_x[1], x);
 -    s->text_y[0] = MIN(s->text_y[0], y);
 -    s->text_y[1] = MAX(s->text_y[1], y);
++    if (s->update_x0 > x * FONT_WIDTH)
++        s->update_x0 = x * FONT_WIDTH;
++    if (s->update_y0 > y * FONT_HEIGHT)
++        s->update_y0 = y * FONT_HEIGHT;
++    if (s->update_x1 < (x + 1) * FONT_WIDTH)
++        s->update_x1 = (x + 1) * FONT_WIDTH;
++    if (s->update_y1 < (y + 1) * FONT_HEIGHT)
++        s->update_y1 = (y + 1) * FONT_HEIGHT;
+ }
  static void update_xy(TextConsole *s, int x, int y)
  {
      TextCell *c;
              c = &s->cells[y1 * s->width + x];
              vga_putcharxy(s->ds, x, y2, c->ch,
                            &(c->t_attrib));
--            dpy_update(s->ds, x * FONT_WIDTH, y2 * FONT_HEIGHT,
--                       FONT_WIDTH, FONT_HEIGHT);
++            invalidate_xy(s, x, y2);
          }
      }
  }
@@@ -554,13 -587,12 +580,11 @@@ static void console_show_cursor(TextCon
              if (show) {
                  TextAttributes t_attrib = s->t_attrib_default;
                  t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
-                 vga_putcharxy(s->ds, s->x, y, c->ch, &t_attrib);
+                 vga_putcharxy(s->ds, x, y, c->ch, &t_attrib);
              } else {
-                 vga_putcharxy(s->ds, s->x, y, c->ch,
-                               &(c->t_attrib));
+                 vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib));
              }
-             dpy_update(s->ds, s->x * FONT_WIDTH, y * FONT_HEIGHT,
 -            dpy_update(s->ds, x * FONT_WIDTH, y * FONT_HEIGHT,
--                       FONT_WIDTH, FONT_HEIGHT);
++            invalidate_xy(s, x, y);
          }
      }
  }
@@@ -572,8 -604,16 +596,8 @@@ static void console_refresh(TextConsol
  
      if (s != active_console)
          return;
 -    if (!ds_get_bits_per_pixel(s->ds)) {
 -        s->text_x[0] = 0;
 -        s->text_y[0] = 0;
 -        s->text_x[1] = s->width - 1;
 -        s->text_y[1] = s->height - 1;
 -        s->cursor_invalidate = 1;
 -        return;
 -    }
  
-     vga_fill_rect(s->ds, 0, 0, s->ds->width, s->ds->height,
+     vga_fill_rect(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds),
                    color_table[0][COLOR_BLACK]);
      y1 = s->y_displayed;
      for(y = 0; y < s->height; y++) {
          if (++y1 == s->total_height)
              y1 = 0;
      }
-     dpy_update(s->ds, 0, 0, s->ds->width, s->ds->height);
 -    dpy_update(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds));
      console_show_cursor(s, 1);
++    dpy_update(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds));
  }
  
  static void console_scroll(int ydelta)
@@@ -655,8 -703,8 +679,10 @@@ static void console_put_lf(TextConsole 
              vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
                            s->width * FONT_WIDTH, FONT_HEIGHT,
                            color_table[0][s->t_attrib_default.bgcol]);
--            dpy_update(s->ds, 0, 0,
--                       s->width * FONT_WIDTH, s->height * FONT_HEIGHT);
++            s->update_x0 = 0;
++            s->update_y0 = 0;
++            s->update_x1 = s->width * FONT_WIDTH;
++            s->update_y1 = s->height * FONT_HEIGHT;
          }
      }
  }
@@@ -1000,20 -1044,13 +1026,21 @@@ void console_select(unsigned int index
  
      if (index >= MAX_CONSOLES)
          return;
++    active_console->g_width = ds_get_width(active_console->ds);
++    active_console->g_height = ds_get_height(active_console->ds);
      s = consoles[index];
      if (s) {
++        DisplayState *ds = s->ds;
          active_console = s;
-         if (s->console_type == TEXT_CONSOLE) {
-             if (s->g_width != s->ds->width ||
-                 s->g_height != s->ds->height) {
-                 s->g_width = s->ds->width;
-                 s->g_height = s->ds->height;
-                 text_console_resize(s);
-             }
-             console_refresh(s);
 -        if (s->console_type != TEXT_CONSOLE && s->g_width && s->g_height
 -            && (s->g_width != ds_get_width(s->ds) || s->g_height != ds_get_height(s->ds)))
 -            dpy_resize(s->ds, s->g_width, s->g_height);
++        if (ds_get_bits_per_pixel(s->ds)) {
++            ds->surface = qemu_resize_displaysurface(ds, s->g_width,
++                    s->g_height, 32, 4 * s->g_width);
 +        } else {
-             vga_hw_invalidate();
++            s->ds->surface->width = s->width;
++            s->ds->surface->height = s->height;
 +        }
++        dpy_resize(s->ds);
+         vga_hw_invalidate();
      }
  }
  
@@@ -1022,11 -1059,11 +1049,20 @@@ static int console_puts(CharDriverStat
      TextConsole *s = chr->opaque;
      int i;
  
++    s->update_x0 = s->width * FONT_WIDTH;
++    s->update_y0 = s->height * FONT_HEIGHT;
++    s->update_x1 = 0;
++    s->update_y1 = 0;
      console_show_cursor(s, 0);
      for(i = 0; i < len; i++) {
          console_putchar(s, buf[i]);
      }
      console_show_cursor(s, 1);
++    if (ds_get_bits_per_pixel(s->ds) && s->update_x0 < s->update_x1) {
++        dpy_update(s->ds, s->update_x0, s->update_y0,
++                   s->update_x1 - s->update_x0,
++                   s->update_y1 - s->update_y0);
++    }
      return len;
  }
  
@@@ -1120,15 -1157,15 +1156,10 @@@ void kbd_put_keysym(int keysym
  static void text_console_invalidate(void *opaque)
  {
      TextConsole *s = (TextConsole *) opaque;
--
-     if (s->g_width != s->ds->width || s->g_height != s->ds->height) {
 -    if (s->g_width != ds_get_width(s->ds) || s->g_height != ds_get_height(s->ds)) {
--        if (s->console_type == TEXT_CONSOLE_FIXED_SIZE)
--            dpy_resize(s->ds, s->g_width, s->g_height);
--        else {
-             s->g_width = s->ds->width;
-             s->g_height = s->ds->height;
 -            s->g_width = ds_get_width(s->ds);
 -            s->g_height = ds_get_height(s->ds);
--            text_console_resize(s);
--        }
++    if (!ds_get_bits_per_pixel(s->ds) && s->console_type == TEXT_CONSOLE) {
++        s->g_width = ds_get_width(s->ds);
++        s->g_height = ds_get_height(s->ds);
++        text_console_resize(s);
      }
      console_refresh(s);
  }
@@@ -1160,6 -1197,6 +1191,18 @@@ static void text_console_update(void *o
      }
  }
  
++static TextConsole *get_graphic_console(DisplayState *ds)
++{
++    int i;
++    TextConsole *s;
++    for (i = 0; i < nb_consoles; i++) {
++        s = consoles[i];
++        if (s->console_type == GRAPHIC_CONSOLE && s->ds == ds)
++            return s;
++    }
++    return NULL;
++}
++
  static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
  {
      TextConsole *s;
              consoles[i] = consoles[i - 1];
          }
          consoles[i] = s;
++        nb_consoles++;
      }
      return s;
  }
  
--TextConsole *graphic_console_init(DisplayState *ds, vga_hw_update_ptr update,
--                                  vga_hw_invalidate_ptr invalidate,
--                                  vga_hw_screen_dump_ptr screen_dump,
--                                  vga_hw_text_update_ptr text_update,
--                                  void *opaque)
++DisplayState *graphic_console_init(vga_hw_update_ptr update,
++                                   vga_hw_invalidate_ptr invalidate,
++                                   vga_hw_screen_dump_ptr screen_dump,
++                                   vga_hw_text_update_ptr text_update,
++                                   void *opaque)
  {
      TextConsole *s;
++    DisplayState *ds;
++
++    ds = (DisplayState *) qemu_mallocz(sizeof(DisplayState));
++    if (ds == NULL)
++        return NULL;
++    ds->allocator = &default_allocator; 
++    ds->surface = qemu_create_displaysurface(ds, 640, 480, 32, 640 * 4);
  
      s = new_console(ds, GRAPHIC_CONSOLE);
--    if (!s)
--      return NULL;
++    if (s == NULL) {
++        qemu_free_displaysurface(ds);
++        qemu_free(ds);
++        return NULL;
++    }
      s->hw_update = update;
      s->hw_invalidate = invalidate;
      s->hw_screen_dump = screen_dump;
      s->hw_text_update = text_update;
      s->hw = opaque;
--    return s;
++
++    register_displaystate(ds);
++    return ds;
  }
  
  int is_graphic_console(void)
@@@ -1231,19 -1268,21 +1287,21 @@@ void console_color_init(DisplayState *d
      }
  }
  
--CharDriverState *text_console_init(DisplayState *ds, const char *p)
++static int n_text_consoles;
++static CharDriverState *text_consoles[128];
++static char *text_console_strs[128];
++
++static void text_console_do_init(CharDriverState *chr, DisplayState *ds, const char *p)
  {
--    CharDriverState *chr;
      TextConsole *s;
+     unsigned width;
+     unsigned height;
      static int color_inited;
  
--    chr = qemu_mallocz(sizeof(CharDriverState));
--    if (!chr)
--        return NULL;
      s = new_console(ds, (p == 0) ? TEXT_CONSOLE : TEXT_CONSOLE_FIXED_SIZE);
      if (!s) {
          free(chr);
--        return NULL;
++        return;
      }
      chr->opaque = s;
      chr->chr_write = console_puts;
      s->out_fifo.buf = s->out_fifo_buf;
      s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
      s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s);
++    s->ds = ds;
  
      if (!color_inited) {
          color_inited = 1;
      text_console_resize(s);
  
      qemu_chr_reset(chr);
++    if (chr->init)
++        chr->init(chr);
++}
++
++CharDriverState *text_console_init(const char *p)
++{
++    CharDriverState *chr;
++
++    chr = qemu_mallocz(sizeof(CharDriverState));
++    if (!chr)
++        return NULL;
++
++    if (n_text_consoles == 128) {
++        fprintf(stderr, "Too many text consoles\n");
++        exit(1);
++    }
++    text_consoles[n_text_consoles] = chr;
++    text_console_strs[n_text_consoles] = p ? qemu_strdup(p) : NULL;
++    n_text_consoles++;
  
      return chr;
  }
  
--void qemu_console_resize(QEMUConsole *console, int width, int height)
++void text_consoles_set_display(DisplayState *ds)
  {
--    if (console->g_width != width || console->g_height != height
-         || !console->ds->data) {
 -        || !ds_get_data(console->ds)) {
--        console->g_width = width;
--        console->g_height = height;
--        if (active_console == console) {
--            dpy_resize(console->ds, width, height);
--        }
++    int i;
++
++    for (i = 0; i < n_text_consoles; i++) {
++        text_console_do_init(text_consoles[i], ds, text_console_strs[i]);
++        qemu_free(text_console_strs[i]);
      }
++
++    n_text_consoles = 0;
  }
  
--void qemu_console_copy(QEMUConsole *console, int src_x, int src_y,
++void qemu_console_resize(DisplayState *ds, int width, int height)
++{
++    TextConsole *s = get_graphic_console(ds);
++    if (!s) return;
++    s->g_width = width;
++    s->g_height = height;
++    if (is_graphic_console()) {
++        ds->surface = qemu_resize_displaysurface(ds, width, height, 32, 4 * width);
++        dpy_resize(ds);
++    }
++}
++
++void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
                  int dst_x, int dst_y, int w, int h)
  {
--    if (active_console == console) {
--        if (console->ds->dpy_copy)
--            console->ds->dpy_copy(console->ds,
--                            src_x, src_y, dst_x, dst_y, w, h);
--        else {
--            /* TODO */
--            console->ds->dpy_update(console->ds, dst_x, dst_y, w, h);
--        }
++    if (is_graphic_console()) {
++        dpy_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
++    }
++}
++
++PixelFormat qemu_different_endianness_pixelformat(int bpp)
++{
++    PixelFormat pf;
++
++    memset(&pf, 0x00, sizeof(PixelFormat));
++
++    pf.bits_per_pixel = bpp;
++    pf.bytes_per_pixel = bpp / 8;
++    pf.depth = bpp == 32 ? 24 : bpp;
++
++    switch (bpp) {
++        case 24:
++            pf.rmask = 0x000000FF;
++            pf.gmask = 0x0000FF00;
++            pf.bmask = 0x00FF0000;
++            pf.rmax = 255;
++            pf.gmax = 255;
++            pf.bmax = 255;
++            pf.rshift = 0;
++            pf.gshift = 8;
++            pf.bshift = 16;
++            pf.rbits = 8;
++            pf.gbits = 8;
++            pf.bbits = 8;
++            break;
++        case 32:
++            pf.rmask = 0x0000FF00;
++            pf.gmask = 0x00FF0000;
++            pf.bmask = 0xFF000000;
++            pf.amask = 0x00000000;
++            pf.amax = 255;
++            pf.rmax = 255;
++            pf.gmax = 255;
++            pf.bmax = 255;
++            pf.ashift = 0;
++            pf.rshift = 8;
++            pf.gshift = 16;
++            pf.bshift = 24;
++            pf.rbits = 8;
++            pf.gbits = 8;
++            pf.bbits = 8;
++            pf.abits = 8;
++            break;
++        default:
++            break;
+     }
++    return pf;
++}
++
++PixelFormat qemu_default_pixelformat(int bpp)
++{
++    PixelFormat pf;
++
++    memset(&pf, 0x00, sizeof(PixelFormat));
++
++    pf.bits_per_pixel = bpp;
++    pf.bytes_per_pixel = bpp / 8;
++    pf.depth = bpp == 32 ? 24 : bpp;
++
++    switch (bpp) {
++        case 16:
++            pf.rmask = 0x0000F800;
++            pf.gmask = 0x000007E0;
++            pf.bmask = 0x0000001F;
++            pf.rmax = 31;
++            pf.gmax = 63;
++            pf.bmax = 31;
++            pf.rshift = 11;
++            pf.gshift = 5;
++            pf.bshift = 0;
++            pf.rbits = 5;
++            pf.gbits = 6;
++            pf.bbits = 5;
++            break;
++        case 24:
++            pf.rmask = 0x00FF0000;
++            pf.gmask = 0x0000FF00;
++            pf.bmask = 0x000000FF;
++            pf.rmax = 255;
++            pf.gmax = 255;
++            pf.bmax = 255;
++            pf.rshift = 16;
++            pf.gshift = 8;
++            pf.bshift = 0;
++            pf.rbits = 8;
++            pf.gbits = 8;
++            pf.bbits = 8;
++        case 32:
++            pf.rmask = 0x00FF0000;
++            pf.gmask = 0x0000FF00;
++            pf.bmask = 0x000000FF;
++            pf.amax = 255;
++            pf.rmax = 255;
++            pf.gmax = 255;
++            pf.bmax = 255;
++            pf.ashift = 24;
++            pf.rshift = 16;
++            pf.gshift = 8;
++            pf.bshift = 0;
++            pf.rbits = 8;
++            pf.gbits = 8;
++            pf.bbits = 8;
++            pf.abits = 8;
++            break;
++        default:
++            break;
++    }
++    return pf;
++}
++
++DisplaySurface* defaultallocator_create_displaysurface(int width, int height, int bpp, int linesize)
++{
++    DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
++    if (surface == NULL) {
++        fprintf(stderr, "defaultallocator_create_displaysurface: malloc failed\n");
++        exit(1);
 +    }
++
++    surface->width = width;
++    surface->height = height;
++    surface->linesize = linesize;
++    surface->pf = qemu_default_pixelformat(bpp);
++#ifdef WORDS_BIGENDIAN
++    surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
++#else
++    surface->flags = QEMU_ALLOCATED_FLAG;
++#endif
++    surface->data = (uint8_t*) qemu_mallocz(surface->linesize * surface->height);
++    if (surface->data == NULL) {
++        fprintf(stderr, "defaultallocator_create_displaysurface: malloc failed\n");
++        exit(1);
++    }
++
++    return surface;
++}
++
++DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface,
++                                          int width, int height, int bpp, int linesize)
++{
++    surface->width = width;
++    surface->height = height;
++    surface->linesize = linesize;
++    surface->pf = qemu_default_pixelformat(bpp);
++    if (surface->flags & QEMU_ALLOCATED_FLAG)
++        surface->data = (uint8_t*) qemu_realloc(surface->data, surface->linesize * surface->height);
++    else
++        surface->data = (uint8_t*) qemu_malloc(surface->linesize * surface->height);
++    if (surface->data == NULL) {
++        fprintf(stderr, "defaultallocator_resize_displaysurface: malloc failed\n");
++        exit(1);
++    }
++#ifdef WORDS_BIGENDIAN
++    surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
++#else
++    surface->flags = QEMU_ALLOCATED_FLAG;
++#endif
++
++    return surface;
++}
++
++DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
++                                              int linesize, uint8_t *data)
++{
++    DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
++    if (surface == NULL) {
++        fprintf(stderr, "qemu_create_displaysurface_from: malloc failed\n");
++        exit(1);
++    }
++
++    surface->width = width;
++    surface->height = height;
++    surface->linesize = linesize;
++    surface->pf = qemu_default_pixelformat(bpp);
++#ifdef WORDS_BIGENDIAN
++    surface->flags = QEMU_BIG_ENDIAN_FLAG;
++#endif
++    surface->data = data;
++
++    return surface;
++}
++
++void defaultallocator_free_displaysurface(DisplaySurface *surface)
++{
++    if (surface == NULL)
++        return;
++    if (surface->flags & QEMU_ALLOCATED_FLAG)
++        qemu_free(surface->data);
++    qemu_free(surface);
  }
diff --cc console.h
Simple merge
diff --cc cutils.c
index 97d6080d0a0d9a0d8402a82419fed3e675ab7dbf,9617e083c6434e0b2bccef3d8a6493ee68a13818..6136e8dc3304ad53bad6ba39af99fe7494f903eb
+++ b/cutils.c
@@@ -22,8 -22,9 +22,9 @@@
   * THE SOFTWARE.
   */
  #include "qemu-common.h"
+ #include "host-utils.h"
  
 -void pstrcpy(char *buf, int buf_size, const char *str)
 +void pstrcpy(char *buf, size_t buf_size, const char *str)
  {
      int c;
      char *q = buf;
diff --cc exec-all.h
Simple merge
diff --cc hw/boards.h
Simple merge
diff --cc hw/cirrus_vga.c
index e1a416b83b6ea20047aa32488648ceb12a0ca3de,f9ad479573bc28af7e7570c10eee31f76d059c3c..cb22c389121d8e4a5c09ed01455dbdaa5aeaf5e4
@@@ -1397,6 -1399,6 +1399,21 @@@ cirrus_hook_write_sr(CirrusVGAState * s
        s->sr[reg_index] = (s->sr[reg_index] & 0x38) | (reg_value & 0xc7);
          cirrus_update_memory_access(s);
          break;
++
++
++       // Extension to allow BIOS to clear 16K VRAM bank in one operation
++    case 0xFE:
++       s->gr[reg_index] = reg_value;  // Lower byte of value to be written
++       break;
++    case 0xFF:
++        {
++            target_phys_addr_t addr;
++            for (addr = 0xa0000; addr < 0xa4000; addr += 2)
++                cirrus_vga_mem_writew(s, addr, (reg_value << 8) | s->gr[0xFE]);
++        }
++        break;
++     default:
++
      default:
  #ifdef DEBUG_CIRRUS
        printf("cirrus: outport sr_index %02x, sr_value %02x\n", reg_index,
@@@ -2639,10 -2631,50 +2646,55 @@@ static CPUWriteMemoryFunc *cirrus_linea
      cirrus_linear_bitblt_writel,
  };
  
 -
+ static void map_linear_vram(CirrusVGAState *s)
+ {
++    if (s->lfb_addr && s->lfb_end && s->vram_gmfn != s->lfb_addr) {
++        set_vram_mapping(s, s->lfb_addr, s->lfb_end);
++    }
+     if (!s->map_addr && s->lfb_addr && s->lfb_end) {
+         s->map_addr = s->lfb_addr;
+         s->map_end = s->lfb_end;
+         cpu_register_physical_memory(s->map_addr, s->map_end - s->map_addr, s->vram_offset);
+         vga_dirty_log_start((VGAState *)s);
+     }
+     if (!s->map_addr)
+         return;
+     s->lfb_vram_mapped = 0;
+     if (!(s->cirrus_srcptr != s->cirrus_srcptr_end)
+         && !((s->sr[0x07] & 0x01) == 0)
+         && !((s->gr[0x0B] & 0x14) == 0x14)
+         && !(s->gr[0x0B] & 0x02)) {
+         cpu_register_physical_memory(isa_mem_base + 0xa0000, 0x8000,
+                                     (s->vram_offset + s->cirrus_bank_base[0]) | IO_MEM_RAM);
+         cpu_register_physical_memory(isa_mem_base + 0xa8000, 0x8000,
+                                     (s->vram_offset + s->cirrus_bank_base[1]) | IO_MEM_RAM);
+         s->lfb_vram_mapped = 1;
+         vga_dirty_log_start((VGAState *)s);
+     }
+     else {
+         cpu_register_physical_memory(isa_mem_base + 0xa0000, 0x8000, s->vga_io_memory);
+         cpu_register_physical_memory(isa_mem_base + 0xa8000, 0x8000, s->vga_io_memory);
+     }
+ }
  
void cirrus_restart_acc(CirrusVGAState *s)
static void unmap_linear_vram(CirrusVGAState *s)
  {
-     set_vram_mapping(s, s->lfb_addr, s->lfb_end);
++    if (s->lfb_addr && s->lfb_end && s->vram_gmfn != s->lfb_addr) {
++        unset_vram_mapping(s);
++    }
+     if (s->map_addr && s->lfb_addr && s->lfb_end) {
+         vga_dirty_log_stop((VGAState *)s);
+         s->map_addr = s->map_end = 0;
+     }
+     cpu_register_physical_memory(isa_mem_base + 0xa0000, 0x20000,
+                                  s->vga_io_memory);
  }
  
  /* Compute the memory access functions */
@@@ -3104,11 -3118,9 +3151,10 @@@ static void cirrus_vga_save(QEMUFile *f
  static int cirrus_vga_load(QEMUFile *f, void *opaque, int version_id)
  {
      CirrusVGAState *s = opaque;
-     uint64_t t;
 +    uint8_t vga_acc = 0;
      int ret;
  
 -    if (version_id > 2)
 +    if (version_id > 3)
          return -EINVAL;
  
      if (s->pci_dev && version_id >= 2) {
      qemu_get_be32s(f, &s->hw_cursor_x);
      qemu_get_be32s(f, &s->hw_cursor_y);
  
 +    qemu_get_8s(f, &vga_acc);
 +    /* XXX throwing away 32 bits */
 +    qemu_get_be32(f);
 +    qemu_get_be32s(f, &s->lfb_addr);
 +    /* XXX throwing away 32 bits */
 +    qemu_get_be32(f);
 +    qemu_get_be32s(f, &s->lfb_end);
 +
 +    if (version_id >= 3)
 +        qemu_get_be64s(f, &s->vram_gmfn);
 +    t = s->vram_gmfn;
 +    if (!s->vram_gmfn) {
 +        /* Old guest, VRAM is not mapped, we have to restore it
 +         * ourselves */
 +        s->vram_gmfn = vga_acc ? s->lfb_addr : VRAM_RESERVED_ADDRESS;
 +        xen_vga_populate_vram(s->vram_gmfn, s->vram_size);
 +    } else {
 +        xen_vga_vram_map(s->vram_gmfn, s->vram_size);
 +    }
 +    if (version_id < 3 || (!vga_acc && !t))
 +        qemu_get_buffer(f, s->vram_ptr, s->vram_size);
 +
+     cirrus_update_memory_access(s);
      /* force refresh */
      s->graphic_mode = -1;
      cirrus_update_bank_ptr(s, 0);
@@@ -3287,8 -3238,63 +3294,63 @@@ static void cirrus_reset(void *opaque
      s->get_resolution = cirrus_get_resolution;
      s->cursor_invalidate = cirrus_cursor_invalidate;
      s->cursor_draw_line = cirrus_cursor_draw_line;
+ }
+ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci)
+ {
+     int i;
+     static int inited;
+     if (!inited) {
+         inited = 1;
+         for(i = 0;i < 256; i++)
+             rop_to_index[i] = CIRRUS_ROP_NOP_INDEX; /* nop rop */
+         rop_to_index[CIRRUS_ROP_0] = 0;
+         rop_to_index[CIRRUS_ROP_SRC_AND_DST] = 1;
+         rop_to_index[CIRRUS_ROP_NOP] = 2;
+         rop_to_index[CIRRUS_ROP_SRC_AND_NOTDST] = 3;
+         rop_to_index[CIRRUS_ROP_NOTDST] = 4;
+         rop_to_index[CIRRUS_ROP_SRC] = 5;
+         rop_to_index[CIRRUS_ROP_1] = 6;
+         rop_to_index[CIRRUS_ROP_NOTSRC_AND_DST] = 7;
+         rop_to_index[CIRRUS_ROP_SRC_XOR_DST] = 8;
+         rop_to_index[CIRRUS_ROP_SRC_OR_DST] = 9;
+         rop_to_index[CIRRUS_ROP_NOTSRC_OR_NOTDST] = 10;
+         rop_to_index[CIRRUS_ROP_SRC_NOTXOR_DST] = 11;
+         rop_to_index[CIRRUS_ROP_SRC_OR_NOTDST] = 12;
+         rop_to_index[CIRRUS_ROP_NOTSRC] = 13;
+         rop_to_index[CIRRUS_ROP_NOTSRC_OR_DST] = 14;
+         rop_to_index[CIRRUS_ROP_NOTSRC_AND_NOTDST] = 15;
+         s->device_id = device_id;
+         if (is_pci)
+             s->bustype = CIRRUS_BUSTYPE_PCI;
+         else
+             s->bustype = CIRRUS_BUSTYPE_ISA;
+     }
  
 -    register_savevm("cirrus_vga", 0, 2, cirrus_vga_save, cirrus_vga_load, s);
+     register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
+     register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
+     register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);
+     register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);
+     register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);
+     register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
+     register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);
+     register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);
+     register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
+     register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
+     s->vga_io_memory = cpu_register_io_memory(0, cirrus_vga_mem_read,
+                                            cirrus_vga_mem_write, s);
+     cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
+                                  s->vga_io_memory);
+     qemu_register_coalesced_mmio(isa_mem_base + 0x000a0000, 0x20000);
+     qemu_register_reset(cirrus_reset, s);
+     cirrus_reset(s);
 +    register_savevm("cirrus_vga", 0, 3, cirrus_vga_save, cirrus_vga_load, s);
  }
  
  /***************************************
@@@ -3302,13 -3308,8 +3364,13 @@@ void isa_cirrus_vga_init(DisplayState *
  {
      CirrusVGAState *s;
  
-     s = qemu_mallocz(sizeof(CirrusVGAState));
 +    if (vga_ram_size != 4*1024*1024) {
 +        fprintf(stderr, "The -videoram option does not work with the cirrus vga model. Video ram set to 4M. \n");
 +        vga_ram_size = 4*1024*1024;
 +    }
 +
+     s = qemu_mallocz(sizeof(CirrusVGAState));
      vga_common_init((VGAState *)s,
                      ds, vga_ram_base, vga_ram_offset, vga_ram_size);
      cirrus_init_common(s, CIRRUS_ID_CLGD5430, 0);
@@@ -3329,14 -3332,15 +3391,21 @@@ static void cirrus_pci_lfb_map(PCIDevic
      /* XXX: add byte swapping apertures */
      cpu_register_physical_memory(addr, s->vram_size,
                                 s->cirrus_linear_io_addr);
 +    s->lfb_addr = addr;
 +    s->lfb_end = addr + s->vram_size;
 +
 +    if (s->lfb_addr != s->vram_gmfn)
 +        fprintf(logfile, "cirrus vga map change while on lfb mode\n");
 +
      cpu_register_physical_memory(addr + 0x1000000, 0x400000,
                                 s->cirrus_linear_bitblt_io_addr);
+     s->map_addr = s->map_end = 0;
+     s->lfb_addr = addr & TARGET_PAGE_MASK;
+     s->lfb_end = ((addr + VGA_RAM_SIZE) + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
+     /* account for overflow */
+     if (s->lfb_end < addr + VGA_RAM_SIZE)
+         s->lfb_end = addr + VGA_RAM_SIZE;
  }
  
  static void cirrus_pci_mmio_map(PCIDevice *d, int region_num,
@@@ -3371,20 -3375,16 +3440,22 @@@ void pci_cirrus_vga_init(PCIBus *bus, D
      pci_conf[0x0a] = PCI_CLASS_SUB_VGA;
      pci_conf[0x0b] = PCI_CLASS_BASE_DISPLAY;
      pci_conf[0x0e] = PCI_CLASS_HEADERTYPE_00h;
-     /* setup VGA */
-     s = &d->cirrus_vga;
 +    pci_conf[0x2c] = 0x53; /* subsystem vendor: XenSource */
 +    pci_conf[0x2d] = 0x58;
 +    pci_conf[0x2e] = 0x01; /* subsystem device */
 +    pci_conf[0x2f] = 0x00;
 +
 +    if (vga_ram_size != 4*1024*1024) {
 +        fprintf(stderr, "The -videoram option does not work with the cirrus vga model. Video ram set to 4M. \n");
 +        vga_ram_size = 4*1024*1024;
 +    }
+     /* setup VGA */
+     s = &d->cirrus_vga;
      vga_common_init((VGAState *)s,
                      ds, vga_ram_base, vga_ram_offset, vga_ram_size);
      cirrus_init_common(s, device_id, 1);
 -    s->console = graphic_console_init(s->ds, s->update, s->invalidate,
 -                                      s->screen_dump, s->text_update, s);
 -
      s->pci_dev = (PCIDevice *)d;
  
      /* setup memory space */
diff --cc hw/dma.c
Simple merge
diff --cc hw/eepro100.c
Simple merge
diff --cc hw/ide.c
index da7057cabe770478b7d014d5f3fcf8d8ce72f2e0,41f94d95e56db0b1db48ab7ef5e4b49f00664493..42920b07635866c942b06c27cfad3e4238a67102
+++ b/hw/ide.c
@@@ -2907,103 -2755,6 +2938,46 @@@ static void ide_reset(IDEState *s
      s->media_changed = 0;
  }
  
- struct partition {
-       uint8_t boot_ind;               /* 0x80 - active */
-       uint8_t head;           /* starting head */
-       uint8_t sector;         /* starting sector */
-       uint8_t cyl;            /* starting cylinder */
-       uint8_t sys_ind;                /* What partition type */
-       uint8_t end_head;               /* end head */
-       uint8_t end_sector;     /* end sector */
-       uint8_t end_cyl;                /* end cylinder */
-       uint32_t start_sect;    /* starting sector counting from 0 */
-       uint32_t nr_sects;              /* nr of sectors in partition */
- } __attribute__((packed));
- /* try to guess the disk logical geometry from the MSDOS partition table. Return 0 if OK, -1 if could not guess */
- static int guess_disk_lchs(IDEState *s,
-                            int *pcylinders, int *pheads, int *psectors)
- {
-     uint8_t *buf = s->io_buffer;
-     int ret, i, heads, sectors, cylinders;
-     struct partition *p;
-     uint32_t nr_sects;
-     ret = bdrv_read(s->bs, 0, buf, 1);
-     if (ret < 0) {
-         return -1;
-     }
-     /* test msdos magic */
-     if (buf[510] != 0x55 || buf[511] != 0xaa) {
-         return -1;
-     }
-     for(i = 0; i < 4; i++) {
-         p = ((struct partition *)(buf + 0x1be)) + i;
-         nr_sects = le32_to_cpu(p->nr_sects);
-         if (nr_sects && p->end_head) {
-             /* We make the assumption that the partition terminates on
-                a cylinder boundary */
-             heads = p->end_head + 1;
-             sectors = p->end_sector & 63;
-             if (sectors == 0)
-                 continue;
-             cylinders = s->nb_sectors / (heads * sectors);
-             if (cylinders < 1 || cylinders > 16383)
-                 continue;
-             *pheads = heads;
-             *psectors = sectors;
-             *pcylinders = cylinders;
- #if 0
-             printf("guessed geometry: LCHS=%d %d %d\n",
-                    cylinders, heads, sectors);
- #endif
-             return 0;
-         }
-     }
-     return -1;
- }
 +/* Unplug all of the IDE hard disks, starting at index @start in the
 +   table. */
 +static void _ide_unplug_harddisks(int start)
 +{
 +    IDEState *s;
 +    int i, j;
 +
 +    if (!principal_ide_controller) {
 +        fprintf(stderr, "No principal controller?\n");
 +        return;
 +    }
 +    for (i = start; i < 4; i++) {
 +        s = principal_ide_controller->ide_if + i;
 +        if (!s->bs)
 +            continue; /* drive not present */
 +        if (s->is_cdrom)
 +            continue; /* cdrom */
 +        /* Is a hard disk, unplug it. */
 +        for (j = 0; j < nb_drives; j++)
 +            if (drives_table[j].bdrv == s->bs)
 +                drives_table[j].bdrv = NULL;
 +        bdrv_close(s->bs);
 +        s->bs = NULL;
 +        ide_reset(s);
 +    }
 +}
 +
 +/* Unplug all hard disks except for the primary master (which will
 +   almost always be the boot device). */
 +void ide_unplug_aux_harddisks(void)
 +{
 +    _ide_unplug_harddisks(1);
 +}
 +
 +/* Unplug all hard disks, including the boot device. */
 +void ide_unplug_harddisks(void)
 +{
 +    _ide_unplug_harddisks(0);
 +}
 +
  static void ide_init2(IDEState *ide_state,
                        BlockDriverState *hd0, BlockDriverState *hd1,
                        qemu_irq irq)
diff --cc hw/iommu.c
index 0ad697de7ef6309a1f56ea3cd87289c20effcaeb,82a49328841b2b9a8ef330e58f954abd681f35ba..b4ca11a08187e2100166e9cc7c4a5b665ab1781f
@@@ -109,16 -122,11 +122,15 @@@ do { printf("IOMMU: " fmt , ##args); } 
  #define IOPTE_VALID         0x00000002 /* IOPTE is valid */
  #define IOPTE_WAZ           0x00000001 /* Write as zeros */
  
- #define PAGE_SHIFT      12
 +#if defined(__i386__) || defined(__x86_64__)
- #define PAGE_SHIFT      14
+ #define IOMMU_PAGE_SHIFT    12
 +#elif defined(__ia64__)
- #define PAGE_SIZE       (1 << PAGE_SHIFT)
- #define PAGE_MASK       (PAGE_SIZE - 1)
++#define IOMMU_PAGE_SHIFT    14
 +#endif 
+ #define IOMMU_PAGE_SIZE     (1 << IOMMU_PAGE_SHIFT)
+ #define IOMMU_PAGE_MASK     ~(IOMMU_PAGE_SIZE - 1)
  
  typedef struct IOMMUState {
-     target_phys_addr_t addr;
      uint32_t regs[IOMMU_NREGS];
      target_phys_addr_t iostart;
      uint32_t version;
diff --cc hw/lsi53c895a.c
index 5f13f799b26b04abe492fec69924c260a5574c53,9f50dcbd187a7c6b13aabb00f1d3373c3486fb9f..db2882df1a2360cb03e1948ec53acb78db509a22
@@@ -1380,8 -1475,9 +1475,9 @@@ static uint8_t lsi_reg_readb(LSIState *
          shift = (offset & 3) * 8;
          return (s->scratch[n] >> shift) & 0xff;
      }
 -    BADF("readb 0x%x\n", offset);
 -    exit(1);
 +    /* XEN: This path can be triggered (e.g. ASPI8DOS.SYS reads 0x8). */
 +    return 0;
+ #undef CASE_GET_REG24
  #undef CASE_GET_REG32
  }
  
index 4c636dbb5b361e69a0b878a4848c509410fdc027,83f1a63e5c25c3902c947972069caa5823444084..2c48b00e021d605bc4a9e1706961f5acc84563c8
@@@ -194,7 -184,6 +184,6 @@@ QEMUMachine mips_mipssim_machine = 
      .name = "mipssim",
      .desc = "MIPS MIPSsim platform",
      .init = mips_mipssim_init,
 -    .ram_require = BIOS_SIZE + VGA_RAM_SIZE /* unused */,
 +    .ram_require = BIOS_SIZE /* unused */,
      .nodisk_ok = 1,
-     .max_cpus = 1,
  };
diff --cc hw/mips_r4k.c
index 670a1eabac6b5c31d28cb3f57550eeeaf644cba8,c12ab54b0913b1abc25abd18646f62c73965904c..9bf748d2713f7b17cacb272954331e0dedfc74af
@@@ -285,7 -275,6 +275,6 @@@ QEMUMachine mips_machine = 
      .name = "mips",
      .desc = "mips r4k platform",
      .init = mips_r4k_init,
 -    .ram_require = VGA_RAM_SIZE + BIOS_SIZE,
 +    .ram_require = BIOS_SIZE,
      .nodisk_ok = 1,
-     .max_cpus = 1,
  };
diff --cc hw/ne2000.c
index 0d1311834ca9af5733d43148b0c77c255045ec8a,a85730f8c7dd4a2d981fedaf0e7fb5fae61ee99f..0cb1c4aaf29a68ac722441f868e6b2f295ff296f
@@@ -773,19 -743,12 +775,12 @@@ void isa_ne2000_init(int base, qemu_ir
  
      ne2000_reset(s);
  
-     s->vc = qemu_new_vlan_client(nd->vlan, ne2000_receive,
-                                  ne2000_can_receive, s);
-     snprintf(s->vc->info_str, sizeof(s->vc->info_str),
-              "ne2000 macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
-              s->macaddr[0],
-              s->macaddr[1],
-              s->macaddr[2],
-              s->macaddr[3],
-              s->macaddr[4],
-              s->macaddr[5]);
-              
+     s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name,
+                                  ne2000_receive, ne2000_can_receive, s);
+     qemu_format_nic_info_str(s->vc, s->macaddr);
 -    register_savevm("ne2000", -1, 2, ne2000_save, ne2000_load, s);
 +    register_savevm("ne2000", base, 2, ne2000_save, ne2000_load, s);
  }
  
  /***********************************************************/
diff --cc hw/pc.c
index f0492c8abbeb9f882bcf071cdcac1636c5439aeb,d64e442601da8cac3016c0dd2d9009a12c6a890b..2ffbefdbb9229f13ecb22ebf21c13affd632e5b3
+++ b/hw/pc.c
  #include "smbus.h"
  #include "boards.h"
  #include "console.h"
 +#include "exec-all.h"
 +
 +#include "xen_platform.h"
  #include "fw_cfg.h"
+ #include "virtio-blk.h"
+ #include "virtio-balloon.h"
+ #include "virtio-console.h"
+ #include "hpet_emul.h"
  
  /* output Bochs bios info messages */
  //#define DEBUG_BIOS
@@@ -693,8 -684,7 +703,8 @@@ static void load_linux(uint8_t *option_
      memset(gpr, 0, sizeof gpr);
      gpr[4] = cmdline_addr-real_addr-16;       /* SP (-16 is paranoia) */
  
-     generate_bootsect(gpr, seg, 0);
+     generate_bootsect(option_rom, gpr, seg, 0);
 +#endif
  }
  
  static void main_cpu_reset(void *opaque)
@@@ -868,22 -852,24 +877,24 @@@ static void pc_init1(ram_addr_t ram_siz
          exit(1);
      }
  
-     /* VGA BIOS load */
-     if (cirrus_vga_enabled) {
-         snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_CIRRUS_FILENAME);
-     } else {
-         snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_FILENAME);
-     }
-     vga_bios_size = get_image_size(buf);
-     if (vga_bios_size <= 0 || vga_bios_size > 65536)
-         goto vga_bios_error;
-     vga_bios_offset = qemu_ram_alloc(65536);
-     ret = load_image_targphys(buf, vga_bios_offset, vga_bios_size);
-     if (ret != vga_bios_size) {
-     vga_bios_error:
-         fprintf(stderr, "qemu: could not load VGA BIOS '%s'\n", buf);
-         exit(1);
+     if (cirrus_vga_enabled || std_vga_enabled || vmsvga_enabled) {
+         /* VGA BIOS load */
+         if (cirrus_vga_enabled) {
+             snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_CIRRUS_FILENAME);
+         } else {
+             snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_FILENAME);
+         }
+         vga_bios_size = get_image_size(buf);
+         if (vga_bios_size <= 0 || vga_bios_size > 65536)
+             goto vga_bios_error;
+         vga_bios_offset = qemu_ram_alloc(65536);
 -        ret = load_image(buf, phys_ram_base + vga_bios_offset);
++        ret = load_image_targphys(buf, phys_ram_base + vga_bios_offset);
+         if (ret != vga_bios_size) {
+ vga_bios_error:
+             fprintf(stderr, "qemu: could not load VGA BIOS '%s'\n", buf);
+             exit(1);
+         }
      }
  
      /* setup basic memory access */
          }
      }
  
 +    if (pci_enabled) {
 +        PCI_EMULATION_INFO *p;
 +        for (p = PciEmulationInfoHead; p != NULL; p = p->next) {
 +            pci_emulation_init(pci_bus, p);
 +        }
 +    }
++
+     /* Add virtio block devices */
+     if (pci_enabled) {
+         int index;
+         int unit_id = 0;
+         while ((index = drive_get_index(IF_VIRTIO, 0, unit_id)) != -1) {
+             virtio_blk_init(pci_bus, drives_table[index].bdrv);
+             unit_id++;
+         }
+     }
+     /* Add virtio balloon device */
+     if (pci_enabled)
+         virtio_balloon_init(pci_bus);
+     /* Add virtio console devices */
+     if (pci_enabled) {
+         for(i = 0; i < MAX_VIRTIO_CONSOLES; i++) {
+             if (virtcon_hds[i])
+                 virtio_console_init(pci_bus, virtcon_hds[i]);
+         }
+     }
  }
  
  static void pc_init_pci(ram_addr_t ram_size, int vga_ram_size,
@@@ -1170,18 -1131,17 +1196,26 @@@ static void pc_init_isa(ram_addr_t ram_
  {
      pc_init1(ram_size, vga_ram_size, boot_device, ds,
               kernel_filename, kernel_cmdline,
 -             initrd_filename, 0, cpu_model);
 +             initrd_filename, 0, cpu_model,
 +             direct_pci);
 +}
 +
 +/* set CMOS shutdown status register (index 0xF) as S3_resume(0xFE)
 +   BIOS will read it and start S3 resume at POST Entry*/
 +void cmos_set_s3_resume(void)
 +{
 +    if (rtc_state)
 +        rtc_set_memory(rtc_state, 0xF, 0xFE);
  }
  
+ /* set CMOS shutdown status register (index 0xF) as S3_resume(0xFE)
+    BIOS will read it and start S3 resume at POST Entry */
+ void cmos_set_s3_resume(void)
+ {
+     if (rtc_state)
+         rtc_set_memory(rtc_state, 0xF, 0xFE);
+ }
  QEMUMachine pc_machine = {
      .name = "pc",
      .desc = "Standard PC",
diff --cc hw/pc.h
index a6000003924e7bfce083d846b78683d1c7473803,5dc770985ea0778eae27c6190d1077a966553eae..0a8f8e3d1108f53b07705a7d5b715d736a1136cc
+++ b/hw/pc.h
@@@ -96,9 -102,9 +103,12 @@@ i2c_bus *piix4_pm_init(PCIBus *bus, in
  void piix4_smbus_register_device(SMBusDevice *dev, uint8_t addr);
  void acpi_bios_init(void);
  
 +void acpi_php_add(int);
 +void acpi_php_del(int);
 +
+ /* hpet.c */
+ extern int no_hpet;
  /* pcspk.c */
  void pcspk_init(PITState *);
  int pcspk_audio_init(AudioState *, qemu_irq *pic);
diff --cc hw/pci.c
index e72c6694cae12232f9e72c3969e7a0e5232766c2,62b957a243ca5639d0f8199d9bc14bb103ae8d55..50b4009362b043e9a058edc4316161916880165b
+++ b/hw/pci.c
  #include "pci.h"
  #include "console.h"
  #include "net.h"
+ #include "virtio-net.h"
  
 +#include "exec-all.h"
 +#include "qemu-xen.h"
 +
  //#define DEBUG_PCI
  
  struct PCIBus {
@@@ -53,6 -51,9 +54,8 @@@ static void pci_update_mappings(PCIDevi
  static void pci_set_irq(void *opaque, int irq_num, int level);
  
  target_phys_addr_t pci_mem_base;
 -static int pci_irq_index;
+ static uint16_t pci_default_sub_vendor_id = PCI_SUBVENDOR_ID_REDHAT_QUMRANET;
+ static uint16_t pci_default_sub_device_id = PCI_SUBDEVICE_ID_QEMU;
  static PCIBus *first_bus;
  
  static int pcibus_load(QEMUFile *f, void *opaque, int version_id)
@@@ -624,73 -635,45 +640,87 @@@ void pci_info(void
      pci_for_each_device(0, pci_info_device);
  }
  
+ static const char * const pci_nic_models[] = {
+     "ne2k_pci",
+     "i82551",
+     "i82557b",
+     "i82559er",
+     "rtl8139",
++    "e100",
+     "e1000",
+     "pcnet",
+     "virtio",
+     NULL
+ };
+ typedef void (*PCINICInitFn)(PCIBus *, NICInfo *, int);
+ static PCINICInitFn pci_nic_init_fns[] = {
+     pci_ne2000_init,
+     pci_i82551_init,
+     pci_i82557b_init,
+     pci_i82559er_init,
+     pci_rtl8139_init,
++    pci_e100_init,
+     pci_e1000_init,
+     pci_pcnet_init,
+     virtio_net_init,
+     NULL
+ };
  /* Initialize a PCI NIC.  */
- void pci_nic_init(PCIBus *bus, NICInfo *nd, int devfn)
+ void pci_nic_init(PCIBus *bus, NICInfo *nd, int devfn,
+                   const char *default_model)
  {
-     if (strcmp(nd->model, "ne2k_pci") == 0) {
-         pci_ne2000_init(bus, nd, devfn);
-     } else if (strcmp(nd->model, "i82551") == 0) {
-         pci_i82551_init(bus, nd, devfn);
-     } else if (strcmp(nd->model, "i82557b") == 0) {
-         pci_i82557b_init(bus, nd, devfn);
-     } else if (strcmp(nd->model, "i82559er") == 0) {
-         pci_i82559er_init(bus, nd, devfn);
-     } else if (strcmp(nd->model, "rtl8139") == 0) {
-         pci_rtl8139_init(bus, nd, devfn);
-     } else if (strcmp(nd->model, "e1000") == 0) {
-         pci_e1000_init(bus, nd, devfn);
-     } else if (strcmp(nd->model, "pcnet") == 0) {
-         pci_pcnet_init(bus, nd, devfn);
-     } else if (strcmp(nd->model, "?") == 0) {
-         fprintf(stderr, "qemu: Supported PCI NICs: i82551 i82557b i82559er"
-                         " ne2k_pci pcnet rtl8139 e100 e1000\n");
-         exit (1);
-     } else {
-         fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model);
-         exit (1);
-     }
+     int i;
+     qemu_check_nic_model_list(nd, pci_nic_models, default_model);
+     for (i = 0; pci_nic_models[i]; i++)
+         if (strcmp(nd->model, pci_nic_models[i]) == 0)
+             pci_nic_init_fns[i](bus, nd, devfn);
  }
  
 +void pci_unplug_netifs(void)
 +{
 +    PCIBus *bus;
 +    PCIDevice *dev;
 +    PCIIORegion *region;
 +    int x;
 +    int i;
 +
 +    /* We only support one PCI bus */
 +    for (bus = first_bus; bus; bus = NULL) {
 +       for (x = 0; x < 256; x++) {
 +           dev = bus->devices[x];
 +           if (dev &&
 +               dev->config[0xa] == 0 &&
 +               dev->config[0xb] == 2) {
 +               /* Found a netif.  Remove it from the bus.  Note that
 +                  we don't free it here, since there could still be
 +                  references to it floating around.  There are only
 +                  ever one or two structures leaked, and it's not
 +                  worth finding them all. */
 +               bus->devices[x] = NULL;
 +               for (i = 0; i < PCI_NUM_REGIONS; i++) {
 +                   region = &dev->io_regions[i];
 +                   if (region->addr == (uint32_t)-1 ||
 +                       region->size == 0)
 +                       continue;
 +                   fprintf(logfile, "region type %d at [%x,%x).\n",
 +                           region->type, region->addr,
 +                           region->addr+region->size);
 +                   if (region->type == PCI_ADDRESS_SPACE_IO) {
 +                       isa_unassign_ioport(region->addr, region->size);
 +                   } else if (region->type == PCI_ADDRESS_SPACE_MEM) {
 +                       unregister_iomem(region->addr);
 +                   }
 +               }
 +           }
 +       }
 +    }
 +}
 +
  typedef struct {
      PCIDevice dev;
      PCIBus *bus;
diff --cc hw/pci.h
index a527a3975bed71df8c0a1952a3ecbdc95871f510,76f4474a5c06afae6f9b1082fc9c04998a4250b1..7645cd43798c88c06b1fab68f8856da4b5613a0a
+++ b/hw/pci.h
@@@ -162,10 -169,12 +195,15 @@@ void pci_pcnet_init(PCIBus *bus, NICInf
  PCIBus *pci_prep_init(qemu_irq *pic);
  
  /* apb_pci.c */
- PCIBus *pci_apb_init(target_phys_addr_t special_base, target_phys_addr_t mem_base,
-                      qemu_irq *pic);
+ PCIBus *pci_apb_init(target_phys_addr_t special_base,
+                      target_phys_addr_t mem_base,
+                      qemu_irq *pic, PCIBus **bus2, PCIBus **bus3);
+ /* sh_pci.c */
+ PCIBus *sh_pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
+                             qemu_irq *pic, int devfn_min, int nirq);
  
 +/* pass-through.c */
 +int pt_init(PCIBus *e_bus, const char *direct_pci_opt);
 +
  #endif
diff --cc hw/pcnet.c
Simple merge
diff --cc hw/piix_pci.c
Simple merge
diff --cc hw/rtl8139.c
index c464d6f67ca20eed5f1ee1002e478b760478f3e5,70cb080d267d0debcc032866b76fbcf5ba0c7a0e..31913f5116e463fd4c35166b669e139c1baf9d8c
@@@ -3477,8 -3461,7 +3484,8 @@@ void pci_rtl8139_init(PCIBus *bus, NICI
      s->cplus_txbuffer_len = 0;
      s->cplus_txbuffer_offset = 0;
  
 -    register_savevm("rtl8139", -1, 4, rtl8139_save, rtl8139_load, s);
 +    instance = pci_bus_num(bus) << 8 | s->pci_dev->devfn;
-     register_savevm("rtl8139", instance, 3, rtl8139_save, rtl8139_load, s);
++    register_savevm("rtl8139", instance, 4, rtl8139_save, rtl8139_load, s);
  
  #ifdef RTL8139_ONBOARD_TIMER
      s->timer = qemu_new_timer(vm_clock, rtl8139_timer, s);
diff --cc hw/scsi-disk.c
index 974a826b5b4371d51d203290b36e54940a297871,87bcf3d84fb8befc38c922514df5f640595d3693..d79998340712a1000a7a6fbf1bf063c0272709fb
@@@ -37,13 -39,9 +39,15 @@@ do { fprintf(stderr, "scsi-disk: " fmt 
  #define STATUS_GOOD            0
  #define STATUS_CHECK_CONDITION 2
  
 +#ifdef CONFIG_STUBDOM
 +#include <xen/io/blkif.h>
 +#define SCSI_DMA_BUF_SIZE    ((BLKIF_MAX_SEGMENTS_PER_REQUEST - 1) * PAGE_SIZE)
 +#else
  #define SCSI_DMA_BUF_SIZE    131072
 +#endif
 +
+ #define SCSI_MAX_INQUIRY_LEN 256
  typedef struct SCSIRequest {
      SCSIDeviceState *dev;
      uint32_t tag;
diff --cc hw/serial.c
Simple merge
diff --cc hw/sun4u.c
index 216629f6f93eb759b8adb59b13d2ac34d3b05d67,91e7538da18a45c0206806d37c6159c910df74cf..ed8ab50873c7189edbdf6558a10f72468be62eef
@@@ -587,25 -644,25 +644,25 @@@ QEMUMachine sun4u_machine = 
      .name = "sun4u",
      .desc = "Sun4u platform",
      .init = sun4u_init,
 -    .ram_require = PROM_SIZE_MAX + VGA_RAM_SIZE,
 +    .ram_require = PROM_SIZE_MAX,
      .nodisk_ok = 1,
-     .max_cpus = 16,
+     .max_cpus = 1, // XXX for now
  };
  
  QEMUMachine sun4v_machine = {
      .name = "sun4v",
      .desc = "Sun4v platform",
      .init = sun4v_init,
 -    .ram_require = PROM_SIZE_MAX + VGA_RAM_SIZE,
 +    .ram_require = PROM_SIZE_MAX,
      .nodisk_ok = 1,
-     .max_cpus = 16,
+     .max_cpus = 1, // XXX for now
  };
  
  QEMUMachine niagara_machine = {
      .name = "Niagara",
      .desc = "Sun4v platform, Niagara",
      .init = niagara_init,
 -    .ram_require = PROM_SIZE_MAX + VGA_RAM_SIZE,
 +    .ram_require = PROM_SIZE_MAX,
      .nodisk_ok = 1,
-     .max_cpus = 16,
+     .max_cpus = 1, // XXX for now
  };
diff --cc hw/usb-hid.c
index 4e4e1e143bea06a42d5a827bc33171f4aabcafd8,76fdce69126a20d220f44aec3878c535c7e99235..4f793e956bf5c231df7e63cab8a0fefcb60e3d31
@@@ -77,7 -65,8 +77,7 @@@ typedef struct USBHIDState 
      };
      int kind;
      int protocol;
-     int idle;
+     uint8_t idle;
 -    int changed;
      void *datain_opaque;
      void (*datain)(void *);
  } USBHIDState;
diff --cc hw/vga.c
index d1d61ea16a1ec4574e9cf4e816a3b18a398b88e8,bf84c246edadd6eb33e13fd672591e1f321f71cb..13519255794af03c9f9060183df37510deb39076
+++ b/hw/vga.c
@@@ -1169,14 -1157,20 +1169,11 @@@ static inline int get_depth_index(Displ
      case 8:
          return 0;
      case 15:
 -        if (s->bgr)
 -            return 5;
 -        else
 -            return 1;
 +        return 1;
      case 16:
 -        if (s->bgr)
 -            return 6;
 -        else
 -            return 2;
 +        return 2;
      case 32:
--        if (s->bgr)
--            return 4;
--        else
--            return 3;
++        return 3;
      }
  }
  
@@@ -1248,51 -1273,11 +1245,51 @@@ static void vga_draw_text(VGAState *s, 
      vga_draw_glyph8_func *vga_draw_glyph8;
      vga_draw_glyph9_func *vga_draw_glyph9;
  
 -    vga_dirty_log_stop(s);
 +    /* Disable dirty bit tracking */
 +    xc_hvm_track_dirty_vram(xc_handle, domid, 0, 0, NULL);
 +
 +    /* total width & height */
 +    cheight = (s->cr[9] & 0x1f) + 1;
 +    cw = 8;
 +    if (!(s->sr[1] & 0x01))
 +        cw = 9;
 +    if (s->sr[1] & 0x08)
 +        cw = 16; /* NOTE: no 18 pixel wide */
 +    width = (s->cr[0x01] + 1);
 +    if (s->cr[0x06] == 100) {
 +        /* ugly hack for CGA 160x100x16 - explain me the logic */
 +        height = 100;
 +    } else {
 +        height = s->cr[0x12] |
 +            ((s->cr[0x07] & 0x02) << 7) |
 +            ((s->cr[0x07] & 0x40) << 3);
 +        height = (height + 1) / cheight;
 +    }
 +    if ((height * width) > CH_ATTR_SIZE) {
 +        /* better than nothing: exit if transient size is too big */
 +        return;
 +    }
 +
-     s->last_scr_width = width * cw;
-     s->last_scr_height = height * cheight;
 +    if (width != s->last_width || height != s->last_height ||
 +        cw != s->last_cw || cheight != s->last_ch || s->last_depth) {
-         dpy_resize(s->ds, s->last_scr_width, s->last_scr_height);
++        s->last_scr_width = width * cw;
++        s->last_scr_height = height * cheight;
++        qemu_console_resize(s->ds, s->last_scr_width, s->last_scr_height);
 +        s->last_depth = 0;
++        s->last_width = width;
++        s->last_height = height;
++        s->last_ch = cheight;
++        s->last_cw = cw;
 +        full_update = 1;
 +    }
-     s->last_width = width;
-     s->last_height = height;
-     s->last_ch = cheight;
-     s->last_cw = cw;
 +
 +    s->rgb_to_pixel = 
 +        rgb_to_pixel_dup_table[get_depth_index(s->ds)];
  
      full_update |= update_palette16(s);
      palette = s->last_palette;
 -
 +    
-     x_incr = cw * ((s->ds->depth + 7) >> 3);
++    x_incr = cw * ds_get_bytes_per_pixel(s->ds);
      /* compute font data address (in plane 2) */
      v = s->sr[3];
      offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
      line_offset = s->line_offset;
      s1 = s->vram_ptr + (s->start_addr * 4);
  
 -    vga_get_text_resolution(s, &width, &height, &cw, &cheight);
 -    x_incr = cw * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
 +    /* total width & height */
 +    cheight = (s->cr[9] & 0x1f) + 1;
 +    cw = 8;
 +    if (!(s->sr[1] & 0x01))
 +        cw = 9;
 +    if (s->sr[1] & 0x08)
 +        cw = 16; /* NOTE: no 18 pixel wide */
-     x_incr = cw * ((s->ds->depth + 7) >> 3);
++    x_incr = cw * ds_get_bytes_per_pixel(s->ds);
 +    width = (s->cr[0x01] + 1);
 +    if (s->cr[0x06] == 100) {
 +        /* ugly hack for CGA 160x100x16 - explain me the logic */
 +        height = 100;
 +    } else {
 +        height = s->cr[0x12] |
 +            ((s->cr[0x07] & 0x02) << 7) |
 +            ((s->cr[0x07] & 0x40) << 3);
 +        height = (height + 1) / cheight;
 +    }
      if ((height * width) > CH_ATTR_SIZE) {
          /* better than nothing: exit if transient size is too big */
          return;
          cw != s->last_cw || cheight != s->last_ch) {
          s->last_scr_width = width * cw;
          s->last_scr_height = height * cheight;
--        qemu_console_resize(s->console, s->last_scr_width, s->last_scr_height);
++        qemu_console_resize(s->ds, s->last_scr_width, s->last_scr_height);
          s->last_width = width;
          s->last_height = height;
          s->last_ch = cheight;
@@@ -1615,39 -1620,6 +1612,51 @@@ static void vga_draw_graphic(VGAState *
          s->shift_control = shift_control;
          s->double_scan = double_scan;
      }
-     ds_depth = s->ds->depth;
 +    if (shift_control == 1 && (s->sr[0x01] & 8)) {
 +        disp_width <<= 1;
 +    }
 +
-     if (s->ds->dpy_resize_shared) {
-         if (s->line_offset != s->last_line_offset || 
-             disp_width != s->last_width ||
-             height != s->last_height ||
-             s->last_depth != depth) {
-             dpy_resize_shared(s->ds, disp_width, height, depth, s->line_offset, s->vram_ptr + (s->start_addr * 4));
-             s->last_scr_width = disp_width;
-             s->last_scr_height = height;
-             s->last_width = disp_width;
-             s->last_height = height;
-             s->last_line_offset = s->line_offset;
-             s->last_depth = depth;
-             full_update = 1;
-         } else if (s->ds->shared_buf && (full_update || s->ds->data != s->vram_ptr + (s->start_addr * 4)))
-             s->ds->dpy_setdata(s->ds, s->vram_ptr + (s->start_addr * 4));
-     } else if (disp_width != s->last_width ||
-                height != s->last_height) {
-         dpy_resize(s->ds, disp_width, height);
++    ds_depth = ds_get_bits_per_pixel(s->ds);
 +    depth = s->get_bpp(s);
++    if (s->line_offset != s->last_line_offset || 
++        disp_width != s->last_width ||
++        height != s->last_height ||
++        s->last_depth != depth) {
++#if defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
++        if (depth == 16 || depth == 32) {
++#else
++        if (depth == 32) {
++#endif
++            if (is_graphic_console()) {
++                qemu_free_displaysurface(s->ds);
++                s->ds->surface = qemu_create_displaysurface_from(disp_width, height, depth,
++                                                               s->line_offset,
++                                                               s->vram_ptr + (s->start_addr * 4));
++#if defined(WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
++                s->ds->surface->pf = qemu_different_endianness_pixelformat(depth);
++#endif
++                dpy_resize(s->ds);
++            } else {
++                qemu_console_resize(s->ds, disp_width, height);
++            }
++        } else {
++            qemu_console_resize(s->ds, disp_width, height);
++        }
 +        s->last_scr_width = disp_width;
 +        s->last_scr_height = height;
 +        s->last_width = disp_width;
 +        s->last_height = height;
++        s->last_line_offset = s->line_offset;
++        s->last_depth = depth;
 +        full_update = 1;
++    } else if (is_graphic_console() && is_buffer_shared(s->ds->surface) &&
++               (full_update || s->ds->surface->data != s->vram_ptr + (s->start_addr * 4))) {
++        s->ds->surface->data = s->vram_ptr + (s->start_addr * 4);
++        dpy_setdata(s->ds);
 +    }
 +
 +    s->rgb_to_pixel = 
 +        rgb_to_pixel_dup_table[get_depth_index(s->ds)];
  
      if (shift_control == 0) {
          full_update |= update_palette16(s);
              break;
          }
      }
 -    vga_draw_line = vga_draw_line_table[v * NB_DEPTHS + get_depth_index(s->ds)];
  
 -    if (disp_width != s->last_width ||
 -        height != s->last_height) {
 -        qemu_console_resize(s->console, disp_width, height);
 -        s->last_scr_width = disp_width;
 -        s->last_scr_height = height;
 -        s->last_width = disp_width;
 -        s->last_height = height;
 -        full_update = 1;
 -    }
 -    if (s->cursor_invalidate)
 +    vga_draw_line = vga_draw_line_table[v * NB_DEPTHS + get_depth_index(s->ds)];
-     if (!s->ds->shared_buf && s->cursor_invalidate)
++    if (!is_buffer_shared(s->ds->surface) && s->cursor_invalidate)
          s->cursor_invalidate(s);
  
      line_offset = s->line_offset;
      addr1 = (s->start_addr * 4);
      bwidth = (width * bits + 7) / 8;
      y_start = -1;
 -    page_min = 0x7fffffff;
 -    page_max = -1;
 +    page_min = 0;
 +    page_max = 0;
-     d = s->ds->data;
-     linesize = s->ds->linesize;
+     d = ds_get_data(s->ds);
+     linesize = ds_get_linesize(s->ds);
      y1 = 0;
      for(y = 0; y < height; y++) {
          addr = addr1;
          if (update) {
              if (y_start < 0)
                  y_start = y;
 -            if (page0 < page_min)
 +            if (page_min == 0 || page0 < page_min)
                  page_min = page0;
 -            if (page1 > page_max)
 +            if (page_max == 0 || page1 > page_max)
                  page_max = page1;
-             if (!s->ds->shared_buf) {
 -            vga_draw_line(s, d, s->vram_ptr + addr, width);
 -            if (s->cursor_draw_line)
 -                s->cursor_draw_line(s, d, y);
++            if (!is_buffer_shared(s->ds->surface)) {
 +                vga_draw_line(s, d, s->vram_ptr + addr, width);
 +                if (s->cursor_draw_line)
 +                    s->cursor_draw_line(s, d, y);
 +            }
          } else {
              if (y_start >= 0) {
                  /* flush to display */
@@@ -1841,21 -1774,17 +1850,21 @@@ static void vga_draw_blank(VGAState *s
          return;
      if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
          return;
 -    vga_dirty_log_stop(s);
  
-     if (s->ds->depth == 8)
 +    /* Disable dirty bit tracking */
 +    xc_hvm_track_dirty_vram(xc_handle, domid, 0, 0, NULL);
 +
 +    s->rgb_to_pixel =
 +        rgb_to_pixel_dup_table[get_depth_index(s->ds)];
+     if (ds_get_bits_per_pixel(s->ds) == 8)
          val = s->rgb_to_pixel(0, 0, 0);
      else
          val = 0;
-     w = s->last_scr_width * ((s->ds->depth + 7) >> 3);
-     d = s->ds->data;
 -    w = s->last_scr_width * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
++    w = s->last_scr_width * ds_get_bytes_per_pixel(s->ds);
+     d = ds_get_data(s->ds);
      for(i = 0; i < s->last_scr_height; i++) {
          memset(d, val, w);
-         d += s->ds->linesize;
+         d += ds_get_linesize(s->ds);
      }
      dpy_update(s->ds, 0, 0,
                 s->last_scr_width, s->last_scr_height);
@@@ -1870,9 -1799,12 +1879,9 @@@ static void vga_update_display(void *op
      VGAState *s = (VGAState *)opaque;
      int full_update, graphic_mode;
  
-     if (s->ds->depth == 0) {
+     if (ds_get_bits_per_pixel(s->ds) == 0) {
          /* nothing to do */
      } else {
 -        s->rgb_to_pixel =
 -            rgb_to_pixel_dup_table[get_depth_index(s->ds)];
 -
          full_update = 0;
          if (!(s->ar_index & 0x20)) {
              graphic_mode = GMODE_BLANK;
@@@ -1980,7 -1975,7 +1989,9 @@@ static void vga_update_text(void *opaqu
              cw != s->last_cw || cheight != s->last_ch) {
              s->last_scr_width = width * cw;
              s->last_scr_height = height * cheight;
--            qemu_console_resize(s->console, width, height);
++            s->ds->surface->width = width;
++            s->ds->surface->height = height;
++            dpy_resize(s->ds);
              s->last_width = width;
              s->last_height = height;
              s->last_ch = cheight;
      s->last_width = 60;
      s->last_height = height = 3;
      dpy_cursor(s->ds, -1, -1);
--    qemu_console_resize(s->console, s->last_width, height);
++    s->ds->surface->width = s->last_width;
++    s->ds->surface->height = height;
++    dpy_resize(s->ds);
  
      for (dst = chardata, i = 0; i < s->last_width * height; i ++)
          console_write_ch(dst ++, ' ');
@@@ -2290,207 -2199,36 +2303,207 @@@ static void vga_map(PCIDevice *pci_dev
      }
  }
  
 -void vga_dirty_log_stop(VGAState *s)
 +/* do the same job as vgabios before vgabios get ready - yeah */
 +void vga_bios_init(VGAState *s)
 +{
 +    uint8_t palette_model[192] = {
 +        0,   0,   0,   0,   0, 170,   0, 170,
 +      0,   0, 170, 170, 170,   0,   0, 170,
 +        0, 170, 170,  85,   0, 170, 170, 170,
 +       85,  85,  85,  85,  85, 255,  85, 255,
 +       85,  85, 255, 255, 255,  85,  85, 255,
 +       85, 255, 255, 255,  85, 255, 255, 255,
 +        0,  21,   0,   0,  21,  42,   0,  63,
 +        0,   0,  63,  42,  42,  21,   0,  42,
 +       21,  42,  42,  63,   0,  42,  63,  42,
 +        0,  21,  21,   0,  21,  63,   0,  63,
 +       21,   0,  63,  63,  42,  21,  21,  42,
 +       21,  63,  42,  63,  21,  42,  63,  63,
 +       21,   0,   0,  21,   0,  42,  21,  42,
 +        0,  21,  42,  42,  63,   0,   0,  63,
 +        0,  42,  63,  42,   0,  63,  42,  42,
 +       21,   0,  21,  21,   0,  63,  21,  42,
 +       21,  21,  42,  63,  63,   0,  21,  63,
 +        0,  63,  63,  42,  21,  63,  42,  63,
 +       21,  21,   0,  21,  21,  42,  21,  63,
 +        0,  21,  63,  42,  63,  21,   0,  63,
 +       21,  42,  63,  63,   0,  63,  63,  42,
 +       21,  21,  21,  21,  21,  63,  21,  63,
 +       21,  21,  63,  63,  63,  21,  21,  63,
 +       21,  63,  63,  63,  21,  63,  63,  63
 +    };
 +
 +    s->latch = 0;
 +
 +    s->sr_index = 3;
 +    s->sr[0] = 3;
 +    s->sr[1] = 0;
 +    s->sr[2] = 3;
 +    s->sr[3] = 0;
 +    s->sr[4] = 2;
 +    s->sr[5] = 0;
 +    s->sr[6] = 0;
 +    s->sr[7] = 0;
 +
 +    s->gr_index = 5;
 +    s->gr[0] = 0;
 +    s->gr[1] = 0;
 +    s->gr[2] = 0;
 +    s->gr[3] = 0;
 +    s->gr[4] = 0;
 +    s->gr[5] = 16;
 +    s->gr[6] = 14;
 +    s->gr[7] = 15;
 +    s->gr[8] = 255;
 +
 +    /* changed by out 0x03c0 */
 +    s->ar_index = 32;
 +    s->ar[0] = 0;
 +    s->ar[1] = 1;
 +    s->ar[2] = 2;
 +    s->ar[3] = 3;
 +    s->ar[4] = 4;
 +    s->ar[5] = 5;
 +    s->ar[6] = 6;
 +    s->ar[7] = 7;
 +    s->ar[8] = 8;
 +    s->ar[9] = 9;
 +    s->ar[10] = 10;
 +    s->ar[11] = 11;
 +    s->ar[12] = 12;
 +    s->ar[13] = 13;
 +    s->ar[14] = 14;
 +    s->ar[15] = 15;
 +    s->ar[16] = 12;
 +    s->ar[17] = 0;
 +    s->ar[18] = 15;
 +    s->ar[19] = 8;
 +    s->ar[20] = 0;
 +
 +    s->ar_flip_flop = 1;
 +
 +    s->cr_index = 15;
 +    s->cr[0] = 95;
 +    s->cr[1] = 79;
 +    s->cr[2] = 80;
 +    s->cr[3] = 130;
 +    s->cr[4] = 85;
 +    s->cr[5] = 129;
 +    s->cr[6] = 191;
 +    s->cr[7] = 31;
 +    s->cr[8] = 0;
 +    s->cr[9] = 79;
 +    s->cr[10] = 14;
 +    s->cr[11] = 15;
 +    s->cr[12] = 0;
 +    s->cr[13] = 0;
 +    s->cr[14] = 5;
 +    s->cr[15] = 160;
 +    s->cr[16] = 156;
 +    s->cr[17] = 142;
 +    s->cr[18] = 143;
 +    s->cr[19] = 40;
 +    s->cr[20] = 31;
 +    s->cr[21] = 150;
 +    s->cr[22] = 185;
 +    s->cr[23] = 163;
 +    s->cr[24] = 255;
 +
 +    s->msr = 103;
 +    s->fcr = 0;
 +    s->st00 = 0;
 +    s->st01 = 0;
 +
 +    /* dac_* & palette will be initialized by os through out 0x03c8 &
 +     * out 0c03c9(1:3) */
 +    s->dac_state = 0;
 +    s->dac_sub_index = 0;
 +    s->dac_read_index = 0;
 +    s->dac_write_index = 16;
 +    s->dac_cache[0] = 255;
 +    s->dac_cache[1] = 255;
 +    s->dac_cache[2] = 255;
 +
 +    /* palette */
 +    memcpy(s->palette, palette_model, 192);
 +
 +    s->bank_offset = 0;
 +    s->graphic_mode = -1;
 +
 +    /* TODO: add vbe support if enabled */
 +}
 +
 +
 +static VGAState *xen_vga_state;
 +
 +/* Allocate video memory in the GPFN space */
 +void xen_vga_populate_vram(uint64_t vram_addr, uint32_t vga_ram_size)
  {
 -    if (kvm_enabled() && s->map_addr)
 -        kvm_log_stop(s->map_addr, s->map_end - s->map_addr);
 +    unsigned long nr_pfn;
 +    xen_pfn_t *pfn_list;
 +    int i;
 +    int rc;
 +
 +    fprintf(logfile, "populating video RAM at %llx\n",
 +          (unsigned long long)vram_addr);
 +
 +    nr_pfn = vga_ram_size >> TARGET_PAGE_BITS;
  
 -    if (kvm_enabled() && s->lfb_vram_mapped) {
 -        kvm_log_stop(isa_mem_base + 0xa0000, 0x8000);
 -        kvm_log_stop(isa_mem_base + 0xa8000, 0x8000);
 +    pfn_list = malloc(sizeof(*pfn_list) * nr_pfn);
 +
 +    for (i = 0; i < nr_pfn; i++)
 +        pfn_list[i] = (vram_addr >> TARGET_PAGE_BITS) + i;
 +
 +    if (xc_domain_memory_populate_physmap(xc_handle, domid, nr_pfn, 0, 0, pfn_list)) {
 +        fprintf(stderr, "Failed to populate video ram\n");
 +        exit(1);
      }
 +    free(pfn_list);
 +
 +    xen_vga_vram_map(vram_addr, vga_ram_size);
 +
 +    /* Win2K seems to assume that the pattern buffer is at 0xff
 +       initially ! */
 +    memset(xen_vga_state->vram_ptr, 0xff, vga_ram_size);
  }
  
 -static void vga_map(PCIDevice *pci_dev, int region_num,
 -                    uint32_t addr, uint32_t size, int type)
 +/* Mapping the video memory from GPFN space  */
 +void xen_vga_vram_map(uint64_t vram_addr, uint32_t vga_ram_size)
  {
 -    PCIVGAState *d = (PCIVGAState *)pci_dev;
 -    VGAState *s = &d->vga_state;
 -    if (region_num == PCI_ROM_SLOT) {
 -        cpu_register_physical_memory(addr, s->bios_size, s->bios_offset);
 -    } else {
 -        cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
 -    }
 +    unsigned long nr_pfn;
 +    xen_pfn_t *pfn_list;
 +    int i;
 +    void *vram;
 +
 +    fprintf(logfile, "mapping video RAM from %llx\n",
 +          (unsigned long long)vram_addr);
 +
 +    nr_pfn = vga_ram_size >> TARGET_PAGE_BITS;
 +
 +    pfn_list = malloc(sizeof(*pfn_list) * nr_pfn);
 +
 +    for (i = 0; i < nr_pfn; i++)
 +        pfn_list[i] = (vram_addr >> TARGET_PAGE_BITS) + i;
  
 -    s->map_addr = addr;
 -    s->map_end = addr + VGA_RAM_SIZE;
 +    vram = xc_map_foreign_pages(xc_handle, domid,
 +                                        PROT_READ|PROT_WRITE,
 +                                        pfn_list, nr_pfn);
  
 -    vga_dirty_log_start(s);
 +    if (!vram) {
 +        fprintf(stderr, "Failed to map vram nr_pfn=0x%lx vram_addr=%llx: %s\n",
 +                nr_pfn, (unsigned long long)vram_addr, strerror(errno));
 +        exit(1);
 +    }
 +
 +    xen_vga_state->vram_ptr = vram;
 +#ifdef CONFIG_STUBDOM
-     xenfb_pv_display_start(vram);
++    xenfb_pv_display_vram(vram);
 +#endif
  }
  
 -void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base,
 -                     ram_addr_t vga_ram_offset, int vga_ram_size)
 +/* when used on xen environment, the vga_ram_base is not used */
- void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base,
++void vga_common_init(VGAState *s, uint8_t *vga_ram_base,
 +                     unsigned long vga_ram_offset, int vga_ram_size)
  {
      int i, j, v, b;
  
          expand4to8[i] = v;
      }
  
 -    s->vram_ptr = vga_ram_base;
 +    vga_reset(s);
 +
 +    xen_vga_state = s;
      s->vram_offset = vga_ram_offset;
      s->vram_size = vga_ram_size;
--    s->ds = ds;
-     ds->palette = s->last_palette;
      s->get_bpp = vga_get_bpp;
      s->get_offsets = vga_get_offsets;
      s->get_resolution = vga_get_resolution;
 -    s->update = vga_update_display;
 -    s->invalidate = vga_invalidate_display;
 -    s->screen_dump = vga_screen_dump;
 -    s->text_update = vga_update_text;
 +
++    s->ds = graphic_console_init(vga_update_display, vga_invalidate_display,
++                                 vga_screen_dump, vga_update_text, s);
++
 +    if (!restore) {
 +        xen_vga_populate_vram(VRAM_RESERVED_ADDRESS, s->vram_size);
 +        s->vram_gmfn = VRAM_RESERVED_ADDRESS;
 +    }
 +
-     graphic_console_init(s->ds, vga_update_display, vga_invalidate_display,
-                          vga_screen_dump, vga_update_text, s);
 +    vga_bios_init(s);
      switch (vga_retrace_method) {
      case VGA_RETRACE_DUMB:
          s->retrace = vga_dumb_retrace;
@@@ -2601,9 -2329,85 +2612,9 @@@ static void vga_init(VGAState *s
      vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s);
      cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
                                   vga_io_memory);
 -    qemu_register_coalesced_mmio(isa_mem_base + 0x000a0000, 0x20000);
 -}
 -
 -/* Memory mapped interface */
 -static uint32_t vga_mm_readb (void *opaque, target_phys_addr_t addr)
 -{
 -    VGAState *s = opaque;
 -
 -    return vga_ioport_read(s, addr >> s->it_shift) & 0xff;
 -}
 -
 -static void vga_mm_writeb (void *opaque,
 -                           target_phys_addr_t addr, uint32_t value)
 -{
 -    VGAState *s = opaque;
 -
 -    vga_ioport_write(s, addr >> s->it_shift, value & 0xff);
 -}
 -
 -static uint32_t vga_mm_readw (void *opaque, target_phys_addr_t addr)
 -{
 -    VGAState *s = opaque;
 -
 -    return vga_ioport_read(s, addr >> s->it_shift) & 0xffff;
 -}
 -
 -static void vga_mm_writew (void *opaque,
 -                           target_phys_addr_t addr, uint32_t value)
 -{
 -    VGAState *s = opaque;
 -
 -    vga_ioport_write(s, addr >> s->it_shift, value & 0xffff);
 -}
 -
 -static uint32_t vga_mm_readl (void *opaque, target_phys_addr_t addr)
 -{
 -    VGAState *s = opaque;
 -
 -    return vga_ioport_read(s, addr >> s->it_shift);
 -}
 -
 -static void vga_mm_writel (void *opaque,
 -                           target_phys_addr_t addr, uint32_t value)
 -{
 -    VGAState *s = opaque;
 -
 -    vga_ioport_write(s, addr >> s->it_shift, value);
 -}
 -
 -static CPUReadMemoryFunc *vga_mm_read_ctrl[] = {
 -    &vga_mm_readb,
 -    &vga_mm_readw,
 -    &vga_mm_readl,
 -};
 -
 -static CPUWriteMemoryFunc *vga_mm_write_ctrl[] = {
 -    &vga_mm_writeb,
 -    &vga_mm_writew,
 -    &vga_mm_writel,
 -};
 -
 -static void vga_mm_init(VGAState *s, target_phys_addr_t vram_base,
 -                        target_phys_addr_t ctrl_base, int it_shift)
 -{
 -    int s_ioport_ctrl, vga_io_memory;
 -
 -    s->it_shift = it_shift;
 -    s_ioport_ctrl = cpu_register_io_memory(0, vga_mm_read_ctrl, vga_mm_write_ctrl, s);
 -    vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s);
 -
 -    register_savevm("vga", 0, 2, vga_save, vga_load, s);
 -
 -    cpu_register_physical_memory(ctrl_base, 0x100000, s_ioport_ctrl);
 -    s->bank_offset = 0;
 -    cpu_register_physical_memory(vram_base + 0x000a0000, 0x20000, vga_io_memory);
 -    qemu_register_coalesced_mmio(vram_base + 0x000a0000, 0x20000);
  }
  
--int isa_vga_init(DisplayState *ds, uint8_t *vga_ram_base,
++int isa_vga_init(uint8_t *vga_ram_base,
                   unsigned long vga_ram_offset, int vga_ram_size)
  {
      VGAState *s;
      s = qemu_mallocz(sizeof(VGAState));
      if (!s)
          return -1;
 +    
 +    if (vga_ram_size > 16*1024*1024) {
 +        fprintf (stderr, "The stdvga/VBE device model has no use for more than 16 Megs of vram. Video ram set to 16M. \n");
 +        vga_ram_size = 16*1024*1024;
 +    }
  
--    vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size);
++    vga_common_init(s, vga_ram_base, vga_ram_offset, vga_ram_size);
      vga_init(s);
  
 -    s->console = graphic_console_init(s->ds, s->update, s->invalidate,
 -                                      s->screen_dump, s->text_update, s);
 -
 -#ifdef CONFIG_BOCHS_VBE
 -    /* XXX: use optimized standard vga accesses */
 -    cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
 -                                 vga_ram_size, vga_ram_offset);
 -#endif
 -    return 0;
 -}
 -
 -int isa_vga_mm_init(DisplayState *ds, uint8_t *vga_ram_base,
 -                    unsigned long vga_ram_offset, int vga_ram_size,
 -                    target_phys_addr_t vram_base, target_phys_addr_t ctrl_base,
 -                    int it_shift)
 -{
 -    VGAState *s;
 -
 -    s = qemu_mallocz(sizeof(VGAState));
 -    if (!s)
 -        return -1;
 -
 -    vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size);
 -    vga_mm_init(s, vram_base, ctrl_base, it_shift);
 -
 -    s->console = graphic_console_init(s->ds, s->update, s->invalidate,
 -                                      s->screen_dump, s->text_update, s);
 -
  #ifdef CONFIG_BOCHS_VBE
      /* XXX: use optimized standard vga accesses */
      cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
      return 0;
  }
  
--int pci_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base,
++int pci_vga_init(PCIBus *bus, uint8_t *vga_ram_base,
                   unsigned long vga_ram_offset, int vga_ram_size,
                   unsigned long vga_bios_offset, int vga_bios_size)
  {
          return -1;
      s = &d->vga_state;
  
 -    vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size);
 -    vga_init(s);
 -
 -    s->console = graphic_console_init(s->ds, s->update, s->invalidate,
 -                                      s->screen_dump, s->text_update, s);
 +    if (vga_ram_size > 16*1024*1024) {
 +        fprintf (stderr, "The stdvga/VBE device model has no use for more than 16 Megs of vram. Video ram set to 16M. \n");
 +        vga_ram_size = 16*1024*1024;
 +    }
  
-     vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size);
++    vga_common_init(s, vga_ram_base, vga_ram_offset, vga_ram_size);
 +    vga_init(s);
      s->pci_dev = &d->dev;
  
      pci_conf = d->dev.config;
  /********************************************************/
  /* vga screen dump */
  
--static int vga_save_w, vga_save_h;
--
  static void vga_save_dpy_update(DisplayState *s,
                                  int x, int y, int w, int h)
  {
  }
  
--static void vga_save_dpy_resize(DisplayState *s, int w, int h)
++static void vga_save_dpy_resize(DisplayState *s)
  {
--    s->linesize = w * 4;
--    s->data = qemu_mallocz(h * s->linesize);
--    vga_save_w = w;
--    vga_save_h = h;
  }
  
  static void vga_save_dpy_refresh(DisplayState *s)
  {
  }
  
- static int ppm_save(const char *filename, uint8_t *data,
-                     int w, int h, int linesize)
 -int ppm_save(const char *filename, uint8_t *data,
 -             int w, int h, int linesize)
++int ppm_save(const char *filename, struct DisplaySurface *ds)
  {
      FILE *f;
      uint8_t *d, *d1;
--    unsigned int v;
++    uint32_t v;
      int y, x;
++    uint8_t r, g, b;
  
      f = fopen(filename, "wb");
      if (!f)
          return -1;
      fprintf(f, "P6\n%d %d\n%d\n",
--            w, h, 255);
--    d1 = data;
--    for(y = 0; y < h; y++) {
++            ds->width, ds->height, 255);
++    d1 = ds->data;
++    for(y = 0; y < ds->height; y++) {
          d = d1;
--        for(x = 0; x < w; x++) {
--            v = *(uint32_t *)d;
--            fputc((v >> 16) & 0xff, f);
--            fputc((v >> 8) & 0xff, f);
--            fputc((v) & 0xff, f);
--            d += 4;
++        for(x = 0; x < ds->width; x++) {
++            if (ds->pf.bits_per_pixel == 32)
++                v = *(uint32_t *)d;
++            else
++                v = (uint32_t) (*(uint16_t *)d);
++            r = ((v >> ds->pf.rshift) & ds->pf.rmax) * 256 /
++                (ds->pf.rmax + 1);
++            g = ((v >> ds->pf.gshift) & ds->pf.gmax) * 256 /
++                (ds->pf.gmax + 1);
++            b = ((v >> ds->pf.bshift) & ds->pf.bmax) * 256 /
++                (ds->pf.bmax + 1);
++            fputc(r, f);
++            fputc(g, f);
++            fputc(b, f);
++            d += ds->pf.bytes_per_pixel;
          }
--        d1 += linesize;
++        d1 += ds->linesize;
      }
      fclose(f);
      return 0;
  }
  
 -static void vga_screen_dump_blank(VGAState *s, const char *filename)
 -{
 -    FILE *f;
 -    unsigned int y, x, w, h;
 -
 -    w = s->last_scr_width * sizeof(uint32_t);
 -    h = s->last_scr_height;
 -
 -    f = fopen(filename, "wb");
 -    if (!f)
 -        return;
 -    fprintf(f, "P6\n%d %d\n%d\n", w, h, 255);
 -    for (y = 0; y < h; y++) {
 -        for (x = 0; x < w; x++) {
 -            fputc(0, f);
 -        }
 -    }
 -    fclose(f);
 -}
 -
 -static void vga_screen_dump_common(VGAState *s, const char *filename,
 -                                   int w, int h)
 +/* save the vga display in a PPM image even if no display is
 +   available */
 +static void vga_screen_dump(void *opaque, const char *filename)
  {
 +    VGAState *s = (VGAState *)opaque;
      DisplayState *saved_ds, ds1, *ds = &ds1;
++    DisplayChangeListener dcl;
++    int w, h;
++
++    s->get_resolution(s, &w, &h);
  
      /* XXX: this is a little hackish */
      vga_invalidate_display(s);
      saved_ds = s->ds;
  
      memset(ds, 0, sizeof(DisplayState));
--    ds->dpy_update = vga_save_dpy_update;
--    ds->dpy_resize = vga_save_dpy_resize;
--    ds->dpy_refresh = vga_save_dpy_refresh;
--    ds->depth = 32;
--
 -    ds->linesize = w * sizeof(uint32_t);
 -    ds->data = qemu_mallocz(h * ds->linesize);
++    memset(&dcl, 0, sizeof(DisplayChangeListener));
++    dcl.dpy_update = vga_save_dpy_update;
++    dcl.dpy_resize = vga_save_dpy_resize;
++    dcl.dpy_refresh = vga_save_dpy_refresh;
++    register_displaychangelistener(ds, &dcl);
++    ds->surface = qemu_create_displaysurface(ds, w, h, 32, 4 * w);
++ 
      s->ds = ds;
      s->graphic_mode = -1;
      vga_update_display(s);
 -    ppm_save(filename, ds->data, w, h, ds->linesize);
 -    qemu_free(ds->data);
 -    s->ds = saved_ds;
 -}
 -
 -static void vga_screen_dump_graphic(VGAState *s, const char *filename)
 -{
 -    int w, h;
 -
 -    s->get_resolution(s, &w, &h);
 -    vga_screen_dump_common(s, filename, w, h);
 -}
 -
 -static void vga_screen_dump_text(VGAState *s, const char *filename)
 -{
 -    int w, h, cwidth, cheight;
  
-     if (ds->data) {
-         ppm_save(filename, ds->data, vga_save_w, vga_save_h,
-                  s->ds->linesize);
-         qemu_free(ds->data);
-     }
 -    vga_get_text_resolution(s, &w, &h, &cwidth, &cheight);
 -    vga_screen_dump_common(s, filename, w * cwidth, h * cheight);
 -}
 -
 -/* save the vga display in a PPM image even if no display is
 -   available */
 -static void vga_screen_dump(void *opaque, const char *filename)
 -{
 -    VGAState *s = (VGAState *)opaque;
++    ppm_save(filename, ds->surface);
 -    if (!(s->ar_index & 0x20))
 -        vga_screen_dump_blank(s, filename);
 -    else if (s->gr[6] & 1)
 -        vga_screen_dump_graphic(s, filename);
 -    else
 -        vga_screen_dump_text(s, filename);
++    qemu_free_displaysurface(ds);
 +    s->ds = saved_ds;
  }
diff --cc hw/vga_int.h
index d914b62ee842eb9aeb22e021694b0d6b75b8e957,39b7367dffafce5d8a3ac82b85c4e2c17d8f06a0..c9be893d809a5996da319cbf4cde8d5d34f6ddab
@@@ -144,7 -145,7 +144,6 @@@ typedef void (* vga_update_retrace_info
      VGA_STATE_COMMON_BOCHS_VBE                                          \
      /* display refresh support */                                       \
      DisplayState *ds;                                                   \
--    QEMUConsole *console;                                               \
      uint32_t font_offsets[2];                                           \
      int graphic_mode;                                                   \
      uint8_t shift_control;                                              \
@@@ -187,11 -190,19 +186,12 @@@ static inline int c6_to_8(int v
      return (v << 2) | (b << 1) | b;
  }
  
--void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base,
 -                     ram_addr_t vga_ram_offset, int vga_ram_size);
 -void vga_init(VGAState *s);
 -void vga_reset(void *s);
 -
 -void vga_dirty_log_start(VGAState *s);
 -void vga_dirty_log_stop(VGAState *s);
 -
++void vga_common_init(VGAState *s, uint8_t *vga_ram_base,
 +                     unsigned long vga_ram_offset, int vga_ram_size);
  uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr);
  void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val);
  void vga_invalidate_scanlines(VGAState *s, int y1, int y2);
 -int ppm_save(const char *filename, uint8_t *data,
 -             int w, int h, int linesize);
++int ppm_save(const char *filename, struct DisplaySurface *ds);
  
  void vga_draw_cursor_line_8(uint8_t *d1, const uint8_t *src1,
                              int poffset, int w,
diff --cc hw/vmware_vga.c
Simple merge
diff --cc loader.c
index 173cea118bc81dc008e317286e16aaa54886e6ec,8ecb61d514dc90bd45d4d97cc7625e9765ddaed7..de5c6230e1ba2b42422fc9758815842f11d57acb
+++ b/loader.c
@@@ -390,7 -541,5 +543,7 @@@ out
      if (data)
          qemu_free(data);
      close(fd);
-     return -1;
+     return ret;
  }
 +
 +#endif /*CONFIG_DM*/
diff --cc monitor.c
Simple merge
diff --cc nbd.c
index a9b9401fb0c6e6e278865994533e115716e6043a,77b3e169268fc94ad8d42fbc90ef458f9e213ea5..9d2fcd3a3aac24cb968bfb0d080550cf98f25dd4
--- 1/nbd.c
--- 2/nbd.c
+++ b/nbd.c
@@@ -189,7 -187,7 +189,7 @@@ error
      return -1;
  }
  
--#ifndef _WIN32
++#ifndef NO_UNIX_SOCKETS
  int unix_socket_incoming(const char *path)
  {
      int s;
diff --cc net.c
index 0000000000000000000000000000000000000000,86ee7d540de44e9185c3246c1afe5b946c286287..99430155ed83f817fe2e75ee7a88e498956d4f3e
mode 000000,100644..100644
--- /dev/null
--- 2/net.c
+++ b/net.c
@@@ -1,0 -1,1806 +1,1846 @@@
 -static int get_str_sep(char *buf, int buf_size, const char **pp, int sep)
+ /*
+  * QEMU System Emulator
+  *
+  * Copyright (c) 2003-2008 Fabrice Bellard
+  *
+  * Permission is hereby granted, free of charge, to any person obtaining a copy
+  * of this software and associated documentation files (the "Software"), to deal
+  * in the Software without restriction, including without limitation the rights
+  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  * copies of the Software, and to permit persons to whom the Software is
+  * furnished to do so, subject to the following conditions:
+  *
+  * The above copyright notice and this permission notice shall be included in
+  * all copies or substantial portions of the Software.
+  *
+  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+  * THE SOFTWARE.
+  */
+ #include "qemu-common.h"
+ #include "net.h"
+ #include "console.h"
+ #include "sysemu.h"
+ #include "qemu-timer.h"
+ #include "qemu-char.h"
+ #include "audio/audio.h"
+ #include <unistd.h>
+ #include <fcntl.h>
+ #include <signal.h>
+ #include <time.h>
+ #include <errno.h>
+ #include <sys/time.h>
+ #include <zlib.h>
+ #ifndef _WIN32
+ #include <sys/times.h>
+ #include <sys/wait.h>
+ #include <termios.h>
+ #include <sys/mman.h>
+ #include <sys/ioctl.h>
+ #include <sys/resource.h>
+ #include <sys/socket.h>
+ #include <netinet/in.h>
+ #include <net/if.h>
+ #ifdef __NetBSD__
+ #include <net/if_tap.h>
+ #endif
+ #ifdef __linux__
+ #include <linux/if_tun.h>
+ #endif
+ #include <arpa/inet.h>
+ #include <dirent.h>
+ #include <netdb.h>
+ #include <sys/select.h>
+ #ifdef _BSD
+ #include <sys/stat.h>
+ #ifdef __FreeBSD__
+ #include <libutil.h>
+ #else
+ #include <util.h>
+ #endif
+ #elif defined (__GLIBC__) && defined (__FreeBSD_kernel__)
+ #include <freebsd/stdlib.h>
+ #else
+ #ifdef __linux__
+ #include <pty.h>
+ #include <malloc.h>
+ #include <linux/rtc.h>
+ /* For the benefit of older linux systems which don't supply it,
+    we use a local copy of hpet.h. */
+ /* #include <linux/hpet.h> */
+ #include "hpet.h"
+ #include <linux/ppdev.h>
+ #include <linux/parport.h>
+ #endif
+ #ifdef __sun__
+ #include <sys/stat.h>
+ #include <sys/ethernet.h>
+ #include <sys/sockio.h>
+ #include <netinet/arp.h>
+ #include <netinet/in.h>
+ #include <netinet/in_systm.h>
+ #include <netinet/ip.h>
+ #include <netinet/ip_icmp.h> // must come after ip.h
+ #include <netinet/udp.h>
+ #include <netinet/tcp.h>
+ #include <net/if.h>
+ #include <syslog.h>
+ #include <stropts.h>
+ #endif
+ #endif
+ #endif
+ #include "qemu_socket.h"
+ #if defined(CONFIG_SLIRP)
+ #include "libslirp.h"
+ #endif
+ #if defined(__OpenBSD__)
+ #include <util.h>
+ #endif
+ #if defined(CONFIG_VDE)
+ #include <libvdeplug.h>
+ #endif
+ #ifdef _WIN32
+ #include <malloc.h>
+ #include <sys/timeb.h>
+ #include <mmsystem.h>
+ #define getopt_long_only getopt_long
+ #define memalign(align, size) malloc(size)
+ #endif
+ static VLANState *first_vlan;
++static TAPState *head_net_tap;
++
++void net_tap_shutdown_all(void)
++{
++    struct IOHandlerRecord **pioh, *ioh;
++
++    while (head_net_tap) {
++        qemu_set_fd_handler2(head_net_tap->fd, 0,0,0,0);
++        close(head_net_tap->fd);
++        head_net_tap = head_net_tap->next;
++    }
++}
++
+ /***********************************************************/
+ /* network device redirectors */
+ #if defined(DEBUG_NET) || defined(DEBUG_SLIRP)
+ static void hex_dump(FILE *f, const uint8_t *buf, int size)
+ {
+     int len, i, j, c;
+     for(i=0;i<size;i+=16) {
+         len = size - i;
+         if (len > 16)
+             len = 16;
+         fprintf(f, "%08x ", i);
+         for(j=0;j<16;j++) {
+             if (j < len)
+                 fprintf(f, " %02x", buf[i+j]);
+             else
+                 fprintf(f, "   ");
+         }
+         fprintf(f, " ");
+         for(j=0;j<len;j++) {
+             c = buf[i+j];
+             if (c < ' ' || c > '~')
+                 c = '.';
+             fprintf(f, "%c", c);
+         }
+         fprintf(f, "\n");
+     }
+ }
+ #endif
+ static int parse_macaddr(uint8_t *macaddr, const char *p)
+ {
+     int i;
+     char *last_char;
+     long int offset;
+     errno = 0;
+     offset = strtol(p, &last_char, 0);    
+     if (0 == errno && '\0' == *last_char &&
+             offset >= 0 && offset <= 0xFFFFFF) {
+         macaddr[3] = (offset & 0xFF0000) >> 16;
+         macaddr[4] = (offset & 0xFF00) >> 8;
+         macaddr[5] = offset & 0xFF;
+         return 0;
+     } else {
+         for(i = 0; i < 6; i++) {
+             macaddr[i] = strtol(p, (char **)&p, 16);
+             if (i == 5) {
+                 if (*p != '\0')
+                     return -1;
+             } else {
+                 if (*p != ':' && *p != '-')
+                     return -1;
+                 p++;
+             }
+         }
+         return 0;    
+     }
+     return -1;
+ }
 -#else
++static int get_str_sep(char *buf, size_t buf_size, const char **pp, int sep)
+ {
+     const char *p, *p1;
+     int len;
+     p = *pp;
+     p1 = strchr(p, sep);
+     if (!p1)
+         return -1;
+     len = p1 - p;
+     p1++;
+     if (buf_size > 0) {
+         if (len > buf_size - 1)
+             len = buf_size - 1;
+         memcpy(buf, p, len);
+         buf[len] = '\0';
+     }
+     *pp = p1;
+     return 0;
+ }
+ int parse_host_src_port(struct sockaddr_in *haddr,
+                         struct sockaddr_in *saddr,
+                         const char *input_str)
+ {
+     char *str = strdup(input_str);
+     char *host_str = str;
+     char *src_str;
+     const char *src_str2;
+     char *ptr;
+     /*
+      * Chop off any extra arguments at the end of the string which
+      * would start with a comma, then fill in the src port information
+      * if it was provided else use the "any address" and "any port".
+      */
+     if ((ptr = strchr(str,',')))
+         *ptr = '\0';
+     if ((src_str = strchr(input_str,'@'))) {
+         *src_str = '\0';
+         src_str++;
+     }
+     if (parse_host_port(haddr, host_str) < 0)
+         goto fail;
+     src_str2 = src_str;
+     if (!src_str || *src_str == '\0')
+         src_str2 = ":0";
+     if (parse_host_port(saddr, src_str2) < 0)
+         goto fail;
+     free(str);
+     return(0);
+ fail:
+     free(str);
+     return -1;
+ }
+ int parse_host_port(struct sockaddr_in *saddr, const char *str)
+ {
+     char buf[512];
+     struct hostent *he;
+     const char *p, *r;
+     int port;
+     p = str;
+     if (get_str_sep(buf, sizeof(buf), &p, ':') < 0)
+         return -1;
+     saddr->sin_family = AF_INET;
+     if (buf[0] == '\0') {
+         saddr->sin_addr.s_addr = 0;
+     } else {
+         if (qemu_isdigit(buf[0])) {
+             if (!inet_aton(buf, &saddr->sin_addr))
+                 return -1;
+         } else {
+             if ((he = gethostbyname(buf)) == NULL)
+                 return - 1;
+             saddr->sin_addr = *(struct in_addr *)he->h_addr;
+         }
+     }
+     port = strtol(p, (char **)&r, 0);
+     if (r == p)
+         return -1;
+     saddr->sin_port = htons(port);
+     return 0;
+ }
+ #if !defined(_WIN32) && 0
+ static int parse_unix_path(struct sockaddr_un *uaddr, const char *str)
+ {
+     const char *p;
+     int len;
+     len = MIN(108, strlen(str));
+     p = strchr(str, ',');
+     if (p)
+       len = MIN(len, p - str);
+     memset(uaddr, 0, sizeof(*uaddr));
+     uaddr->sun_family = AF_UNIX;
+     memcpy(uaddr->sun_path, str, len);
+     return 0;
+ }
+ #endif
+ void qemu_format_nic_info_str(VLANClientState *vc, uint8_t macaddr[6])
+ {
+     snprintf(vc->info_str, sizeof(vc->info_str),
+              "model=%s,macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
+              vc->model,
+              macaddr[0], macaddr[1], macaddr[2],
+              macaddr[3], macaddr[4], macaddr[5]);
+ }
+ static char *assign_name(VLANClientState *vc1, const char *model)
+ {
+     VLANState *vlan;
+     char buf[256];
+     int id = 0;
+     for (vlan = first_vlan; vlan; vlan = vlan->next) {
+         VLANClientState *vc;
+         for (vc = vlan->first_client; vc; vc = vc->next)
+             if (vc != vc1 && strcmp(vc->model, model) == 0)
+                 id++;
+     }
+     snprintf(buf, sizeof(buf), "%s.%d", model, id);
+     return strdup(buf);
+ }
+ VLANClientState *qemu_new_vlan_client(VLANState *vlan,
+                                       const char *model,
+                                       const char *name,
+                                       IOReadHandler *fd_read,
+                                       IOCanRWHandler *fd_can_read,
+                                       void *opaque)
+ {
+     VLANClientState *vc, **pvc;
+     vc = qemu_mallocz(sizeof(VLANClientState));
+     if (!vc)
+         return NULL;
+     vc->model = strdup(model);
+     if (name)
+         vc->name = strdup(name);
+     else
+         vc->name = assign_name(vc, model);
+     vc->fd_read = fd_read;
+     vc->fd_can_read = fd_can_read;
+     vc->opaque = opaque;
+     vc->vlan = vlan;
+     vc->next = NULL;
+     pvc = &vlan->first_client;
+     while (*pvc != NULL)
+         pvc = &(*pvc)->next;
+     *pvc = vc;
+     return vc;
+ }
+ void qemu_del_vlan_client(VLANClientState *vc)
+ {
+     VLANClientState **pvc = &vc->vlan->first_client;
+     while (*pvc != NULL)
+         if (*pvc == vc) {
+             *pvc = vc->next;
+             free(vc->name);
+             free(vc->model);
+             free(vc);
+             break;
+         } else
+             pvc = &(*pvc)->next;
+ }
+ int qemu_can_send_packet(VLANClientState *vc1)
+ {
+     VLANState *vlan = vc1->vlan;
+     VLANClientState *vc;
+     for(vc = vlan->first_client; vc != NULL; vc = vc->next) {
+         if (vc != vc1) {
+             if (vc->fd_can_read && vc->fd_can_read(vc->opaque))
+                 return 1;
+         }
+     }
+     return 0;
+ }
+ void qemu_send_packet(VLANClientState *vc1, const uint8_t *buf, int size)
+ {
+     VLANState *vlan = vc1->vlan;
+     VLANClientState *vc;
+     if (vc1->link_down)
+         return;
+ #ifdef DEBUG_NET
+     printf("vlan %d send:\n", vlan->id);
+     hex_dump(stdout, buf, size);
+ #endif
+     for(vc = vlan->first_client; vc != NULL; vc = vc->next) {
+         if (vc != vc1 && !vc->link_down) {
+             vc->fd_read(vc->opaque, buf, size);
+         }
+     }
+ }
+ static ssize_t vc_sendv_compat(VLANClientState *vc, const struct iovec *iov,
+                                int iovcnt)
+ {
+     uint8_t buffer[4096];
+     size_t offset = 0;
+     int i;
+     for (i = 0; i < iovcnt; i++) {
+         size_t len;
+         len = MIN(sizeof(buffer) - offset, iov[i].iov_len);
+         memcpy(buffer + offset, iov[i].iov_base, len);
+         offset += len;
+     }
+     vc->fd_read(vc->opaque, buffer, offset);
+     return offset;
+ }
+ ssize_t qemu_sendv_packet(VLANClientState *vc1, const struct iovec *iov,
+                           int iovcnt)
+ {
+     VLANState *vlan = vc1->vlan;
+     VLANClientState *vc;
+     ssize_t max_len = 0;
+     for (vc = vlan->first_client; vc != NULL; vc = vc->next) {
+         ssize_t len = 0;
+         if (vc == vc1)
+             continue;
+         if (vc->fd_readv)
+             len = vc->fd_readv(vc->opaque, iov, iovcnt);
+         else if (vc->fd_read)
+             len = vc_sendv_compat(vc, iov, iovcnt);
+         max_len = MAX(max_len, len);
+     }
+     return max_len;
+ }
+ #if defined(CONFIG_SLIRP)
+ /* slirp network adapter */
+ static int slirp_inited;
+ static int slirp_restrict;
+ static char *slirp_ip;
+ static VLANClientState *slirp_vc;
+ int slirp_can_output(void)
+ {
+     return !slirp_vc || qemu_can_send_packet(slirp_vc);
+ }
+ void slirp_output(const uint8_t *pkt, int pkt_len)
+ {
+ #ifdef DEBUG_SLIRP
+     printf("slirp output:\n");
+     hex_dump(stdout, pkt, pkt_len);
+ #endif
+     if (!slirp_vc)
+         return;
+     qemu_send_packet(slirp_vc, pkt, pkt_len);
+ }
+ int slirp_is_inited(void)
+ {
+     return slirp_inited;
+ }
+ static void slirp_receive(void *opaque, const uint8_t *buf, int size)
+ {
+ #ifdef DEBUG_SLIRP
+     printf("slirp input:\n");
+     hex_dump(stdout, buf, size);
+ #endif
+     slirp_input(buf, size);
+ }
+ static int net_slirp_init(VLANState *vlan, const char *model, const char *name)
+ {
+     if (!slirp_inited) {
+         slirp_inited = 1;
+         slirp_init(slirp_restrict, slirp_ip);
+     }
+     slirp_vc = qemu_new_vlan_client(vlan, model, name,
+                                     slirp_receive, NULL, NULL);
+     slirp_vc->info_str[0] = '\0';
+     return 0;
+ }
+ void net_slirp_redir(const char *redir_str)
+ {
+     int is_udp;
+     char buf[256], *r;
+     const char *p;
+     struct in_addr guest_addr;
+     int host_port, guest_port;
+     if (!slirp_inited) {
+         slirp_inited = 1;
+         slirp_init(slirp_restrict, slirp_ip);
+     }
+     p = redir_str;
+     if (get_str_sep(buf, sizeof(buf), &p, ':') < 0)
+         goto fail;
+     if (!strcmp(buf, "tcp")) {
+         is_udp = 0;
+     } else if (!strcmp(buf, "udp")) {
+         is_udp = 1;
+     } else {
+         goto fail;
+     }
+     if (get_str_sep(buf, sizeof(buf), &p, ':') < 0)
+         goto fail;
+     host_port = strtol(buf, &r, 0);
+     if (r == buf)
+         goto fail;
+     if (get_str_sep(buf, sizeof(buf), &p, ':') < 0)
+         goto fail;
+     if (buf[0] == '\0') {
+         pstrcpy(buf, sizeof(buf), "10.0.2.15");
+     }
+     if (!inet_aton(buf, &guest_addr))
+         goto fail;
+     guest_port = strtol(p, &r, 0);
+     if (r == p)
+         goto fail;
+     if (slirp_redir(is_udp, host_port, guest_addr, guest_port) < 0) {
+         fprintf(stderr, "qemu: could not set up redirection\n");
+         exit(1);
+     }
+     return;
+  fail:
+     fprintf(stderr, "qemu: syntax: -redir [tcp|udp]:host-port:[guest-host]:guest-port\n");
+     exit(1);
+ }
+ #ifndef _WIN32
+ static char smb_dir[1024];
+ static void erase_dir(char *dir_name)
+ {
+     DIR *d;
+     struct dirent *de;
+     char filename[1024];
+     /* erase all the files in the directory */
+     if ((d = opendir(dir_name)) != 0) {
+         for(;;) {
+             de = readdir(d);
+             if (!de)
+                 break;
+             if (strcmp(de->d_name, ".") != 0 &&
+                 strcmp(de->d_name, "..") != 0) {
+                 snprintf(filename, sizeof(filename), "%s/%s",
+                          smb_dir, de->d_name);
+                 if (unlink(filename) != 0)  /* is it a directory? */
+                     erase_dir(filename);
+             }
+         }
+         closedir(d);
+         rmdir(dir_name);
+     }
+ }
+ /* automatic user mode samba server configuration */
+ static void smb_exit(void)
+ {
+     erase_dir(smb_dir);
+ }
+ /* automatic user mode samba server configuration */
+ void net_slirp_smb(const char *exported_dir)
+ {
+     char smb_conf[1024];
+     char smb_cmdline[1024];
+     FILE *f;
+     if (!slirp_inited) {
+         slirp_inited = 1;
+         slirp_init(slirp_restrict, slirp_ip);
+     }
+     /* XXX: better tmp dir construction */
+     snprintf(smb_dir, sizeof(smb_dir), "/tmp/qemu-smb.%d", getpid());
+     if (mkdir(smb_dir, 0700) < 0) {
+         fprintf(stderr, "qemu: could not create samba server dir '%s'\n", smb_dir);
+         exit(1);
+     }
+     snprintf(smb_conf, sizeof(smb_conf), "%s/%s", smb_dir, "smb.conf");
+     f = fopen(smb_conf, "w");
+     if (!f) {
+         fprintf(stderr, "qemu: could not create samba server configuration file '%s'\n", smb_conf);
+         exit(1);
+     }
+     fprintf(f,
+             "[global]\n"
+             "private dir=%s\n"
+             "smb ports=0\n"
+             "socket address=127.0.0.1\n"
+             "pid directory=%s\n"
+             "lock directory=%s\n"
+             "log file=%s/log.smbd\n"
+             "smb passwd file=%s/smbpasswd\n"
+             "security = share\n"
+             "[qemu]\n"
+             "path=%s\n"
+             "read only=no\n"
+             "guest ok=yes\n",
+             smb_dir,
+             smb_dir,
+             smb_dir,
+             smb_dir,
+             smb_dir,
+             exported_dir
+             );
+     fclose(f);
+     atexit(smb_exit);
+     snprintf(smb_cmdline, sizeof(smb_cmdline), "%s -s %s",
+              SMBD_COMMAND, smb_conf);
+     slirp_add_exec(0, smb_cmdline, 4, 139);
+ }
+ #endif /* !defined(_WIN32) */
+ void do_info_slirp(void)
+ {
+     slirp_stats();
+ }
+ #endif /* CONFIG_SLIRP */
+ #if !defined(_WIN32)
+ typedef struct TAPState {
+     VLANClientState *vc;
+     int fd;
++    struct TAPState *next;
+     char down_script[1024];
+     char down_script_arg[128];
++    char script_arg[1024];
+ } TAPState;
+ #ifdef HAVE_IOVEC
+ static ssize_t tap_receive_iov(void *opaque, const struct iovec *iov,
+                                int iovcnt)
+ {
+     TAPState *s = opaque;
+     ssize_t len;
+     do {
+         len = writev(s->fd, iov, iovcnt);
+     } while (len == -1 && (errno == EINTR || errno == EAGAIN));
+     return len;
+ }
+ #endif
+ static void tap_receive(void *opaque, const uint8_t *buf, int size)
+ {
+     TAPState *s = opaque;
+     int ret;
+     for(;;) {
+         ret = write(s->fd, buf, size);
+         if (ret < 0 && (errno == EINTR || errno == EAGAIN)) {
+         } else {
+             break;
+         }
+     }
+ }
+ static void tap_send(void *opaque)
+ {
+     TAPState *s = opaque;
+     uint8_t buf[4096];
+     int size;
+ #ifdef __sun__
+     struct strbuf sbuf;
+     int f = 0;
+     sbuf.maxlen = sizeof(buf);
+     sbuf.buf = buf;
+     size = getmsg(s->fd, NULL, &sbuf, &f) >=0 ? sbuf.len : -1;
+ #else
+     size = read(s->fd, buf, sizeof(buf));
+ #endif
+     if (size > 0) {
+         qemu_send_packet(s->vc, buf, size);
+     }
+ }
+ /* fd support */
+ static TAPState *net_tap_fd_init(VLANState *vlan,
+                                  const char *model,
+                                  const char *name,
+                                  int fd)
+ {
+     TAPState *s;
+     s = qemu_mallocz(sizeof(TAPState));
+     if (!s)
+         return NULL;
+     s->fd = fd;
+     s->vc = qemu_new_vlan_client(vlan, model, name, tap_receive, NULL, s);
++    s->next = head_net_tap;
++    head_net_tap = s;
+ #ifdef HAVE_IOVEC
+     s->vc->fd_readv = tap_receive_iov;
+ #endif
+     qemu_set_fd_handler(s->fd, tap_send, NULL, s);
+     snprintf(s->vc->info_str, sizeof(s->vc->info_str), "fd=%d", fd);
+     return s;
+ }
+ #if defined (_BSD) || defined (__FreeBSD_kernel__)
+ static int tap_open(char *ifname, int ifname_size)
+ {
+     int fd;
++#ifndef TAPGIFNAME
+     char *dev;
+     struct stat s;
++#endif
+     TFR(fd = open("/dev/tap", O_RDWR));
+     if (fd < 0) {
+         fprintf(stderr, "warning: could not open /dev/tap: no virtual network emulation\n");
+         return -1;
+     }
++#ifdef TAPGIFNAME
++    if (ioctl (fd, TAPGIFNAME, (void*)&ifr) < 0) {
++       fprintf(stderr, "warning: could not open get tap name: %s\n",
++           strerror(errno));
++       return -1;
++    }
++    pstrcpy(ifname, ifname_size, ifr.ifr_name);
++#else
+     fstat(fd, &s);
+     dev = devname(s.st_rdev, S_IFCHR);
+     pstrcpy(ifname, ifname_size, dev);
++#endif
+     fcntl(fd, F_SETFL, O_NONBLOCK);
+     return fd;
+ }
+ #elif defined(__sun__)
+ #define TUNNEWPPA       (('T'<<16) | 0x0001)
+ /*
+  * Allocate TAP device, returns opened fd.
+  * Stores dev name in the first arg(must be large enough).
+  */
+ int tap_alloc(char *dev, size_t dev_size)
+ {
+     int tap_fd, if_fd, ppa = -1;
+     static int ip_fd = 0;
+     char *ptr;
+     static int arp_fd = 0;
+     int ip_muxid, arp_muxid;
+     struct strioctl  strioc_if, strioc_ppa;
+     int link_type = I_PLINK;;
+     struct lifreq ifr;
+     char actual_name[32] = "";
+     memset(&ifr, 0x0, sizeof(ifr));
+     if( *dev ){
+        ptr = dev;
+        while( *ptr && !qemu_isdigit((int)*ptr) ) ptr++;
+        ppa = atoi(ptr);
+     }
+     /* Check if IP device was opened */
+     if( ip_fd )
+        close(ip_fd);
+     TFR(ip_fd = open("/dev/udp", O_RDWR, 0));
+     if (ip_fd < 0) {
+        syslog(LOG_ERR, "Can't open /dev/ip (actually /dev/udp)");
+        return -1;
+     }
+     TFR(tap_fd = open("/dev/tap", O_RDWR, 0));
+     if (tap_fd < 0) {
+        syslog(LOG_ERR, "Can't open /dev/tap");
+        return -1;
+     }
+     /* Assign a new PPA and get its unit number. */
+     strioc_ppa.ic_cmd = TUNNEWPPA;
+     strioc_ppa.ic_timout = 0;
+     strioc_ppa.ic_len = sizeof(ppa);
+     strioc_ppa.ic_dp = (char *)&ppa;
+     if ((ppa = ioctl (tap_fd, I_STR, &strioc_ppa)) < 0)
+        syslog (LOG_ERR, "Can't assign new interface");
+     TFR(if_fd = open("/dev/tap", O_RDWR, 0));
+     if (if_fd < 0) {
+        syslog(LOG_ERR, "Can't open /dev/tap (2)");
+        return -1;
+     }
+     if(ioctl(if_fd, I_PUSH, "ip") < 0){
+        syslog(LOG_ERR, "Can't push IP module");
+        return -1;
+     }
+     if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) < 0)
+       syslog(LOG_ERR, "Can't get flags\n");
+     snprintf (actual_name, 32, "tap%d", ppa);
+     pstrcpy(ifr.lifr_name, sizeof(ifr.lifr_name), actual_name);
+     ifr.lifr_ppa = ppa;
+     /* Assign ppa according to the unit number returned by tun device */
+     if (ioctl (if_fd, SIOCSLIFNAME, &ifr) < 0)
+         syslog (LOG_ERR, "Can't set PPA %d", ppa);
+     if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) <0)
+         syslog (LOG_ERR, "Can't get flags\n");
+     /* Push arp module to if_fd */
+     if (ioctl (if_fd, I_PUSH, "arp") < 0)
+         syslog (LOG_ERR, "Can't push ARP module (2)");
+     /* Push arp module to ip_fd */
+     if (ioctl (ip_fd, I_POP, NULL) < 0)
+         syslog (LOG_ERR, "I_POP failed\n");
+     if (ioctl (ip_fd, I_PUSH, "arp") < 0)
+         syslog (LOG_ERR, "Can't push ARP module (3)\n");
+     /* Open arp_fd */
+     TFR(arp_fd = open ("/dev/tap", O_RDWR, 0));
+     if (arp_fd < 0)
+        syslog (LOG_ERR, "Can't open %s\n", "/dev/tap");
+     /* Set ifname to arp */
+     strioc_if.ic_cmd = SIOCSLIFNAME;
+     strioc_if.ic_timout = 0;
+     strioc_if.ic_len = sizeof(ifr);
+     strioc_if.ic_dp = (char *)&ifr;
+     if (ioctl(arp_fd, I_STR, &strioc_if) < 0){
+         syslog (LOG_ERR, "Can't set ifname to arp\n");
+     }
+     if((ip_muxid = ioctl(ip_fd, I_LINK, if_fd)) < 0){
+        syslog(LOG_ERR, "Can't link TAP device to IP");
+        return -1;
+     }
+     if ((arp_muxid = ioctl (ip_fd, link_type, arp_fd)) < 0)
+         syslog (LOG_ERR, "Can't link TAP device to ARP");
+     close (if_fd);
+     memset(&ifr, 0x0, sizeof(ifr));
+     pstrcpy(ifr.lifr_name, sizeof(ifr.lifr_name), actual_name);
+     ifr.lifr_ip_muxid  = ip_muxid;
+     ifr.lifr_arp_muxid = arp_muxid;
+     if (ioctl (ip_fd, SIOCSLIFMUXID, &ifr) < 0)
+     {
+       ioctl (ip_fd, I_PUNLINK , arp_muxid);
+       ioctl (ip_fd, I_PUNLINK, ip_muxid);
+       syslog (LOG_ERR, "Can't set multiplexor id");
+     }
+     snprintf(dev, dev_size, "tap%d", ppa);
+     return tap_fd;
+ }
+ static int tap_open(char *ifname, int ifname_size)
+ {
+     char  dev[10]="";
+     int fd;
+     if( (fd = tap_alloc(dev, sizeof(dev))) < 0 ){
+        fprintf(stderr, "Cannot allocate TAP device\n");
+        return -1;
+     }
+     pstrcpy(ifname, ifname_size, dev);
+     fcntl(fd, F_SETFL, O_NONBLOCK);
+     return fd;
+ }
+ #elif defined (_AIX)
+ static int tap_open(char *ifname, int ifname_size)
+ {
+     fprintf (stderr, "no tap on AIX\n");
+     return -1;
+ }
 -static int launch_script(const char *setup_script, const char *ifname, int fd)
++#elif defined(__linux__)
+ static int tap_open(char *ifname, int ifname_size)
+ {
+     struct ifreq ifr;
+     int fd, ret;
+     TFR(fd = open("/dev/net/tun", O_RDWR));
+     if (fd < 0) {
+         fprintf(stderr, "warning: could not open /dev/net/tun: no virtual network emulation\n");
+         return -1;
+     }
+     memset(&ifr, 0, sizeof(ifr));
+     ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+     if (ifname[0] != '\0')
+         pstrcpy(ifr.ifr_name, IFNAMSIZ, ifname);
+     else
+         pstrcpy(ifr.ifr_name, IFNAMSIZ, "tap%d");
+     ret = ioctl(fd, TUNSETIFF, (void *) &ifr);
+     if (ret != 0) {
+         fprintf(stderr, "warning: could not configure /dev/net/tun: no virtual network emulation\n");
+         close(fd);
+         return -1;
+     }
+     pstrcpy(ifname, ifname_size, ifr.ifr_name);
+     fcntl(fd, F_SETFL, O_NONBLOCK);
+     return fd;
+ }
+ #endif
 -    char *args[3];
++static int launch_script(const char *setup_script, const char *ifname,
++                         const char *script_arg, int fd)
+ {
+     int pid, status;
 -                        const char *setup_script, const char *down_script)
++    char *args[4];
+     char **parg;
+         /* try to launch network script */
+         pid = fork();
+         if (pid >= 0) {
+             if (pid == 0) {
+                 int open_max = sysconf (_SC_OPEN_MAX), i;
+                 for (i = 0; i < open_max; i++)
+                     if (i != STDIN_FILENO &&
+                         i != STDOUT_FILENO &&
+                         i != STDERR_FILENO &&
+                         i != fd)
+                         close(i);
+                 parg = args;
+                 *parg++ = (char *)setup_script;
+                 *parg++ = (char *)ifname;
++                if (script_arg && script_arg[0])
++                    *parg++ = (char *)script_arg;
+                 *parg++ = NULL;
+                 execv(setup_script, args);
+                 _exit(1);
+             }
+             while (waitpid(pid, &status, 0) != pid);
+             if (!WIFEXITED(status) ||
+                 WEXITSTATUS(status) != 0) {
+                 fprintf(stderr, "%s: could not launch network script\n",
+                         setup_script);
+                 return -1;
+             }
+         }
+     return 0;
+ }
+ static int net_tap_init(VLANState *vlan, const char *model,
+                         const char *name, const char *ifname1,
 -      if (launch_script(setup_script, ifname, fd))
++                        const char *setup_script, const char *down_script,
++                        const char *script_arg)
+ {
+     TAPState *s;
+     int fd;
+     char ifname[128];
+     if (ifname1 != NULL)
+         pstrcpy(ifname, sizeof(ifname), ifname1);
+     else
+         ifname[0] = '\0';
+     TFR(fd = tap_open(ifname, sizeof(ifname)));
+     if (fd < 0)
+         return -1;
+     if (!setup_script || !strcmp(setup_script, "no"))
+         setup_script = "";
+     if (setup_script[0] != '\0') {
 -        char setup_script[1024], down_script[1024];
++      if (launch_script(setup_script, ifname, script_arg, fd))
+           return -1;
+     }
+     s = net_tap_fd_init(vlan, model, name, fd);
+     if (!s)
+         return -1;
+     snprintf(s->vc->info_str, sizeof(s->vc->info_str),
+              "ifname=%s,script=%s,downscript=%s",
+              ifname, setup_script, down_script);
+     if (down_script && strcmp(down_script, "no")) {
+         snprintf(s->down_script, sizeof(s->down_script), "%s", down_script);
+         snprintf(s->down_script_arg, sizeof(s->down_script_arg), "%s", ifname);
+     }
++    if (script_arg && script_arg[0])
++        snprintf(s->script_arg, sizeof(s->script_arg), "%s", script_arg);
++    else
++        s->script_arg[0] = '\0';
+     return 0;
+ }
+ #endif /* !_WIN32 */
+ #if defined(CONFIG_VDE)
+ typedef struct VDEState {
+     VLANClientState *vc;
+     VDECONN *vde;
+ } VDEState;
+ static void vde_to_qemu(void *opaque)
+ {
+     VDEState *s = opaque;
+     uint8_t buf[4096];
+     int size;
+     size = vde_recv(s->vde, buf, sizeof(buf), 0);
+     if (size > 0) {
+         qemu_send_packet(s->vc, buf, size);
+     }
+ }
+ static void vde_from_qemu(void *opaque, const uint8_t *buf, int size)
+ {
+     VDEState *s = opaque;
+     int ret;
+     for(;;) {
+         ret = vde_send(s->vde, buf, size, 0);
+         if (ret < 0 && errno == EINTR) {
+         } else {
+             break;
+         }
+     }
+ }
+ static int net_vde_init(VLANState *vlan, const char *model,
+                         const char *name, const char *sock,
+                         int port, const char *group, int mode)
+ {
+     VDEState *s;
+     char *init_group = strlen(group) ? (char *)group : NULL;
+     char *init_sock = strlen(sock) ? (char *)sock : NULL;
+     struct vde_open_args args = {
+         .port = port,
+         .group = init_group,
+         .mode = mode,
+     };
+     s = qemu_mallocz(sizeof(VDEState));
+     if (!s)
+         return -1;
+     s->vde = vde_open(init_sock, "QEMU", &args);
+     if (!s->vde){
+         free(s);
+         return -1;
+     }
+     s->vc = qemu_new_vlan_client(vlan, model, name, vde_from_qemu, NULL, s);
+     qemu_set_fd_handler(vde_datafd(s->vde), vde_to_qemu, NULL, s);
+     snprintf(s->vc->info_str, sizeof(s->vc->info_str), "sock=%s,fd=%d",
+              sock, vde_datafd(s->vde));
+     return 0;
+ }
+ #endif
+ /* network connection */
+ typedef struct NetSocketState {
+     VLANClientState *vc;
+     int fd;
+     int state; /* 0 = getting length, 1 = getting data */
+     int index;
+     int packet_len;
+     uint8_t buf[4096];
+     struct sockaddr_in dgram_dst; /* contains inet host and port destination iff connectionless (SOCK_DGRAM) */
+ } NetSocketState;
+ typedef struct NetSocketListenState {
+     VLANState *vlan;
+     char *model;
+     char *name;
+     int fd;
+ } NetSocketListenState;
+ /* XXX: we consider we can send the whole packet without blocking */
+ static void net_socket_receive(void *opaque, const uint8_t *buf, int size)
+ {
+     NetSocketState *s = opaque;
+     uint32_t len;
+     len = htonl(size);
+     send_all(s->fd, (const uint8_t *)&len, sizeof(len));
+     send_all(s->fd, buf, size);
+ }
+ static void net_socket_receive_dgram(void *opaque, const uint8_t *buf, int size)
+ {
+     NetSocketState *s = opaque;
+     sendto(s->fd, buf, size, 0,
+            (struct sockaddr *)&s->dgram_dst, sizeof(s->dgram_dst));
+ }
+ static void net_socket_send(void *opaque)
+ {
+     NetSocketState *s = opaque;
+     int l, size, err;
+     uint8_t buf1[4096];
+     const uint8_t *buf;
+     size = recv(s->fd, buf1, sizeof(buf1), 0);
+     if (size < 0) {
+         err = socket_error();
+         if (err != EWOULDBLOCK)
+             goto eoc;
+     } else if (size == 0) {
+         /* end of connection */
+     eoc:
+         qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
+         closesocket(s->fd);
+         return;
+     }
+     buf = buf1;
+     while (size > 0) {
+         /* reassemble a packet from the network */
+         switch(s->state) {
+         case 0:
+             l = 4 - s->index;
+             if (l > size)
+                 l = size;
+             memcpy(s->buf + s->index, buf, l);
+             buf += l;
+             size -= l;
+             s->index += l;
+             if (s->index == 4) {
+                 /* got length */
+                 s->packet_len = ntohl(*(uint32_t *)s->buf);
+                 s->index = 0;
+                 s->state = 1;
+             }
+             break;
+         case 1:
+             l = s->packet_len - s->index;
+             if (l > size)
+                 l = size;
+             memcpy(s->buf + s->index, buf, l);
+             s->index += l;
+             buf += l;
+             size -= l;
+             if (s->index >= s->packet_len) {
+                 qemu_send_packet(s->vc, s->buf, s->packet_len);
+                 s->index = 0;
+                 s->state = 0;
+             }
+             break;
+         }
+     }
+ }
+ static void net_socket_send_dgram(void *opaque)
+ {
+     NetSocketState *s = opaque;
+     int size;
+     size = recv(s->fd, s->buf, sizeof(s->buf), 0);
+     if (size < 0)
+         return;
+     if (size == 0) {
+         /* end of connection */
+         qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
+         return;
+     }
+     qemu_send_packet(s->vc, s->buf, size);
+ }
+ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr)
+ {
+     struct ip_mreq imr;
+     int fd;
+     int val, ret;
+     if (!IN_MULTICAST(ntohl(mcastaddr->sin_addr.s_addr))) {
+       fprintf(stderr, "qemu: error: specified mcastaddr \"%s\" (0x%08x) does not contain a multicast address\n",
+               inet_ntoa(mcastaddr->sin_addr),
+                 (int)ntohl(mcastaddr->sin_addr.s_addr));
+       return -1;
+     }
+     fd = socket(PF_INET, SOCK_DGRAM, 0);
+     if (fd < 0) {
+         perror("socket(PF_INET, SOCK_DGRAM)");
+         return -1;
+     }
+     val = 1;
+     ret=setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
+                    (const char *)&val, sizeof(val));
+     if (ret < 0) {
+       perror("setsockopt(SOL_SOCKET, SO_REUSEADDR)");
+       goto fail;
+     }
+     ret = bind(fd, (struct sockaddr *)mcastaddr, sizeof(*mcastaddr));
+     if (ret < 0) {
+         perror("bind");
+         goto fail;
+     }
+     /* Add host to multicast group */
+     imr.imr_multiaddr = mcastaddr->sin_addr;
+     imr.imr_interface.s_addr = htonl(INADDR_ANY);
+     ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+                      (const char *)&imr, sizeof(struct ip_mreq));
+     if (ret < 0) {
+       perror("setsockopt(IP_ADD_MEMBERSHIP)");
+       goto fail;
+     }
+     /* Force mcast msgs to loopback (eg. several QEMUs in same host */
+     val = 1;
+     ret=setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
+                    (const char *)&val, sizeof(val));
+     if (ret < 0) {
+       perror("setsockopt(SOL_IP, IP_MULTICAST_LOOP)");
+       goto fail;
+     }
+     socket_set_nonblock(fd);
+     return fd;
+ fail:
+     if (fd >= 0)
+         closesocket(fd);
+     return -1;
+ }
+ static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan,
+                                                 const char *model,
+                                                 const char *name,
+                                                 int fd, int is_connected)
+ {
+     struct sockaddr_in saddr;
+     int newfd;
+     socklen_t saddr_len;
+     NetSocketState *s;
+     /* fd passed: multicast: "learn" dgram_dst address from bound address and save it
+      * Because this may be "shared" socket from a "master" process, datagrams would be recv()
+      * by ONLY ONE process: we must "clone" this dgram socket --jjo
+      */
+     if (is_connected) {
+       if (getsockname(fd, (struct sockaddr *) &saddr, &saddr_len) == 0) {
+           /* must be bound */
+           if (saddr.sin_addr.s_addr==0) {
+               fprintf(stderr, "qemu: error: init_dgram: fd=%d unbound, cannot setup multicast dst addr\n",
+                       fd);
+               return NULL;
+           }
+           /* clone dgram socket */
+           newfd = net_socket_mcast_create(&saddr);
+           if (newfd < 0) {
+               /* error already reported by net_socket_mcast_create() */
+               close(fd);
+               return NULL;
+           }
+           /* clone newfd to fd, close newfd */
+           dup2(newfd, fd);
+           close(newfd);
+       } else {
+           fprintf(stderr, "qemu: error: init_dgram: fd=%d failed getsockname(): %s\n",
+                   fd, strerror(errno));
+           return NULL;
+       }
+     }
+     s = qemu_mallocz(sizeof(NetSocketState));
+     if (!s)
+         return NULL;
+     s->fd = fd;
+     s->vc = qemu_new_vlan_client(vlan, model, name, net_socket_receive_dgram, NULL, s);
+     qemu_set_fd_handler(s->fd, net_socket_send_dgram, NULL, s);
+     /* mcast: save bound address as dst */
+     if (is_connected) s->dgram_dst=saddr;
+     snprintf(s->vc->info_str, sizeof(s->vc->info_str),
+           "socket: fd=%d (%s mcast=%s:%d)",
+           fd, is_connected? "cloned" : "",
+           inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
+     return s;
+ }
+ static void net_socket_connect(void *opaque)
+ {
+     NetSocketState *s = opaque;
+     qemu_set_fd_handler(s->fd, net_socket_send, NULL, s);
+ }
+ static NetSocketState *net_socket_fd_init_stream(VLANState *vlan,
+                                                  const char *model,
+                                                  const char *name,
+                                                  int fd, int is_connected)
+ {
+     NetSocketState *s;
+     s = qemu_mallocz(sizeof(NetSocketState));
+     if (!s)
+         return NULL;
+     s->fd = fd;
+     s->vc = qemu_new_vlan_client(vlan, model, name,
+                                  net_socket_receive, NULL, s);
+     snprintf(s->vc->info_str, sizeof(s->vc->info_str),
+              "socket: fd=%d", fd);
+     if (is_connected) {
+         net_socket_connect(s);
+     } else {
+         qemu_set_fd_handler(s->fd, NULL, net_socket_connect, s);
+     }
+     return s;
+ }
+ static NetSocketState *net_socket_fd_init(VLANState *vlan,
+                                           const char *model, const char *name,
+                                           int fd, int is_connected)
+ {
+     int so_type=-1, optlen=sizeof(so_type);
+     if(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&so_type,
+         (socklen_t *)&optlen)< 0) {
+       fprintf(stderr, "qemu: error: getsockopt(SO_TYPE) for fd=%d failed\n", fd);
+       return NULL;
+     }
+     switch(so_type) {
+     case SOCK_DGRAM:
+         return net_socket_fd_init_dgram(vlan, model, name, fd, is_connected);
+     case SOCK_STREAM:
+         return net_socket_fd_init_stream(vlan, model, name, fd, is_connected);
+     default:
+         /* who knows ... this could be a eg. a pty, do warn and continue as stream */
+         fprintf(stderr, "qemu: warning: socket type=%d for fd=%d is not SOCK_DGRAM or SOCK_STREAM\n", so_type, fd);
+         return net_socket_fd_init_stream(vlan, model, name, fd, is_connected);
+     }
+     return NULL;
+ }
+ static void net_socket_accept(void *opaque)
+ {
+     NetSocketListenState *s = opaque;
+     NetSocketState *s1;
+     struct sockaddr_in saddr;
+     socklen_t len;
+     int fd;
+     for(;;) {
+         len = sizeof(saddr);
+         fd = accept(s->fd, (struct sockaddr *)&saddr, &len);
+         if (fd < 0 && errno != EINTR) {
+             return;
+         } else if (fd >= 0) {
+             break;
+         }
+     }
+     s1 = net_socket_fd_init(s->vlan, s->model, s->name, fd, 1);
+     if (!s1) {
+         closesocket(fd);
+     } else {
+         snprintf(s1->vc->info_str, sizeof(s1->vc->info_str),
+                  "socket: connection from %s:%d",
+                  inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
+     }
+ }
+ static int net_socket_listen_init(VLANState *vlan,
+                                   const char *model,
+                                   const char *name,
+                                   const char *host_str)
+ {
+     NetSocketListenState *s;
+     int fd, val, ret;
+     struct sockaddr_in saddr;
+     if (parse_host_port(&saddr, host_str) < 0)
+         return -1;
+     s = qemu_mallocz(sizeof(NetSocketListenState));
+     if (!s)
+         return -1;
+     fd = socket(PF_INET, SOCK_STREAM, 0);
+     if (fd < 0) {
+         perror("socket");
+         return -1;
+     }
+     socket_set_nonblock(fd);
+     /* allow fast reuse */
+     val = 1;
+     setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val));
+     ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr));
+     if (ret < 0) {
+         perror("bind");
+         return -1;
+     }
+     ret = listen(fd, 0);
+     if (ret < 0) {
+         perror("listen");
+         return -1;
+     }
+     s->vlan = vlan;
+     s->model = strdup(model);
+     s->name = strdup(name);
+     s->fd = fd;
+     qemu_set_fd_handler(fd, net_socket_accept, NULL, s);
+     return 0;
+ }
+ static int net_socket_connect_init(VLANState *vlan,
+                                    const char *model,
+                                    const char *name,
+                                    const char *host_str)
+ {
+     NetSocketState *s;
+     int fd, connected, ret, err;
+     struct sockaddr_in saddr;
+     if (parse_host_port(&saddr, host_str) < 0)
+         return -1;
+     fd = socket(PF_INET, SOCK_STREAM, 0);
+     if (fd < 0) {
+         perror("socket");
+         return -1;
+     }
+     socket_set_nonblock(fd);
+     connected = 0;
+     for(;;) {
+         ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr));
+         if (ret < 0) {
+             err = socket_error();
+             if (err == EINTR || err == EWOULDBLOCK) {
+             } else if (err == EINPROGRESS) {
+                 break;
+ #ifdef _WIN32
+             } else if (err == WSAEALREADY) {
+                 break;
+ #endif
+             } else {
+                 perror("connect");
+                 closesocket(fd);
+                 return -1;
+             }
+         } else {
+             connected = 1;
+             break;
+         }
+     }
+     s = net_socket_fd_init(vlan, model, name, fd, connected);
+     if (!s)
+         return -1;
+     snprintf(s->vc->info_str, sizeof(s->vc->info_str),
+              "socket: connect to %s:%d",
+              inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
+     return 0;
+ }
+ static int net_socket_mcast_init(VLANState *vlan,
+                                  const char *model,
+                                  const char *name,
+                                  const char *host_str)
+ {
+     NetSocketState *s;
+     int fd;
+     struct sockaddr_in saddr;
+     if (parse_host_port(&saddr, host_str) < 0)
+         return -1;
+     fd = net_socket_mcast_create(&saddr);
+     if (fd < 0)
+       return -1;
+     s = net_socket_fd_init(vlan, model, name, fd, 0);
+     if (!s)
+         return -1;
+     s->dgram_dst = saddr;
+     snprintf(s->vc->info_str, sizeof(s->vc->info_str),
+              "socket: mcast=%s:%d",
+              inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
+     return 0;
+ }
+ /* find or alloc a new VLAN */
+ VLANState *qemu_find_vlan(int id)
+ {
+     VLANState **pvlan, *vlan;
+     for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) {
+         if (vlan->id == id)
+             return vlan;
+     }
+     vlan = qemu_mallocz(sizeof(VLANState));
+     if (!vlan)
+         return NULL;
+     vlan->id = id;
+     vlan->next = NULL;
+     pvlan = &first_vlan;
+     while (*pvlan != NULL)
+         pvlan = &(*pvlan)->next;
+     *pvlan = vlan;
+     return vlan;
+ }
+ void qemu_check_nic_model(NICInfo *nd, const char *model)
+ {
+     const char *models[2];
+     models[0] = model;
+     models[1] = NULL;
+     qemu_check_nic_model_list(nd, models, model);
+ }
+ void qemu_check_nic_model_list(NICInfo *nd, const char * const *models,
+                                const char *default_model)
+ {
+     int i, exit_status = 0;
+     if (!nd->model)
+         nd->model = strdup(default_model);
+     if (strcmp(nd->model, "?") != 0) {
+         for (i = 0 ; models[i]; i++)
+             if (strcmp(nd->model, models[i]) == 0)
+                 return;
+         fprintf(stderr, "qemu: Unsupported NIC model: %s\n", nd->model);
+         exit_status = 1;
+     }
+     fprintf(stderr, "qemu: Supported NIC models: ");
+     for (i = 0 ; models[i]; i++)
+         fprintf(stderr, "%s%c", models[i], models[i+1] ? ',' : '\n');
+     exit(exit_status);
+ }
+ int net_client_init(const char *device, const char *p)
+ {
+     char buf[1024];
+     int vlan_id, ret;
+     VLANState *vlan;
+     char *name = NULL;
+     vlan_id = 0;
+     if (get_param_value(buf, sizeof(buf), "vlan", p)) {
+         vlan_id = strtol(buf, NULL, 0);
+     }
+     vlan = qemu_find_vlan(vlan_id);
+     if (!vlan) {
+         fprintf(stderr, "Could not create vlan %d\n", vlan_id);
+         return -1;
+     }
+     if (get_param_value(buf, sizeof(buf), "name", p)) {
+         name = strdup(buf);
+     }
+     if (!strcmp(device, "nic")) {
+         NICInfo *nd;
+         uint8_t *macaddr;
+         if (nb_nics >= MAX_NICS) {
+             fprintf(stderr, "Too Many NICs\n");
+             return -1;
+         }
+         nd = &nd_table[nb_nics];
+         macaddr = nd->macaddr;
+         macaddr[0] = 0x52;
+         macaddr[1] = 0x54;
+         macaddr[2] = 0x00;
+         macaddr[3] = 0x12;
+         macaddr[4] = 0x34;
+         macaddr[5] = 0x56 + nb_nics;
+         if (get_param_value(buf, sizeof(buf), "macaddr", p)) {
+             if (parse_macaddr(macaddr, buf) < 0) {
+                 fprintf(stderr, "invalid syntax for ethernet address\n");
+                 return -1;
+             }
+         }
+         if (get_param_value(buf, sizeof(buf), "model", p)) {
+             nd->model = strdup(buf);
+         }
+         nd->vlan = vlan;
+         nd->name = name;
+         name = NULL;
+         nb_nics++;
+         vlan->nb_guest_devs++;
+         ret = 0;
+     } else
+     if (!strcmp(device, "none")) {
+         /* does nothing. It is needed to signal that no network cards
+            are wanted */
+         ret = 0;
+     } else
+ #ifdef CONFIG_SLIRP
+     if (!strcmp(device, "user")) {
+         if (get_param_value(buf, sizeof(buf), "hostname", p)) {
+             pstrcpy(slirp_hostname, sizeof(slirp_hostname), buf);
+         }
+         if (get_param_value(buf, sizeof(buf), "restrict", p)) {
+             slirp_restrict = (buf[0] == 'y') ? 1 : 0;
+         }
+         if (get_param_value(buf, sizeof(buf), "ip", p)) {
+             slirp_ip = strdup(buf);
+         }
+         vlan->nb_host_devs++;
+         ret = net_slirp_init(vlan, device, name);
+     } else
+ #endif
+ #ifdef _WIN32
+     if (!strcmp(device, "tap")) {
+         char ifname[64];
+         if (get_param_value(ifname, sizeof(ifname), "ifname", p) <= 0) {
+             fprintf(stderr, "tap: no interface name\n");
+             return -1;
+         }
+         vlan->nb_host_devs++;
+         ret = tap_win32_init(vlan, device, name, ifname);
+     } else
+ #elif defined (_AIX)
+ #else
+     if (!strcmp(device, "tap")) {
+         char ifname[64];
 -            ret = net_tap_init(vlan, device, name, ifname, setup_script, down_script);
++        char setup_script[1024], down_script[1024], script_arg[1024];
+         int fd;
+         vlan->nb_host_devs++;
+         if (get_param_value(buf, sizeof(buf), "fd", p) > 0) {
+             fd = strtol(buf, NULL, 0);
+             fcntl(fd, F_SETFL, O_NONBLOCK);
+             ret = -1;
+             if (net_tap_fd_init(vlan, device, name, fd))
+                 ret = 0;
+         } else {
+             if (get_param_value(ifname, sizeof(ifname), "ifname", p) <= 0) {
+                 ifname[0] = '\0';
+             }
+             if (get_param_value(setup_script, sizeof(setup_script), "script", p) == 0) {
+                 pstrcpy(setup_script, sizeof(setup_script), DEFAULT_NETWORK_SCRIPT);
+             }
+             if (get_param_value(down_script, sizeof(down_script), "downscript", p) == 0) {
+                 pstrcpy(down_script, sizeof(down_script), DEFAULT_NETWORK_DOWN_SCRIPT);
+             }
++            if (get_param_value(script_arg, sizeof(script_arg), "scriptarg", p) == 0 &&
++                get_param_value(script_arg, sizeof(script_arg), "bridge", p) == 0) { /* deprecated; for xend compatibility */
+++                pstrcpy(script_arg, sizeof(script_arg), "");
++            }
++            ret = net_tap_init(vlan, device, name, ifname, setup_script, down_script, script_arg);
+         }
+     } else
+ #endif
+     if (!strcmp(device, "socket")) {
+         if (get_param_value(buf, sizeof(buf), "fd", p) > 0) {
+             int fd;
+             fd = strtol(buf, NULL, 0);
+             ret = -1;
+             if (net_socket_fd_init(vlan, device, name, fd, 1))
+                 ret = 0;
+         } else if (get_param_value(buf, sizeof(buf), "listen", p) > 0) {
+             ret = net_socket_listen_init(vlan, device, name, buf);
+         } else if (get_param_value(buf, sizeof(buf), "connect", p) > 0) {
+             ret = net_socket_connect_init(vlan, device, name, buf);
+         } else if (get_param_value(buf, sizeof(buf), "mcast", p) > 0) {
+             ret = net_socket_mcast_init(vlan, device, name, buf);
+         } else {
+             fprintf(stderr, "Unknown socket options: %s\n", p);
+             return -1;
+         }
+         vlan->nb_host_devs++;
+     } else
+ #ifdef CONFIG_VDE
+     if (!strcmp(device, "vde")) {
+         char vde_sock[1024], vde_group[512];
+       int vde_port, vde_mode;
+         vlan->nb_host_devs++;
+         if (get_param_value(vde_sock, sizeof(vde_sock), "sock", p) <= 0) {
+           vde_sock[0] = '\0';
+       }
+       if (get_param_value(buf, sizeof(buf), "port", p) > 0) {
+           vde_port = strtol(buf, NULL, 10);
+       } else {
+           vde_port = 0;
+       }
+       if (get_param_value(vde_group, sizeof(vde_group), "group", p) <= 0) {
+           vde_group[0] = '\0';
+       }
+       if (get_param_value(buf, sizeof(buf), "mode", p) > 0) {
+           vde_mode = strtol(buf, NULL, 8);
+       } else {
+           vde_mode = 0700;
+       }
+       ret = net_vde_init(vlan, device, name, vde_sock, vde_port, vde_group, vde_mode);
+     } else
+ #endif
+     {
+         fprintf(stderr, "Unknown network device: %s\n", device);
+         if (name)
+             free(name);
+         return -1;
+     }
+     if (ret < 0) {
+         fprintf(stderr, "Could not initialize device '%s'\n", device);
+     }
+     if (name)
+         free(name);
+     return ret;
+ }
+ int net_client_parse(const char *str)
+ {
+     const char *p;
+     char *q;
+     char device[64];
+     p = str;
+     q = device;
+     while (*p != '\0' && *p != ',') {
+         if ((q - device) < sizeof(device) - 1)
+             *q++ = *p;
+         p++;
+     }
+     *q = '\0';
+     if (*p == ',')
+         p++;
+     return net_client_init(device, p);
+ }
+ void do_info_network(void)
+ {
+     VLANState *vlan;
+     VLANClientState *vc;
+     for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) {
+         term_printf("VLAN %d devices:\n", vlan->id);
+         for(vc = vlan->first_client; vc != NULL; vc = vc->next)
+             term_printf("  %s: %s\n", vc->name, vc->info_str);
+     }
+ }
+ int do_set_link(const char *name, const char *up_or_down)
+ {
+     VLANState *vlan;
+     VLANClientState *vc = NULL;
+     for (vlan = first_vlan; vlan != NULL; vlan = vlan->next)
+         for (vc = vlan->first_client; vc != NULL; vc = vc->next)
+             if (strcmp(vc->name, name) == 0)
+                 goto done;
+ done:
+     if (!vc) {
+         term_printf("could not find network device '%s'", name);
+         return 0;
+     }
+     if (strcmp(up_or_down, "up") == 0)
+         vc->link_down = 0;
+     else if (strcmp(up_or_down, "down") == 0)
+         vc->link_down = 1;
+     else
+         term_printf("invalid link status '%s'; only 'up' or 'down' valid\n",
+                     up_or_down);
+     if (vc->link_status_changed)
+         vc->link_status_changed(vc);
+     return 1;
+ }
+ void net_cleanup(void)
+ {
+     VLANState *vlan;
+ #if !defined(_WIN32)
+     /* close network clients */
+     for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) {
+         VLANClientState *vc;
+         for(vc = vlan->first_client; vc != NULL; vc = vc->next) {
+             if (vc->fd_read == tap_receive) {
+                 TAPState *s = vc->opaque;
+                 if (s->down_script[0])
+                     launch_script(s->down_script, s->down_script_arg, s->fd);
+             }
+ #if defined(CONFIG_VDE)
+             if (vc->fd_read == vde_from_qemu) {
+                 VDEState *s = vc->opaque;
+                 vde_close(s->vde);
+             }
+ #endif
+         }
+     }
+ #endif
+ }
+ void net_client_check(void)
+ {
+     VLANState *vlan;
+     for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) {
+         if (vlan->nb_guest_devs == 0 && vlan->nb_host_devs == 0)
+             continue;
+         if (vlan->nb_guest_devs == 0)
+             fprintf(stderr, "Warning: vlan %d with no nics\n", vlan->id);
+         if (vlan->nb_host_devs == 0)
+             fprintf(stderr,
+                     "Warning: vlan %d is not connected to host network\n",
+                     vlan->id);
+     }
+ }
diff --cc net.h
index 0d7ce7790600431bbd80c219686100c29f4b7f70,291807a65c6cba89e6976bdce5addbbfbe6fdf74..1662724cc89c3f5a547fdcdaeb705638a1d80443
--- 1/net.h
--- 2/net.h
+++ b/net.h
@@@ -69,4 -90,21 +90,23 @@@ uint16_t net_checksum_tcpudp(uint16_t l
                               uint8_t *addrs, uint8_t *buf);
  void net_checksum_calculate(uint8_t *data, int length);
  
+ /* from net.c */
+ int net_client_init(const char *device, const char *p);
+ int net_client_parse(const char *str);
+ void net_slirp_smb(const char *exported_dir);
+ void net_slirp_redir(const char *redir_str);
+ void net_cleanup(void);
+ int slirp_is_inited(void);
+ void net_client_check(void);
++#ifndef DEFAULT_NETWORK_SCRIPT
+ #define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup"
+ #define DEFAULT_NETWORK_DOWN_SCRIPT "/etc/qemu-ifdown"
++#endif
+ #ifdef __sun__
+ #define SMBD_COMMAND "/usr/sfw/sbin/smbd"
+ #else
+ #define SMBD_COMMAND "/usr/sbin/smbd"
+ #endif
  #endif
diff --cc osdep.c
Simple merge
diff --cc qemu-char.c
index 0000000000000000000000000000000000000000,0a01e16d4e3b6e8ff91e4ed6e8ee379f84834f5e..054bea952c3f77422e39142b34970ad0356de438
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,2216 +1,2226 @@@
 -#ifndef _WIN32
+ /*
+  * QEMU System Emulator
+  *
+  * Copyright (c) 2003-2008 Fabrice Bellard
+  *
+  * Permission is hereby granted, free of charge, to any person obtaining a copy
+  * of this software and associated documentation files (the "Software"), to deal
+  * in the Software without restriction, including without limitation the rights
+  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  * copies of the Software, and to permit persons to whom the Software is
+  * furnished to do so, subject to the following conditions:
+  *
+  * The above copyright notice and this permission notice shall be included in
+  * all copies or substantial portions of the Software.
+  *
+  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+  * THE SOFTWARE.
+  */
+ #include "qemu-common.h"
+ #include "net.h"
+ #include "console.h"
+ #include "sysemu.h"
+ #include "qemu-timer.h"
+ #include "qemu-char.h"
+ #include "block.h"
+ #include "hw/usb.h"
+ #include "hw/baum.h"
+ #include <unistd.h>
+ #include <fcntl.h>
+ #include <signal.h>
+ #include <time.h>
+ #include <errno.h>
+ #include <sys/time.h>
+ #include <zlib.h>
+ #ifndef _WIN32
+ #include <sys/times.h>
+ #include <sys/wait.h>
+ #include <termios.h>
+ #include <sys/mman.h>
+ #include <sys/ioctl.h>
+ #include <sys/resource.h>
+ #include <sys/socket.h>
+ #include <netinet/in.h>
+ #include <net/if.h>
+ #ifdef __NetBSD__
+ #include <net/if_tap.h>
+ #endif
+ #ifdef __linux__
+ #include <linux/if_tun.h>
+ #endif
+ #include <arpa/inet.h>
+ #include <dirent.h>
+ #include <netdb.h>
+ #include <sys/select.h>
+ #ifdef _BSD
+ #include <sys/stat.h>
+ #ifdef __FreeBSD__
+ #include <libutil.h>
+ #include <dev/ppbus/ppi.h>
+ #include <dev/ppbus/ppbconf.h>
+ #else
+ #include <util.h>
+ #endif
+ #elif defined (__GLIBC__) && defined (__FreeBSD_kernel__)
+ #include <freebsd/stdlib.h>
+ #else
+ #ifdef __linux__
+ #include <pty.h>
+ #include <linux/ppdev.h>
+ #include <linux/parport.h>
+ #endif
+ #ifdef __sun__
+ #include <sys/stat.h>
+ #include <sys/ethernet.h>
+ #include <sys/sockio.h>
+ #include <netinet/arp.h>
+ #include <netinet/in.h>
+ #include <netinet/in_systm.h>
+ #include <netinet/ip.h>
+ #include <netinet/ip_icmp.h> // must come after ip.h
+ #include <netinet/udp.h>
+ #include <netinet/tcp.h>
+ #include <net/if.h>
+ #include <syslog.h>
+ #include <stropts.h>
+ #endif
+ #endif
+ #endif
+ #include "qemu_socket.h"
+ /***********************************************************/
+ /* character device */
+ static void qemu_chr_event(CharDriverState *s, int event)
+ {
+     if (!s->chr_event)
+         return;
+     s->chr_event(s->handler_opaque, event);
+ }
+ static void qemu_chr_reset_bh(void *opaque)
+ {
+     CharDriverState *s = opaque;
+     qemu_chr_event(s, CHR_EVENT_RESET);
+     qemu_bh_delete(s->bh);
+     s->bh = NULL;
+ }
+ void qemu_chr_reset(CharDriverState *s)
+ {
+     if (s->bh == NULL) {
+       s->bh = qemu_bh_new(qemu_chr_reset_bh, s);
+       qemu_bh_schedule(s->bh);
+     }
+ }
+ int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len)
+ {
+     return s->chr_write(s, buf, len);
+ }
+ int qemu_chr_ioctl(CharDriverState *s, int cmd, void *arg)
+ {
+     if (!s->chr_ioctl)
+         return -ENOTSUP;
+     return s->chr_ioctl(s, cmd, arg);
+ }
+ int qemu_chr_can_read(CharDriverState *s)
+ {
+     if (!s->chr_can_read)
+         return 0;
+     return s->chr_can_read(s->handler_opaque);
+ }
+ void qemu_chr_read(CharDriverState *s, uint8_t *buf, int len)
+ {
+     s->chr_read(s->handler_opaque, buf, len);
+ }
+ void qemu_chr_accept_input(CharDriverState *s)
+ {
+     if (s->chr_accept_input)
+         s->chr_accept_input(s);
+ }
+ void qemu_chr_printf(CharDriverState *s, const char *fmt, ...)
+ {
+     char buf[4096];
+     va_list ap;
+     va_start(ap, fmt);
+     vsnprintf(buf, sizeof(buf), fmt, ap);
+     qemu_chr_write(s, (uint8_t *)buf, strlen(buf));
+     va_end(ap);
+ }
+ void qemu_chr_send_event(CharDriverState *s, int event)
+ {
+     if (s->chr_send_event)
+         s->chr_send_event(s, event);
+ }
+ void qemu_chr_add_handlers(CharDriverState *s,
+                            IOCanRWHandler *fd_can_read,
+                            IOReadHandler *fd_read,
+                            IOEventHandler *fd_event,
+                            void *opaque)
+ {
+     s->chr_can_read = fd_can_read;
+     s->chr_read = fd_read;
+     s->chr_event = fd_event;
+     s->handler_opaque = opaque;
+     if (s->chr_update_read_handler)
+         s->chr_update_read_handler(s);
+ }
+ static int null_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+ {
+     return len;
+ }
+ static CharDriverState *qemu_chr_open_null(void)
+ {
+     CharDriverState *chr;
+     chr = qemu_mallocz(sizeof(CharDriverState));
+     if (!chr)
+         return NULL;
+     chr->chr_write = null_chr_write;
+     return chr;
+ }
+ /* MUX driver for serial I/O splitting */
+ static int term_timestamps;
+ static int64_t term_timestamps_start;
+ #define MAX_MUX 4
+ #define MUX_BUFFER_SIZE 32    /* Must be a power of 2.  */
+ #define MUX_BUFFER_MASK (MUX_BUFFER_SIZE - 1)
+ typedef struct {
+     IOCanRWHandler *chr_can_read[MAX_MUX];
+     IOReadHandler *chr_read[MAX_MUX];
+     IOEventHandler *chr_event[MAX_MUX];
+     void *ext_opaque[MAX_MUX];
+     CharDriverState *drv;
+     unsigned char buffer[MUX_BUFFER_SIZE];
+     int prod;
+     int cons;
+     int mux_cnt;
+     int term_got_escape;
+     int max_size;
+ } MuxDriver;
+ static int mux_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+ {
+     MuxDriver *d = chr->opaque;
+     int ret;
+     if (!term_timestamps) {
+         ret = d->drv->chr_write(d->drv, buf, len);
+     } else {
+         int i;
+         ret = 0;
+         for(i = 0; i < len; i++) {
+             ret += d->drv->chr_write(d->drv, buf+i, 1);
+             if (buf[i] == '\n') {
+                 char buf1[64];
+                 int64_t ti;
+                 int secs;
+                 ti = qemu_get_clock(rt_clock);
+                 if (term_timestamps_start == -1)
+                     term_timestamps_start = ti;
+                 ti -= term_timestamps_start;
+                 secs = ti / 1000000000;
+                 snprintf(buf1, sizeof(buf1),
+                          "[%02d:%02d:%02d.%03d] ",
+                          secs / 3600,
+                          (secs / 60) % 60,
+                          secs % 60,
+                          (int)((ti / 1000000) % 1000));
+                 d->drv->chr_write(d->drv, (uint8_t *)buf1, strlen(buf1));
+             }
+         }
+     }
+     return ret;
+ }
+ static const char * const mux_help[] = {
+     "% h    print this help\n\r",
+     "% x    exit emulator\n\r",
+     "% s    save disk data back to file (if -snapshot)\n\r",
+     "% t    toggle console timestamps\n\r"
+     "% b    send break (magic sysrq)\n\r",
+     "% c    switch between console and monitor\n\r",
+     "% %  sends %\n\r",
+     NULL
+ };
+ int term_escape_char = 0x01; /* ctrl-a is used for escape */
+ static void mux_print_help(CharDriverState *chr)
+ {
+     int i, j;
+     char ebuf[15] = "Escape-Char";
+     char cbuf[50] = "\n\r";
+     if (term_escape_char > 0 && term_escape_char < 26) {
+         snprintf(cbuf, sizeof(cbuf), "\n\r");
+         snprintf(ebuf, sizeof(ebuf), "C-%c", term_escape_char - 1 + 'a');
+     } else {
+         snprintf(cbuf, sizeof(cbuf),
+                  "\n\rEscape-Char set to Ascii: 0x%02x\n\r\n\r",
+                  term_escape_char);
+     }
+     chr->chr_write(chr, (uint8_t *)cbuf, strlen(cbuf));
+     for (i = 0; mux_help[i] != NULL; i++) {
+         for (j=0; mux_help[i][j] != '\0'; j++) {
+             if (mux_help[i][j] == '%')
+                 chr->chr_write(chr, (uint8_t *)ebuf, strlen(ebuf));
+             else
+                 chr->chr_write(chr, (uint8_t *)&mux_help[i][j], 1);
+         }
+     }
+ }
+ static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch)
+ {
+     if (d->term_got_escape) {
+         d->term_got_escape = 0;
+         if (ch == term_escape_char)
+             goto send_char;
+         switch(ch) {
+         case '?':
+         case 'h':
+             mux_print_help(chr);
+             break;
+         case 'x':
+             {
+                  const char *term =  "QEMU: Terminated\n\r";
+                  chr->chr_write(chr,(uint8_t *)term,strlen(term));
+                  exit(0);
+                  break;
+             }
+         case 's':
+             {
+                 int i;
+                 for (i = 0; i < nb_drives; i++) {
+                         bdrv_commit(drives_table[i].bdrv);
+                 }
+             }
+             break;
+         case 'b':
+             qemu_chr_event(chr, CHR_EVENT_BREAK);
+             break;
+         case 'c':
+             /* Switch to the next registered device */
+             chr->focus++;
+             if (chr->focus >= d->mux_cnt)
+                 chr->focus = 0;
+             break;
+        case 't':
+            term_timestamps = !term_timestamps;
+            term_timestamps_start = -1;
+            break;
+         }
+     } else if (ch == term_escape_char) {
+         d->term_got_escape = 1;
+     } else {
+     send_char:
+         return 1;
+     }
+     return 0;
+ }
+ static void mux_chr_accept_input(CharDriverState *chr)
+ {
+     int m = chr->focus;
+     MuxDriver *d = chr->opaque;
+     while (d->prod != d->cons &&
+            d->chr_can_read[m] &&
+            d->chr_can_read[m](d->ext_opaque[m])) {
+         d->chr_read[m](d->ext_opaque[m],
+                        &d->buffer[d->cons++ & MUX_BUFFER_MASK], 1);
+     }
+ }
+ static int mux_chr_can_read(void *opaque)
+ {
+     CharDriverState *chr = opaque;
+     MuxDriver *d = chr->opaque;
+     if ((d->prod - d->cons) < MUX_BUFFER_SIZE)
+         return 1;
+     if (d->chr_can_read[chr->focus])
+         return d->chr_can_read[chr->focus](d->ext_opaque[chr->focus]);
+     return 0;
+ }
+ static void mux_chr_read(void *opaque, const uint8_t *buf, int size)
+ {
+     CharDriverState *chr = opaque;
+     MuxDriver *d = chr->opaque;
+     int m = chr->focus;
+     int i;
+     mux_chr_accept_input (opaque);
+     for(i = 0; i < size; i++)
+         if (mux_proc_byte(chr, d, buf[i])) {
+             if (d->prod == d->cons &&
+                 d->chr_can_read[m] &&
+                 d->chr_can_read[m](d->ext_opaque[m]))
+                 d->chr_read[m](d->ext_opaque[m], &buf[i], 1);
+             else
+                 d->buffer[d->prod++ & MUX_BUFFER_MASK] = buf[i];
+         }
+ }
+ static void mux_chr_event(void *opaque, int event)
+ {
+     CharDriverState *chr = opaque;
+     MuxDriver *d = chr->opaque;
+     int i;
+     /* Send the event to all registered listeners */
+     for (i = 0; i < d->mux_cnt; i++)
+         if (d->chr_event[i])
+             d->chr_event[i](d->ext_opaque[i], event);
+ }
+ static void mux_chr_update_read_handler(CharDriverState *chr)
+ {
+     MuxDriver *d = chr->opaque;
+     if (d->mux_cnt >= MAX_MUX) {
+         fprintf(stderr, "Cannot add I/O handlers, MUX array is full\n");
+         return;
+     }
+     d->ext_opaque[d->mux_cnt] = chr->handler_opaque;
+     d->chr_can_read[d->mux_cnt] = chr->chr_can_read;
+     d->chr_read[d->mux_cnt] = chr->chr_read;
+     d->chr_event[d->mux_cnt] = chr->chr_event;
+     /* Fix up the real driver with mux routines */
+     if (d->mux_cnt == 0) {
+         qemu_chr_add_handlers(d->drv, mux_chr_can_read, mux_chr_read,
+                               mux_chr_event, chr);
+     }
+     chr->focus = d->mux_cnt;
+     d->mux_cnt++;
+ }
+ static CharDriverState *qemu_chr_open_mux(CharDriverState *drv)
+ {
+     CharDriverState *chr;
+     MuxDriver *d;
+     chr = qemu_mallocz(sizeof(CharDriverState));
+     if (!chr)
+         return NULL;
+     d = qemu_mallocz(sizeof(MuxDriver));
+     if (!d) {
+         free(chr);
+         return NULL;
+     }
+     chr->opaque = d;
+     d->drv = drv;
+     chr->focus = -1;
+     chr->chr_write = mux_chr_write;
+     chr->chr_update_read_handler = mux_chr_update_read_handler;
+     chr->chr_accept_input = mux_chr_accept_input;
+     return chr;
+ }
+ #ifdef _WIN32
+ int send_all(int fd, const void *buf, int len1)
+ {
+     int ret, len;
+     len = len1;
+     while (len > 0) {
+         ret = send(fd, buf, len, 0);
+         if (ret < 0) {
+             errno = WSAGetLastError();
+             if (errno != WSAEWOULDBLOCK) {
+                 return -1;
+             }
+         } else if (ret == 0) {
+             break;
+         } else {
+             buf += ret;
+             len -= ret;
+         }
+     }
+     return len1 - len;
+ }
+ #else
+ int send_all(int fd, const void *buf, int len1)
+ {
+     return qemu_write(fd, buf, len1);
+ }
+ #endif /* !_WIN32 */
+ #ifndef _WIN32
+ typedef struct {
+     int fd_in, fd_out;
+     int max_size;
+ } FDCharDriver;
+ #define STDIO_MAX_CLIENTS 1
+ static int stdio_nb_clients = 0;
+ static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+ {
+     FDCharDriver *s = chr->opaque;
+     return send_all(s->fd_out, buf, len);
+ }
+ static int fd_chr_read_poll(void *opaque)
+ {
+     CharDriverState *chr = opaque;
+     FDCharDriver *s = chr->opaque;
+     s->max_size = qemu_chr_can_read(chr);
+     return s->max_size;
+ }
+ static void fd_chr_read(void *opaque)
+ {
+     CharDriverState *chr = opaque;
+     FDCharDriver *s = chr->opaque;
+     int size, len;
+     uint8_t buf[1024];
+     len = sizeof(buf);
+     if (len > s->max_size)
+         len = s->max_size;
+     if (len == 0)
+         return;
+     size = read(s->fd_in, buf, len);
+     if (size == 0) {
+         /* FD has been closed. Remove it from the active list.  */
+         qemu_set_fd_handler2(s->fd_in, NULL, NULL, NULL, NULL);
+         return;
+     }
+     if (size > 0) {
+         qemu_chr_read(chr, buf, size);
+     }
+ }
+ static void fd_chr_update_read_handler(CharDriverState *chr)
+ {
+     FDCharDriver *s = chr->opaque;
+     if (s->fd_in >= 0) {
+         if (nographic && s->fd_in == 0) {
+         } else {
+             qemu_set_fd_handler2(s->fd_in, fd_chr_read_poll,
+                                  fd_chr_read, NULL, chr);
+         }
+     }
+ }
+ static void fd_chr_close(struct CharDriverState *chr)
+ {
+     FDCharDriver *s = chr->opaque;
+     if (s->fd_in >= 0) {
+         if (nographic && s->fd_in == 0) {
+         } else {
+             qemu_set_fd_handler2(s->fd_in, NULL, NULL, NULL, NULL);
+         }
+     }
+     qemu_free(s);
+ }
+ /* open a character device to a unix fd */
+ static CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out)
+ {
+     CharDriverState *chr;
+     FDCharDriver *s;
+     socket_set_nonblock(fd_in);
+     socket_set_nonblock(fd_out);
+     chr = qemu_mallocz(sizeof(CharDriverState));
+     if (!chr)
+         return NULL;
+     s = qemu_mallocz(sizeof(FDCharDriver));
+     if (!s) {
+         free(chr);
+         return NULL;
+     }
+     s->fd_in = fd_in;
+     s->fd_out = fd_out;
+     chr->opaque = s;
+     chr->chr_write = fd_chr_write;
+     chr->chr_update_read_handler = fd_chr_update_read_handler;
+     chr->chr_close = fd_chr_close;
+     qemu_chr_reset(chr);
+     return chr;
+ }
+ static CharDriverState *qemu_chr_open_file_out(const char *file_out)
+ {
+     int fd_out;
+     TFR(fd_out = open(file_out, O_WRONLY | O_TRUNC | O_CREAT | O_BINARY, 0666));
+     if (fd_out < 0)
+         return NULL;
+     return qemu_chr_open_fd(-1, fd_out);
+ }
+ static CharDriverState *qemu_chr_open_pipe(const char *filename)
+ {
+     int fd_in, fd_out;
+     char filename_in[256], filename_out[256];
+     snprintf(filename_in, 256, "%s.in", filename);
+     snprintf(filename_out, 256, "%s.out", filename);
+     TFR(fd_in = open(filename_in, O_RDWR | O_BINARY));
+     TFR(fd_out = open(filename_out, O_RDWR | O_BINARY));
+     if (fd_in < 0 || fd_out < 0) {
+       if (fd_in >= 0)
+           close(fd_in);
+       if (fd_out >= 0)
+           close(fd_out);
+         TFR(fd_in = fd_out = open(filename, O_RDWR | O_BINARY));
+         if (fd_in < 0)
+             return NULL;
+     }
+     return qemu_chr_open_fd(fd_in, fd_out);
+ }
+ /* for STDIO, we handle the case where several clients use it
+    (nographic mode) */
+ #define TERM_FIFO_MAX_SIZE 1
+ static uint8_t term_fifo[TERM_FIFO_MAX_SIZE];
+ static int term_fifo_size;
+ static int stdio_read_poll(void *opaque)
+ {
+     CharDriverState *chr = opaque;
+     /* try to flush the queue if needed */
+     if (term_fifo_size != 0 && qemu_chr_can_read(chr) > 0) {
+         qemu_chr_read(chr, term_fifo, 1);
+         term_fifo_size = 0;
+     }
+     /* see if we can absorb more chars */
+     if (term_fifo_size == 0)
+         return 1;
+     else
+         return 0;
+ }
+ static void stdio_read(void *opaque)
+ {
+     int size;
+     uint8_t buf[1];
+     CharDriverState *chr = opaque;
+     size = read(0, buf, 1);
+     if (size == 0) {
+         /* stdin has been closed. Remove it from the active list.  */
+         qemu_set_fd_handler2(0, NULL, NULL, NULL, NULL);
+         return;
+     }
+     if (size > 0) {
+         if (qemu_chr_can_read(chr) > 0) {
+             qemu_chr_read(chr, buf, 1);
+         } else if (term_fifo_size == 0) {
+             term_fifo[term_fifo_size++] = buf[0];
+         }
+     }
+ }
+ /* init terminal so that we can grab keys */
+ static struct termios oldtty;
+ static int old_fd0_flags;
+ static int term_atexit_done;
+ static void term_exit(void)
+ {
+     tcsetattr (0, TCSANOW, &oldtty);
+     fcntl(0, F_SETFL, old_fd0_flags);
+ }
+ static void term_init(void)
+ {
+     struct termios tty;
+     tcgetattr (0, &tty);
+     oldtty = tty;
+     old_fd0_flags = fcntl(0, F_GETFL);
+     tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
+                           |INLCR|IGNCR|ICRNL|IXON);
+     tty.c_oflag |= OPOST;
+     tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
+     /* if graphical mode, we allow Ctrl-C handling */
+     if (nographic)
+         tty.c_lflag &= ~ISIG;
+     tty.c_cflag &= ~(CSIZE|PARENB);
+     tty.c_cflag |= CS8;
+     tty.c_cc[VMIN] = 1;
+     tty.c_cc[VTIME] = 0;
+     tcsetattr (0, TCSANOW, &tty);
+     if (!term_atexit_done++)
+         atexit(term_exit);
+     fcntl(0, F_SETFL, O_NONBLOCK);
+ }
+ static void qemu_chr_close_stdio(struct CharDriverState *chr)
+ {
+     term_exit();
+     stdio_nb_clients--;
+     qemu_set_fd_handler2(0, NULL, NULL, NULL, NULL);
+     fd_chr_close(chr);
+ }
+ static CharDriverState *qemu_chr_open_stdio(void)
+ {
+     CharDriverState *chr;
+     if (stdio_nb_clients >= STDIO_MAX_CLIENTS)
+         return NULL;
+     chr = qemu_chr_open_fd(0, 1);
+     chr->chr_close = qemu_chr_close_stdio;
+     qemu_set_fd_handler2(0, stdio_read_poll, stdio_read, NULL, chr);
+     stdio_nb_clients++;
+     term_init();
+     return chr;
+ }
+ #ifdef __sun__
+ /* Once Solaris has openpty(), this is going to be removed. */
+ int openpty(int *amaster, int *aslave, char *name,
+             struct termios *termp, struct winsize *winp)
+ {
+         const char *slave;
+         int mfd = -1, sfd = -1;
+         *amaster = *aslave = -1;
+         mfd = open("/dev/ptmx", O_RDWR | O_NOCTTY);
+         if (mfd < 0)
+                 goto err;
+         if (grantpt(mfd) == -1 || unlockpt(mfd) == -1)
+                 goto err;
+         if ((slave = ptsname(mfd)) == NULL)
+                 goto err;
+         if ((sfd = open(slave, O_RDONLY | O_NOCTTY)) == -1)
+                 goto err;
+         if (ioctl(sfd, I_PUSH, "ptem") == -1 ||
+             (termp != NULL && tcgetattr(sfd, termp) < 0))
+                 goto err;
+         if (amaster)
+                 *amaster = mfd;
+         if (aslave)
+                 *aslave = sfd;
+         if (winp)
+                 ioctl(sfd, TIOCSWINSZ, winp);
+         return 0;
+ err:
+         if (sfd != -1)
+                 close(sfd);
+         close(mfd);
+         return -1;
+ }
+ void cfmakeraw (struct termios *termios_p)
+ {
+         termios_p->c_iflag &=
+                 ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
+         termios_p->c_oflag &= ~OPOST;
+         termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
+         termios_p->c_cflag &= ~(CSIZE|PARENB);
+         termios_p->c_cflag |= CS8;
+         termios_p->c_cc[VMIN] = 0;
+         termios_p->c_cc[VTIME] = 0;
+ }
+ #endif
+ #if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \
+     || defined(__NetBSD__) || defined(__OpenBSD__)
+ typedef struct {
+     int fd;
+     int connected;
+     int polling;
+     int read_bytes;
+     QEMUTimer *timer;
+ } PtyCharDriver;
+ static void pty_chr_update_read_handler(CharDriverState *chr);
+ static void pty_chr_state(CharDriverState *chr, int connected);
+ static int pty_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+ {
+     PtyCharDriver *s = chr->opaque;
+     if (!s->connected) {
+         /* guest sends data, check for (re-)connect */
+         pty_chr_update_read_handler(chr);
+         return 0;
+     }
+     return send_all(s->fd, buf, len);
+ }
+ static int pty_chr_read_poll(void *opaque)
+ {
+     CharDriverState *chr = opaque;
+     PtyCharDriver *s = chr->opaque;
+     s->read_bytes = qemu_chr_can_read(chr);
+     return s->read_bytes;
+ }
+ static void pty_chr_read(void *opaque)
+ {
+     CharDriverState *chr = opaque;
+     PtyCharDriver *s = chr->opaque;
+     int size, len;
+     uint8_t buf[1024];
+     len = sizeof(buf);
+     if (len > s->read_bytes)
+         len = s->read_bytes;
+     if (len == 0)
+         return;
+     size = read(s->fd, buf, len);
+     if ((size == -1 && errno == EIO) ||
+         (size == 0)) {
+         pty_chr_state(chr, 0);
+         return;
+     }
+     if (size > 0) {
+         pty_chr_state(chr, 1);
+         qemu_chr_read(chr, buf, size);
+     }
+ }
+ static void pty_chr_update_read_handler(CharDriverState *chr)
+ {
+     PtyCharDriver *s = chr->opaque;
+     qemu_set_fd_handler2(s->fd, pty_chr_read_poll,
+                          pty_chr_read, NULL, chr);
+     s->polling = 1;
+     /*
+      * Short timeout here: just need wait long enougth that qemu makes
+      * it through the poll loop once.  When reconnected we want a
+      * short timeout so we notice it almost instantly.  Otherwise
+      * read() gives us -EIO instantly, making pty_chr_state() reset the
+      * timeout to the normal (much longer) poll interval before the
+      * timer triggers.
+      */
+     qemu_mod_timer(s->timer, qemu_get_clock(rt_clock) + 10);
+ }
+ static void pty_chr_state(CharDriverState *chr, int connected)
+ {
+     PtyCharDriver *s = chr->opaque;
+     if (!connected) {
+         qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
+         s->connected = 0;
+         s->polling = 0;
+         /* (re-)connect poll interval for idle guests: once per second.
+          * We check more frequently in case the guests sends data to
+          * the virtual device linked to our pty. */
+         qemu_mod_timer(s->timer, qemu_get_clock(rt_clock) + 1000);
+     } else {
+         if (!s->connected)
+             qemu_chr_reset(chr);
+         s->connected = 1;
+     }
+ }
+ static void pty_chr_timer(void *opaque)
+ {
+     struct CharDriverState *chr = opaque;
+     PtyCharDriver *s = chr->opaque;
+     if (s->connected)
+         return;
+     if (s->polling) {
+         /* If we arrive here without polling being cleared due
+          * read returning -EIO, then we are (re-)connected */
+         pty_chr_state(chr, 1);
+         return;
+     }
+     /* Next poll ... */
+     pty_chr_update_read_handler(chr);
+ }
++static int pty_chr_getname(struct CharDriverState *chr, char *buf, size_t len) {
++    char *name;
++    FDCharDriver *s = chr->opaque;
++
++    name = ptsname(s->fd_in);
++    if (!name) return -1;
++    return snprintf(buf,len, "pty %s", name);
++}
++
+ static void pty_chr_close(struct CharDriverState *chr)
+ {
+     PtyCharDriver *s = chr->opaque;
+     qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
+     close(s->fd);
+     qemu_free(s);
+ }
+ static CharDriverState *qemu_chr_open_pty(void)
+ {
+     CharDriverState *chr;
+     PtyCharDriver *s;
+     struct termios tty;
+     int slave_fd, len;
+ #if defined(__OpenBSD__)
+     char pty_name[PATH_MAX];
+ #define q_ptsname(x) pty_name
+ #else
+     char *pty_name = NULL;
+ #define q_ptsname(x) ptsname(x)
+ #endif
+     chr = qemu_mallocz(sizeof(CharDriverState));
+     if (!chr)
+         return NULL;
+     s = qemu_mallocz(sizeof(PtyCharDriver));
+     if (!s) {
+         qemu_free(chr);
+         return NULL;
+     }
+     if (openpty(&s->fd, &slave_fd, pty_name, NULL, NULL) < 0) {
+         return NULL;
+     }
+     /* Set raw attributes on the pty. */
+     tcgetattr(slave_fd, &tty);
+     cfmakeraw(&tty);
+     tcsetattr(slave_fd, TCSAFLUSH, &tty);
+     close(slave_fd);
+     len = strlen(q_ptsname(s->fd)) + 5;
+     chr->filename = qemu_malloc(len);
+     snprintf(chr->filename, len, "pty:%s", q_ptsname(s->fd));
+     fprintf(stderr, "char device redirected to %s\n", q_ptsname(s->fd));
+     chr->opaque = s;
+     chr->chr_write = pty_chr_write;
+     chr->chr_update_read_handler = pty_chr_update_read_handler;
+     chr->chr_close = pty_chr_close;
++    chr->chr_getname = pty_chr_getname;
+     s->timer = qemu_new_timer(rt_clock, pty_chr_timer, chr);
+     return chr;
+ }
+ static void tty_serial_init(int fd, int speed,
+                             int parity, int data_bits, int stop_bits)
+ {
+     struct termios tty;
+     speed_t spd;
+ #if 0
+     printf("tty_serial_init: speed=%d parity=%c data=%d stop=%d\n",
+            speed, parity, data_bits, stop_bits);
+ #endif
+     tcgetattr (fd, &tty);
+ #define MARGIN 1.1
+     if (speed <= 50 * MARGIN)
+         spd = B50;
+     else if (speed <= 75 * MARGIN)
+         spd = B75;
+     else if (speed <= 300 * MARGIN)
+         spd = B300;
+     else if (speed <= 600 * MARGIN)
+         spd = B600;
+     else if (speed <= 1200 * MARGIN)
+         spd = B1200;
+     else if (speed <= 2400 * MARGIN)
+         spd = B2400;
+     else if (speed <= 4800 * MARGIN)
+         spd = B4800;
+     else if (speed <= 9600 * MARGIN)
+         spd = B9600;
+     else if (speed <= 19200 * MARGIN)
+         spd = B19200;
+     else if (speed <= 38400 * MARGIN)
+         spd = B38400;
+     else if (speed <= 57600 * MARGIN)
+         spd = B57600;
+     else if (speed <= 115200 * MARGIN)
+         spd = B115200;
+     else
+         spd = B115200;
+     cfsetispeed(&tty, spd);
+     cfsetospeed(&tty, spd);
+     tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
+                           |INLCR|IGNCR|ICRNL|IXON);
+     tty.c_oflag |= OPOST;
+     tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN|ISIG);
+     tty.c_cflag &= ~(CSIZE|PARENB|PARODD|CRTSCTS|CSTOPB);
+     switch(data_bits) {
+     default:
+     case 8:
+         tty.c_cflag |= CS8;
+         break;
+     case 7:
+         tty.c_cflag |= CS7;
+         break;
+     case 6:
+         tty.c_cflag |= CS6;
+         break;
+     case 5:
+         tty.c_cflag |= CS5;
+         break;
+     }
+     switch(parity) {
+     default:
+     case 'N':
+         break;
+     case 'E':
+         tty.c_cflag |= PARENB;
+         break;
+     case 'O':
+         tty.c_cflag |= PARENB | PARODD;
+         break;
+     }
+     if (stop_bits == 2)
+         tty.c_cflag |= CSTOPB;
+     tcsetattr (fd, TCSANOW, &tty);
+ }
+ static int tty_serial_ioctl(CharDriverState *chr, int cmd, void *arg)
+ {
+     FDCharDriver *s = chr->opaque;
+     switch(cmd) {
+     case CHR_IOCTL_SERIAL_SET_PARAMS:
+         {
+             QEMUSerialSetParams *ssp = arg;
+             tty_serial_init(s->fd_in, ssp->speed, ssp->parity,
+                             ssp->data_bits, ssp->stop_bits);
+         }
+         break;
+     case CHR_IOCTL_SERIAL_SET_BREAK:
+         {
+             int enable = *(int *)arg;
+             if (enable)
+                 tcsendbreak(s->fd_in, 1);
+         }
+         break;
+     case CHR_IOCTL_SERIAL_GET_TIOCM:
+         {
+             int sarg = 0;
+             int *targ = (int *)arg;
+             ioctl(s->fd_in, TIOCMGET, &sarg);
+             *targ = 0;
+             if (sarg | TIOCM_CTS)
+                 *targ |= CHR_TIOCM_CTS;
+             if (sarg | TIOCM_CAR)
+                 *targ |= CHR_TIOCM_CAR;
+             if (sarg | TIOCM_DSR)
+                 *targ |= CHR_TIOCM_DSR;
+             if (sarg | TIOCM_RI)
+                 *targ |= CHR_TIOCM_RI;
+             if (sarg | TIOCM_DTR)
+                 *targ |= CHR_TIOCM_DTR;
+             if (sarg | TIOCM_RTS)
+                 *targ |= CHR_TIOCM_RTS;
+         }
+         break;
+     case CHR_IOCTL_SERIAL_SET_TIOCM:
+         {
+             int sarg = *(int *)arg;
+             int targ = 0;
+             if (sarg | CHR_TIOCM_DTR)
+                 targ |= TIOCM_DTR;
+             if (sarg | CHR_TIOCM_RTS)
+                 targ |= TIOCM_RTS;
+             ioctl(s->fd_in, TIOCMSET, &targ);
+         }
+         break;
+     default:
+         return -ENOTSUP;
+     }
+     return 0;
+ }
+ static CharDriverState *qemu_chr_open_tty(const char *filename)
+ {
+     CharDriverState *chr;
+     int fd;
+     TFR(fd = open(filename, O_RDWR | O_NONBLOCK));
+     tty_serial_init(fd, 115200, 'N', 8, 1);
+     chr = qemu_chr_open_fd(fd, fd);
+     if (!chr) {
+         close(fd);
+         return NULL;
+     }
+     chr->chr_ioctl = tty_serial_ioctl;
+     qemu_chr_reset(chr);
+     return chr;
+ }
+ #else  /* ! __linux__ && ! __sun__ */
+ static CharDriverState *qemu_chr_open_pty(void)
+ {
+     return NULL;
+ }
+ #endif /* __linux__ || __sun__ */
+ #if defined(__linux__)
+ typedef struct {
+     int fd;
+     int mode;
+ } ParallelCharDriver;
+ static int pp_hw_mode(ParallelCharDriver *s, uint16_t mode)
+ {
+     if (s->mode != mode) {
+       int m = mode;
+         if (ioctl(s->fd, PPSETMODE, &m) < 0)
+             return 0;
+       s->mode = mode;
+     }
+     return 1;
+ }
+ static int pp_ioctl(CharDriverState *chr, int cmd, void *arg)
+ {
+     ParallelCharDriver *drv = chr->opaque;
+     int fd = drv->fd;
+     uint8_t b;
+     switch(cmd) {
+     case CHR_IOCTL_PP_READ_DATA:
+         if (ioctl(fd, PPRDATA, &b) < 0)
+             return -ENOTSUP;
+         *(uint8_t *)arg = b;
+         break;
+     case CHR_IOCTL_PP_WRITE_DATA:
+         b = *(uint8_t *)arg;
+         if (ioctl(fd, PPWDATA, &b) < 0)
+             return -ENOTSUP;
+         break;
+     case CHR_IOCTL_PP_READ_CONTROL:
+         if (ioctl(fd, PPRCONTROL, &b) < 0)
+             return -ENOTSUP;
+       /* Linux gives only the lowest bits, and no way to know data
+          direction! For better compatibility set the fixed upper
+          bits. */
+         *(uint8_t *)arg = b | 0xc0;
+         break;
+     case CHR_IOCTL_PP_WRITE_CONTROL:
+         b = *(uint8_t *)arg;
+         if (ioctl(fd, PPWCONTROL, &b) < 0)
+             return -ENOTSUP;
+         break;
+     case CHR_IOCTL_PP_READ_STATUS:
+         if (ioctl(fd, PPRSTATUS, &b) < 0)
+             return -ENOTSUP;
+         *(uint8_t *)arg = b;
+         break;
+     case CHR_IOCTL_PP_DATA_DIR:
+         if (ioctl(fd, PPDATADIR, (int *)arg) < 0)
+             return -ENOTSUP;
+         break;
+     case CHR_IOCTL_PP_EPP_READ_ADDR:
+       if (pp_hw_mode(drv, IEEE1284_MODE_EPP|IEEE1284_ADDR)) {
+           struct ParallelIOArg *parg = arg;
+           int n = read(fd, parg->buffer, parg->count);
+           if (n != parg->count) {
+               return -EIO;
+           }
+       }
+         break;
+     case CHR_IOCTL_PP_EPP_READ:
+       if (pp_hw_mode(drv, IEEE1284_MODE_EPP)) {
+           struct ParallelIOArg *parg = arg;
+           int n = read(fd, parg->buffer, parg->count);
+           if (n != parg->count) {
+               return -EIO;
+           }
+       }
+         break;
+     case CHR_IOCTL_PP_EPP_WRITE_ADDR:
+       if (pp_hw_mode(drv, IEEE1284_MODE_EPP|IEEE1284_ADDR)) {
+           struct ParallelIOArg *parg = arg;
+           int n = write(fd, parg->buffer, parg->count);
+           if (n != parg->count) {
+               return -EIO;
+           }
+       }
+         break;
+     case CHR_IOCTL_PP_EPP_WRITE:
+       if (pp_hw_mode(drv, IEEE1284_MODE_EPP)) {
+           struct ParallelIOArg *parg = arg;
+           int n = write(fd, parg->buffer, parg->count);
+           if (n != parg->count) {
+               return -EIO;
+           }
+       }
+         break;
+     default:
+         return -ENOTSUP;
+     }
+     return 0;
+ }
+ static void pp_close(CharDriverState *chr)
+ {
+     ParallelCharDriver *drv = chr->opaque;
+     int fd = drv->fd;
+     pp_hw_mode(drv, IEEE1284_MODE_COMPAT);
+     ioctl(fd, PPRELEASE);
+     close(fd);
+     qemu_free(drv);
+ }
+ static CharDriverState *qemu_chr_open_pp(const char *filename)
+ {
+     CharDriverState *chr;
+     ParallelCharDriver *drv;
+     int fd;
+     TFR(fd = open(filename, O_RDWR));
+     if (fd < 0)
+         return NULL;
+     if (ioctl(fd, PPCLAIM) < 0) {
+         close(fd);
+         return NULL;
+     }
+     drv = qemu_mallocz(sizeof(ParallelCharDriver));
+     if (!drv) {
+         close(fd);
+         return NULL;
+     }
+     drv->fd = fd;
+     drv->mode = IEEE1284_MODE_COMPAT;
+     chr = qemu_mallocz(sizeof(CharDriverState));
+     if (!chr) {
+       qemu_free(drv);
+         close(fd);
+         return NULL;
+     }
+     chr->chr_write = null_chr_write;
+     chr->chr_ioctl = pp_ioctl;
+     chr->chr_close = pp_close;
+     chr->opaque = drv;
+     qemu_chr_reset(chr);
+     return chr;
+ }
+ #endif /* __linux__ */
+ #if defined(__FreeBSD__)
+ static int pp_ioctl(CharDriverState *chr, int cmd, void *arg)
+ {
+     int fd = (int)chr->opaque;
+     uint8_t b;
+     switch(cmd) {
+     case CHR_IOCTL_PP_READ_DATA:
+         if (ioctl(fd, PPIGDATA, &b) < 0)
+             return -ENOTSUP;
+         *(uint8_t *)arg = b;
+         break;
+     case CHR_IOCTL_PP_WRITE_DATA:
+         b = *(uint8_t *)arg;
+         if (ioctl(fd, PPISDATA, &b) < 0)
+             return -ENOTSUP;
+         break;
+     case CHR_IOCTL_PP_READ_CONTROL:
+         if (ioctl(fd, PPIGCTRL, &b) < 0)
+             return -ENOTSUP;
+         *(uint8_t *)arg = b;
+         break;
+     case CHR_IOCTL_PP_WRITE_CONTROL:
+         b = *(uint8_t *)arg;
+         if (ioctl(fd, PPISCTRL, &b) < 0)
+             return -ENOTSUP;
+         break;
+     case CHR_IOCTL_PP_READ_STATUS:
+         if (ioctl(fd, PPIGSTATUS, &b) < 0)
+             return -ENOTSUP;
+         *(uint8_t *)arg = b;
+         break;
+     default:
+         return -ENOTSUP;
+     }
+     return 0;
+ }
+ static CharDriverState *qemu_chr_open_pp(const char *filename)
+ {
+     CharDriverState *chr;
+     int fd;
+     fd = open(filename, O_RDWR);
+     if (fd < 0)
+         return NULL;
+     chr = qemu_mallocz(sizeof(CharDriverState));
+     if (!chr) {
+         close(fd);
+         return NULL;
+     }
+     chr->opaque = (void *)fd;
+     chr->chr_write = null_chr_write;
+     chr->chr_ioctl = pp_ioctl;
+     return chr;
+ }
+ #endif
+ #else /* _WIN32 */
+ typedef struct {
+     int max_size;
+     HANDLE hcom, hrecv, hsend;
+     OVERLAPPED orecv, osend;
+     BOOL fpipe;
+     DWORD len;
+ } WinCharState;
+ #define NSENDBUF 2048
+ #define NRECVBUF 2048
+ #define MAXCONNECT 1
+ #define NTIMEOUT 5000
+ static int win_chr_poll(void *opaque);
+ static int win_chr_pipe_poll(void *opaque);
+ static void win_chr_close(CharDriverState *chr)
+ {
+     WinCharState *s = chr->opaque;
+     if (s->hsend) {
+         CloseHandle(s->hsend);
+         s->hsend = NULL;
+     }
+     if (s->hrecv) {
+         CloseHandle(s->hrecv);
+         s->hrecv = NULL;
+     }
+     if (s->hcom) {
+         CloseHandle(s->hcom);
+         s->hcom = NULL;
+     }
+     if (s->fpipe)
+         qemu_del_polling_cb(win_chr_pipe_poll, chr);
+     else
+         qemu_del_polling_cb(win_chr_poll, chr);
+ }
+ static int win_chr_init(CharDriverState *chr, const char *filename)
+ {
+     WinCharState *s = chr->opaque;
+     COMMCONFIG comcfg;
+     COMMTIMEOUTS cto = { 0, 0, 0, 0, 0};
+     COMSTAT comstat;
+     DWORD size;
+     DWORD err;
+     s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL);
+     if (!s->hsend) {
+         fprintf(stderr, "Failed CreateEvent\n");
+         goto fail;
+     }
+     s->hrecv = CreateEvent(NULL, TRUE, FALSE, NULL);
+     if (!s->hrecv) {
+         fprintf(stderr, "Failed CreateEvent\n");
+         goto fail;
+     }
+     s->hcom = CreateFile(filename, GENERIC_READ|GENERIC_WRITE, 0, NULL,
+                       OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
+     if (s->hcom == INVALID_HANDLE_VALUE) {
+         fprintf(stderr, "Failed CreateFile (%lu)\n", GetLastError());
+         s->hcom = NULL;
+         goto fail;
+     }
+     if (!SetupComm(s->hcom, NRECVBUF, NSENDBUF)) {
+         fprintf(stderr, "Failed SetupComm\n");
+         goto fail;
+     }
+     ZeroMemory(&comcfg, sizeof(COMMCONFIG));
+     size = sizeof(COMMCONFIG);
+     GetDefaultCommConfig(filename, &comcfg, &size);
+     comcfg.dcb.DCBlength = sizeof(DCB);
+     CommConfigDialog(filename, NULL, &comcfg);
+     if (!SetCommState(s->hcom, &comcfg.dcb)) {
+         fprintf(stderr, "Failed SetCommState\n");
+         goto fail;
+     }
+     if (!SetCommMask(s->hcom, EV_ERR)) {
+         fprintf(stderr, "Failed SetCommMask\n");
+         goto fail;
+     }
+     cto.ReadIntervalTimeout = MAXDWORD;
+     if (!SetCommTimeouts(s->hcom, &cto)) {
+         fprintf(stderr, "Failed SetCommTimeouts\n");
+         goto fail;
+     }
+     if (!ClearCommError(s->hcom, &err, &comstat)) {
+         fprintf(stderr, "Failed ClearCommError\n");
+         goto fail;
+     }
+     qemu_add_polling_cb(win_chr_poll, chr);
+     return 0;
+  fail:
+     win_chr_close(chr);
+     return -1;
+ }
+ static int win_chr_write(CharDriverState *chr, const uint8_t *buf, int len1)
+ {
+     WinCharState *s = chr->opaque;
+     DWORD len, ret, size, err;
+     len = len1;
+     ZeroMemory(&s->osend, sizeof(s->osend));
+     s->osend.hEvent = s->hsend;
+     while (len > 0) {
+         if (s->hsend)
+             ret = WriteFile(s->hcom, buf, len, &size, &s->osend);
+         else
+             ret = WriteFile(s->hcom, buf, len, &size, NULL);
+         if (!ret) {
+             err = GetLastError();
+             if (err == ERROR_IO_PENDING) {
+                 ret = GetOverlappedResult(s->hcom, &s->osend, &size, TRUE);
+                 if (ret) {
+                     buf += size;
+                     len -= size;
+                 } else {
+                     break;
+                 }
+             } else {
+                 break;
+             }
+         } else {
+             buf += size;
+             len -= size;
+         }
+     }
+     return len1 - len;
+ }
+ static int win_chr_read_poll(CharDriverState *chr)
+ {
+     WinCharState *s = chr->opaque;
+     s->max_size = qemu_chr_can_read(chr);
+     return s->max_size;
+ }
+ static void win_chr_readfile(CharDriverState *chr)
+ {
+     WinCharState *s = chr->opaque;
+     int ret, err;
+     uint8_t buf[1024];
+     DWORD size;
+     ZeroMemory(&s->orecv, sizeof(s->orecv));
+     s->orecv.hEvent = s->hrecv;
+     ret = ReadFile(s->hcom, buf, s->len, &size, &s->orecv);
+     if (!ret) {
+         err = GetLastError();
+         if (err == ERROR_IO_PENDING) {
+             ret = GetOverlappedResult(s->hcom, &s->orecv, &size, TRUE);
+         }
+     }
+     if (size > 0) {
+         qemu_chr_read(chr, buf, size);
+     }
+ }
+ static void win_chr_read(CharDriverState *chr)
+ {
+     WinCharState *s = chr->opaque;
+     if (s->len > s->max_size)
+         s->len = s->max_size;
+     if (s->len == 0)
+         return;
+     win_chr_readfile(chr);
+ }
+ static int win_chr_poll(void *opaque)
+ {
+     CharDriverState *chr = opaque;
+     WinCharState *s = chr->opaque;
+     COMSTAT status;
+     DWORD comerr;
+     ClearCommError(s->hcom, &comerr, &status);
+     if (status.cbInQue > 0) {
+         s->len = status.cbInQue;
+         win_chr_read_poll(chr);
+         win_chr_read(chr);
+         return 1;
+     }
+     return 0;
+ }
+ static CharDriverState *qemu_chr_open_win(const char *filename)
+ {
+     CharDriverState *chr;
+     WinCharState *s;
+     chr = qemu_mallocz(sizeof(CharDriverState));
+     if (!chr)
+         return NULL;
+     s = qemu_mallocz(sizeof(WinCharState));
+     if (!s) {
+         free(chr);
+         return NULL;
+     }
+     chr->opaque = s;
+     chr->chr_write = win_chr_write;
+     chr->chr_close = win_chr_close;
+     if (win_chr_init(chr, filename) < 0) {
+         free(s);
+         free(chr);
+         return NULL;
+     }
+     qemu_chr_reset(chr);
+     return chr;
+ }
+ static int win_chr_pipe_poll(void *opaque)
+ {
+     CharDriverState *chr = opaque;
+     WinCharState *s = chr->opaque;
+     DWORD size;
+     PeekNamedPipe(s->hcom, NULL, 0, NULL, &size, NULL);
+     if (size > 0) {
+         s->len = size;
+         win_chr_read_poll(chr);
+         win_chr_read(chr);
+         return 1;
+     }
+     return 0;
+ }
+ static int win_chr_pipe_init(CharDriverState *chr, const char *filename)
+ {
+     WinCharState *s = chr->opaque;
+     OVERLAPPED ov;
+     int ret;
+     DWORD size;
+     char openname[256];
+     s->fpipe = TRUE;
+     s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL);
+     if (!s->hsend) {
+         fprintf(stderr, "Failed CreateEvent\n");
+         goto fail;
+     }
+     s->hrecv = CreateEvent(NULL, TRUE, FALSE, NULL);
+     if (!s->hrecv) {
+         fprintf(stderr, "Failed CreateEvent\n");
+         goto fail;
+     }
+     snprintf(openname, sizeof(openname), "\\\\.\\pipe\\%s", filename);
+     s->hcom = CreateNamedPipe(openname, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
+                               PIPE_TYPE_BYTE | PIPE_READMODE_BYTE |
+                               PIPE_WAIT,
+                               MAXCONNECT, NSENDBUF, NRECVBUF, NTIMEOUT, NULL);
+     if (s->hcom == INVALID_HANDLE_VALUE) {
+         fprintf(stderr, "Failed CreateNamedPipe (%lu)\n", GetLastError());
+         s->hcom = NULL;
+         goto fail;
+     }
+     ZeroMemory(&ov, sizeof(ov));
+     ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+     ret = ConnectNamedPipe(s->hcom, &ov);
+     if (ret) {
+         fprintf(stderr, "Failed ConnectNamedPipe\n");
+         goto fail;
+     }
+     ret = GetOverlappedResult(s->hcom, &ov, &size, TRUE);
+     if (!ret) {
+         fprintf(stderr, "Failed GetOverlappedResult\n");
+         if (ov.hEvent) {
+             CloseHandle(ov.hEvent);
+             ov.hEvent = NULL;
+         }
+         goto fail;
+     }
+     if (ov.hEvent) {
+         CloseHandle(ov.hEvent);
+         ov.hEvent = NULL;
+     }
+     qemu_add_polling_cb(win_chr_pipe_poll, chr);
+     return 0;
+  fail:
+     win_chr_close(chr);
+     return -1;
+ }
+ static CharDriverState *qemu_chr_open_win_pipe(const char *filename)
+ {
+     CharDriverState *chr;
+     WinCharState *s;
+     chr = qemu_mallocz(sizeof(CharDriverState));
+     if (!chr)
+         return NULL;
+     s = qemu_mallocz(sizeof(WinCharState));
+     if (!s) {
+         free(chr);
+         return NULL;
+     }
+     chr->opaque = s;
+     chr->chr_write = win_chr_write;
+     chr->chr_close = win_chr_close;
+     if (win_chr_pipe_init(chr, filename) < 0) {
+         free(s);
+         free(chr);
+         return NULL;
+     }
+     qemu_chr_reset(chr);
+     return chr;
+ }
+ static CharDriverState *qemu_chr_open_win_file(HANDLE fd_out)
+ {
+     CharDriverState *chr;
+     WinCharState *s;
+     chr = qemu_mallocz(sizeof(CharDriverState));
+     if (!chr)
+         return NULL;
+     s = qemu_mallocz(sizeof(WinCharState));
+     if (!s) {
+         free(chr);
+         return NULL;
+     }
+     s->hcom = fd_out;
+     chr->opaque = s;
+     chr->chr_write = win_chr_write;
+     qemu_chr_reset(chr);
+     return chr;
+ }
+ static CharDriverState *qemu_chr_open_win_con(const char *filename)
+ {
+     return qemu_chr_open_win_file(GetStdHandle(STD_OUTPUT_HANDLE));
+ }
+ static CharDriverState *qemu_chr_open_win_file_out(const char *file_out)
+ {
+     HANDLE fd_out;
+     fd_out = CreateFile(file_out, GENERIC_WRITE, FILE_SHARE_READ, NULL,
+                         OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+     if (fd_out == INVALID_HANDLE_VALUE)
+         return NULL;
+     return qemu_chr_open_win_file(fd_out);
+ }
+ #endif /* !_WIN32 */
+ /***********************************************************/
+ /* UDP Net console */
+ typedef struct {
+     int fd;
+     struct sockaddr_in daddr;
+     uint8_t buf[1024];
+     int bufcnt;
+     int bufptr;
+     int max_size;
+ } NetCharDriver;
+ static int udp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+ {
+     NetCharDriver *s = chr->opaque;
+     return sendto(s->fd, buf, len, 0,
+                   (struct sockaddr *)&s->daddr, sizeof(struct sockaddr_in));
+ }
+ static int udp_chr_read_poll(void *opaque)
+ {
+     CharDriverState *chr = opaque;
+     NetCharDriver *s = chr->opaque;
+     s->max_size = qemu_chr_can_read(chr);
+     /* If there were any stray characters in the queue process them
+      * first
+      */
+     while (s->max_size > 0 && s->bufptr < s->bufcnt) {
+         qemu_chr_read(chr, &s->buf[s->bufptr], 1);
+         s->bufptr++;
+         s->max_size = qemu_chr_can_read(chr);
+     }
+     return s->max_size;
+ }
+ static void udp_chr_read(void *opaque)
+ {
+     CharDriverState *chr = opaque;
+     NetCharDriver *s = chr->opaque;
+     if (s->max_size == 0)
+         return;
+     s->bufcnt = recv(s->fd, s->buf, sizeof(s->buf), 0);
+     s->bufptr = s->bufcnt;
+     if (s->bufcnt <= 0)
+         return;
+     s->bufptr = 0;
+     while (s->max_size > 0 && s->bufptr < s->bufcnt) {
+         qemu_chr_read(chr, &s->buf[s->bufptr], 1);
+         s->bufptr++;
+         s->max_size = qemu_chr_can_read(chr);
+     }
+ }
+ static void udp_chr_update_read_handler(CharDriverState *chr)
+ {
+     NetCharDriver *s = chr->opaque;
+     if (s->fd >= 0) {
+         qemu_set_fd_handler2(s->fd, udp_chr_read_poll,
+                              udp_chr_read, NULL, chr);
+     }
+ }
+ static CharDriverState *qemu_chr_open_udp(const char *def)
+ {
+     CharDriverState *chr = NULL;
+     NetCharDriver *s = NULL;
+     int fd = -1;
+     struct sockaddr_in saddr;
+     chr = qemu_mallocz(sizeof(CharDriverState));
+     if (!chr)
+         goto return_err;
+     s = qemu_mallocz(sizeof(NetCharDriver));
+     if (!s)
+         goto return_err;
+     fd = socket(PF_INET, SOCK_DGRAM, 0);
+     if (fd < 0) {
+         perror("socket(PF_INET, SOCK_DGRAM)");
+         goto return_err;
+     }
+     if (parse_host_src_port(&s->daddr, &saddr, def) < 0) {
+         printf("Could not parse: %s\n", def);
+         goto return_err;
+     }
+     if (bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
+     {
+         perror("bind");
+         goto return_err;
+     }
+     s->fd = fd;
+     s->bufcnt = 0;
+     s->bufptr = 0;
+     chr->opaque = s;
+     chr->chr_write = udp_chr_write;
+     chr->chr_update_read_handler = udp_chr_update_read_handler;
+     return chr;
+ return_err:
+     if (chr)
+         free(chr);
+     if (s)
+         free(s);
+     if (fd >= 0)
+         closesocket(fd);
+     return NULL;
+ }
+ /***********************************************************/
+ /* TCP Net console */
+ typedef struct {
+     int fd, listen_fd;
+     int connected;
+     int max_size;
+     int do_telnetopt;
+     int do_nodelay;
+     int is_unix;
+ } TCPCharDriver;
+ static void tcp_chr_accept(void *opaque);
+ static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+ {
+     TCPCharDriver *s = chr->opaque;
+     if (s->connected) {
+         return send_all(s->fd, buf, len);
+     } else {
+         /* XXX: indicate an error ? */
+         return len;
+     }
+ }
+ static int tcp_chr_read_poll(void *opaque)
+ {
+     CharDriverState *chr = opaque;
+     TCPCharDriver *s = chr->opaque;
+     if (!s->connected)
+         return 0;
+     s->max_size = qemu_chr_can_read(chr);
+     return s->max_size;
+ }
+ #define IAC 255
+ #define IAC_BREAK 243
+ static void tcp_chr_process_IAC_bytes(CharDriverState *chr,
+                                       TCPCharDriver *s,
+                                       uint8_t *buf, int *size)
+ {
+     /* Handle any telnet client's basic IAC options to satisfy char by
+      * char mode with no echo.  All IAC options will be removed from
+      * the buf and the do_telnetopt variable will be used to track the
+      * state of the width of the IAC information.
+      *
+      * IAC commands come in sets of 3 bytes with the exception of the
+      * "IAC BREAK" command and the double IAC.
+      */
+     int i;
+     int j = 0;
+     for (i = 0; i < *size; i++) {
+         if (s->do_telnetopt > 1) {
+             if ((unsigned char)buf[i] == IAC && s->do_telnetopt == 2) {
+                 /* Double IAC means send an IAC */
+                 if (j != i)
+                     buf[j] = buf[i];
+                 j++;
+                 s->do_telnetopt = 1;
+             } else {
+                 if ((unsigned char)buf[i] == IAC_BREAK && s->do_telnetopt == 2) {
+                     /* Handle IAC break commands by sending a serial break */
+                     qemu_chr_event(chr, CHR_EVENT_BREAK);
+                     s->do_telnetopt++;
+                 }
+                 s->do_telnetopt++;
+             }
+             if (s->do_telnetopt >= 4) {
+                 s->do_telnetopt = 1;
+             }
+         } else {
+             if ((unsigned char)buf[i] == IAC) {
+                 s->do_telnetopt = 2;
+             } else {
+                 if (j != i)
+                     buf[j] = buf[i];
+                 j++;
+             }
+         }
+     }
+     *size = j;
+ }
+ static void tcp_chr_read(void *opaque)
+ {
+     CharDriverState *chr = opaque;
+     TCPCharDriver *s = chr->opaque;
+     uint8_t buf[1024];
+     int len, size;
+     if (!s->connected || s->max_size <= 0)
+         return;
+     len = sizeof(buf);
+     if (len > s->max_size)
+         len = s->max_size;
+     size = recv(s->fd, buf, len, 0);
+     if (size == 0) {
+         /* connection closed */
+         s->connected = 0;
+         if (s->listen_fd >= 0) {
+             qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr);
+         }
+         qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
+         closesocket(s->fd);
+         s->fd = -1;
+     } else if (size > 0) {
+         if (s->do_telnetopt)
+             tcp_chr_process_IAC_bytes(chr, s, buf, &size);
+         if (size > 0)
+             qemu_chr_read(chr, buf, size);
+     }
+ }
+ static void tcp_chr_connect(void *opaque)
+ {
+     CharDriverState *chr = opaque;
+     TCPCharDriver *s = chr->opaque;
+     s->connected = 1;
+     qemu_set_fd_handler2(s->fd, tcp_chr_read_poll,
+                          tcp_chr_read, NULL, chr);
+     qemu_chr_reset(chr);
+ }
+ #define IACSET(x,a,b,c) x[0] = a; x[1] = b; x[2] = c;
+ static void tcp_chr_telnet_init(int fd)
+ {
+     char buf[3];
+     /* Send the telnet negotion to put telnet in binary, no echo, single char mode */
+     IACSET(buf, 0xff, 0xfb, 0x01);  /* IAC WILL ECHO */
+     send(fd, (char *)buf, 3, 0);
+     IACSET(buf, 0xff, 0xfb, 0x03);  /* IAC WILL Suppress go ahead */
+     send(fd, (char *)buf, 3, 0);
+     IACSET(buf, 0xff, 0xfb, 0x00);  /* IAC WILL Binary */
+     send(fd, (char *)buf, 3, 0);
+     IACSET(buf, 0xff, 0xfd, 0x00);  /* IAC DO Binary */
+     send(fd, (char *)buf, 3, 0);
+ }
+ static void socket_set_nodelay(int fd)
+ {
+     int val = 1;
+     setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
+ }
+ static void tcp_chr_accept(void *opaque)
+ {
+     CharDriverState *chr = opaque;
+     TCPCharDriver *s = chr->opaque;
+     struct sockaddr_in saddr;
 -#ifndef _WIN32
++#ifndef NO_UNIX_SOCKETS
+     struct sockaddr_un uaddr;
+ #endif
+     struct sockaddr *addr;
+     socklen_t len;
+     int fd;
+     for(;;) {
++#ifndef NO_UNIX_SOCKETS
+       if (s->is_unix) {
+           len = sizeof(uaddr);
+           addr = (struct sockaddr *)&uaddr;
+       } else
+ #endif
+       {
+           len = sizeof(saddr);
+           addr = (struct sockaddr *)&saddr;
+       }
+         fd = accept(s->listen_fd, addr, &len);
+         if (fd < 0 && errno != EINTR) {
+             return;
+         } else if (fd >= 0) {
+             if (s->do_telnetopt)
+                 tcp_chr_telnet_init(fd);
+             break;
+         }
+     }
+     socket_set_nonblock(fd);
+     if (s->do_nodelay)
+         socket_set_nodelay(fd);
+     s->fd = fd;
+     qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL);
+     tcp_chr_connect(chr);
+ }
+ static void tcp_chr_close(CharDriverState *chr)
+ {
+     TCPCharDriver *s = chr->opaque;
+     if (s->fd >= 0)
+         closesocket(s->fd);
+     if (s->listen_fd >= 0)
+         closesocket(s->listen_fd);
+     qemu_free(s);
+ }
+ static CharDriverState *qemu_chr_open_tcp(const char *host_str,
+                                           int is_telnet,
+                                         int is_unix)
+ {
+     CharDriverState *chr = NULL;
+     TCPCharDriver *s = NULL;
+     int fd = -1, offset = 0;
+     int is_listen = 0;
+     int is_waitconnect = 1;
+     int do_nodelay = 0;
+     const char *ptr;
+     ptr = host_str;
+     while((ptr = strchr(ptr,','))) {
+         ptr++;
+         if (!strncmp(ptr,"server",6)) {
+             is_listen = 1;
+         } else if (!strncmp(ptr,"nowait",6)) {
+             is_waitconnect = 0;
+         } else if (!strncmp(ptr,"nodelay",6)) {
+             do_nodelay = 1;
+         } else if (!strncmp(ptr,"to=",3)) {
+             /* nothing, inet_listen() parses this one */;
+         } else {
+             printf("Unknown option: %s\n", ptr);
+             goto fail;
+         }
+     }
+     if (!is_listen)
+         is_waitconnect = 0;
+     chr = qemu_mallocz(sizeof(CharDriverState));
+     if (!chr)
+         goto fail;
+     s = qemu_mallocz(sizeof(TCPCharDriver));
+     if (!s)
+         goto fail;
+     if (is_listen) {
+         chr->filename = qemu_malloc(256);
+         if (is_unix) {
+             pstrcpy(chr->filename, 256, "unix:");
+         } else if (is_telnet) {
+             pstrcpy(chr->filename, 256, "telnet:");
+         } else {
+             pstrcpy(chr->filename, 256, "tcp:");
+         }
+         offset = strlen(chr->filename);
+     }
+     if (is_unix) {
+         if (is_listen) {
+             fd = unix_listen(host_str, chr->filename + offset, 256 - offset);
+         } else {
+             fd = unix_connect(host_str);
+         }
+     } else {
+         if (is_listen) {
+             fd = inet_listen(host_str, chr->filename + offset, 256 - offset,
+                              SOCK_STREAM, 0);
+         } else {
+             fd = inet_connect(host_str, SOCK_STREAM);
+         }
+     }
+     if (fd < 0)
+         goto fail;
+     if (!is_waitconnect)
+         socket_set_nonblock(fd);
+     s->connected = 0;
+     s->fd = -1;
+     s->listen_fd = -1;
+     s->is_unix = is_unix;
+     s->do_nodelay = do_nodelay && !is_unix;
+     chr->opaque = s;
+     chr->chr_write = tcp_chr_write;
+     chr->chr_close = tcp_chr_close;
+     if (is_listen) {
+         s->listen_fd = fd;
+         qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr);
+         if (is_telnet)
+             s->do_telnetopt = 1;
+     } else {
+         s->connected = 1;
+         s->fd = fd;
+         socket_set_nodelay(fd);
+         tcp_chr_connect(chr);
+     }
+     if (is_listen && is_waitconnect) {
+         printf("QEMU waiting for connection on: %s\n",
+                chr->filename ? chr->filename : host_str);
+         tcp_chr_accept(chr);
+         socket_set_nonblock(s->listen_fd);
+     }
+     return chr;
+  fail:
+     if (fd >= 0)
+         closesocket(fd);
+     qemu_free(s);
+     qemu_free(chr);
+     return NULL;
+ }
+ static TAILQ_HEAD(CharDriverStateHead, CharDriverState) chardevs
+ = TAILQ_HEAD_INITIALIZER(chardevs);
+ CharDriverState *qemu_chr_open(const char *label, const char *filename)
+ {
+     const char *p;
+     CharDriverState *chr;
+     if (!strcmp(filename, "vc")) {
+         chr = text_console_init(&display_state, 0);
+     } else
+     if (strstart(filename, "vc:", &p)) {
+         chr = text_console_init(&display_state, p);
+     } else
+     if (!strcmp(filename, "null")) {
+         chr = qemu_chr_open_null();
+     } else
+     if (strstart(filename, "tcp:", &p)) {
+         chr = qemu_chr_open_tcp(p, 0, 0);
+     } else
+     if (strstart(filename, "telnet:", &p)) {
+         chr = qemu_chr_open_tcp(p, 1, 0);
+     } else
+     if (strstart(filename, "udp:", &p)) {
+         chr = qemu_chr_open_udp(p);
+     } else
+     if (strstart(filename, "mon:", &p)) {
+         chr = qemu_chr_open(label, p);
+         if (chr) {
+             chr = qemu_chr_open_mux(chr);
+             monitor_init(chr, !nographic);
+         } else {
+             printf("Unable to open driver: %s\n", p);
+         }
+     } else
+ #ifndef _WIN32
+     if (strstart(filename, "unix:", &p)) {
+       chr = qemu_chr_open_tcp(p, 0, 1);
+     } else if (strstart(filename, "file:", &p)) {
+         chr = qemu_chr_open_file_out(p);
+     } else if (strstart(filename, "pipe:", &p)) {
+         chr = qemu_chr_open_pipe(p);
+     } else if (!strcmp(filename, "pty")) {
+         chr = qemu_chr_open_pty();
+     } else if (!strcmp(filename, "stdio")) {
+         chr = qemu_chr_open_stdio();
+     } else
+ #if defined(__linux__)
+     if (strstart(filename, "/dev/parport", NULL)) {
+         chr = qemu_chr_open_pp(filename);
+     } else
+ #elif defined(__FreeBSD__)
+     if (strstart(filename, "/dev/ppi", NULL)) {
+         chr = qemu_chr_open_pp(filename);
+     } else
+ #endif
+ #if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \
+     || defined(__NetBSD__) || defined(__OpenBSD__)
+     if (strstart(filename, "/dev/", NULL)) {
+         chr = qemu_chr_open_tty(filename);
+     } else
+ #endif
+ #else /* !_WIN32 */
+     if (strstart(filename, "COM", NULL)) {
+         chr = qemu_chr_open_win(filename);
+     } else
+     if (strstart(filename, "pipe:", &p)) {
+         chr = qemu_chr_open_win_pipe(p);
+     } else
+     if (strstart(filename, "con:", NULL)) {
+         chr = qemu_chr_open_win_con(filename);
+     } else
+     if (strstart(filename, "file:", &p)) {
+         chr = qemu_chr_open_win_file_out(p);
+     } else
+ #endif
+ #ifdef CONFIG_BRLAPI
+     if (!strcmp(filename, "braille")) {
+         chr = chr_baum_init();
+     } else
+ #endif
+     {
+         chr = NULL;
+     }
+     if (chr) {
+         if (!chr->filename)
+             chr->filename = qemu_strdup(filename);
+         chr->label = qemu_strdup(label);
+         TAILQ_INSERT_TAIL(&chardevs, chr, next);
+     }
+     return chr;
+ }
+ void qemu_chr_close(CharDriverState *chr)
+ {
+     TAILQ_REMOVE(&chardevs, chr, next);
+     if (chr->chr_close)
+         chr->chr_close(chr);
+     qemu_free(chr->filename);
+     qemu_free(chr->label);
+     qemu_free(chr);
+ }
+ void qemu_chr_info(void)
+ {
+     CharDriverState *chr;
+     TAILQ_FOREACH(chr, &chardevs, next) {
+         term_printf("%s: filename=%s\n", chr->label, chr->filename);
+     }
+ }
diff --cc qemu-char.h
Simple merge
diff --cc qemu-common.h
Simple merge
diff --cc qemu-lock.h
Simple merge
diff --cc savevm.c
index 0000000000000000000000000000000000000000,729e84977feeeb77b3a82477706f5f62ec198011..3dc887d2c2dd392a06bce3e8aa05163586c73cad
mode 000000,100644..100644
--- /dev/null
+++ b/savevm.c
@@@ -1,0 -1,1254 +1,1258 @@@
+ /*
+  * QEMU System Emulator
+  *
+  * Copyright (c) 2003-2008 Fabrice Bellard
+  *
+  * Permission is hereby granted, free of charge, to any person obtaining a copy
+  * of this software and associated documentation files (the "Software"), to deal
+  * in the Software without restriction, including without limitation the rights
+  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  * copies of the Software, and to permit persons to whom the Software is
+  * furnished to do so, subject to the following conditions:
+  *
+  * The above copyright notice and this permission notice shall be included in
+  * all copies or substantial portions of the Software.
+  *
+  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+  * THE SOFTWARE.
+  */
+ #include "qemu-common.h"
+ #include "hw/hw.h"
+ #include "net.h"
+ #include "console.h"
+ #include "sysemu.h"
+ #include "qemu-timer.h"
+ #include "qemu-char.h"
+ #include "block.h"
+ #include "audio/audio.h"
+ #include "migration.h"
+ #include "qemu_socket.h"
+ #include <unistd.h>
+ #include <fcntl.h>
+ #include <signal.h>
+ #include <time.h>
+ #include <errno.h>
+ #include <sys/time.h>
+ #include <zlib.h>
+ #ifndef _WIN32
+ #include <sys/times.h>
+ #include <sys/wait.h>
+ #include <termios.h>
+ #include <sys/mman.h>
+ #include <sys/ioctl.h>
+ #include <sys/resource.h>
+ #include <sys/socket.h>
+ #include <netinet/in.h>
+ #include <net/if.h>
+ #if defined(__NetBSD__)
+ #include <net/if_tap.h>
+ #endif
+ #ifdef __linux__
+ #include <linux/if_tun.h>
+ #endif
+ #include <arpa/inet.h>
+ #include <dirent.h>
+ #include <netdb.h>
+ #include <sys/select.h>
+ #ifdef _BSD
+ #include <sys/stat.h>
+ #ifdef __FreeBSD__
+ #include <libutil.h>
+ #else
+ #include <util.h>
+ #endif
+ #elif defined (__GLIBC__) && defined (__FreeBSD_kernel__)
+ #include <freebsd/stdlib.h>
+ #else
+ #ifdef __linux__
+ #include <pty.h>
+ #include <malloc.h>
+ #include <linux/rtc.h>
+ #endif
+ #endif
+ #endif
+ #ifdef _WIN32
+ #include <malloc.h>
+ #include <sys/timeb.h>
+ #include <mmsystem.h>
+ #define getopt_long_only getopt_long
+ #define memalign(align, size) malloc(size)
+ #endif
+ /* point to the block driver where the snapshots are managed */
+ static BlockDriverState *bs_snapshots;
+ #define SELF_ANNOUNCE_ROUNDS 5
+ #define ETH_P_EXPERIMENTAL 0x01F1 /* just a number */
+ //#define ETH_P_EXPERIMENTAL 0x0012 /* make it the size of the packet */
+ #define EXPERIMENTAL_MAGIC 0xf1f23f4f
+ static int announce_self_create(uint8_t *buf, 
+                               uint8_t *mac_addr)
+ {
+     uint32_t magic = EXPERIMENTAL_MAGIC;
+     uint16_t proto = htons(ETH_P_EXPERIMENTAL);
+     /* FIXME: should we send a different packet (arp/rarp/ping)? */
+     memset(buf, 0xff, 6);         /* h_dst */
+     memcpy(buf + 6, mac_addr, 6); /* h_src */
+     memcpy(buf + 12, &proto, 2);  /* h_proto */
+     memcpy(buf + 14, &magic, 4);  /* magic */
+     return 18; /* len */
+ }
+ void qemu_announce_self(void)
+ {
+     int i, j, len;
+     VLANState *vlan;
+     VLANClientState *vc;
+     uint8_t buf[256];
+     for (i = 0; i < nb_nics; i++) {
+         len = announce_self_create(buf, nd_table[i].macaddr);
+         vlan = nd_table[i].vlan;
+         for(vc = vlan->first_client; vc != NULL; vc = vc->next) {
+             for (j=0; j < SELF_ANNOUNCE_ROUNDS; j++)
+                 vc->fd_read(vc->opaque, buf, len);
+         }
+     }
+ }
+ /***********************************************************/
+ /* savevm/loadvm support */
+ #define IO_BUF_SIZE 32768
+ struct QEMUFile {
+     QEMUFilePutBufferFunc *put_buffer;
+     QEMUFileGetBufferFunc *get_buffer;
+     QEMUFileCloseFunc *close;
+     QEMUFileRateLimit *rate_limit;
+     void *opaque;
+     int is_write;
+     int64_t buf_offset; /* start of buffer when writing, end of buffer
+                            when reading */
+     int buf_index;
+     int buf_size; /* 0 when writing */
+     uint8_t buf[IO_BUF_SIZE];
+     int has_error;
+ };
+ typedef struct QEMUFilePopen
+ {
+     FILE *popen_file;
+     QEMUFile *file;
+ } QEMUFilePopen;
+ typedef struct QEMUFileSocket
+ {
+     int fd;
+     QEMUFile *file;
+ } QEMUFileSocket;
+ static int socket_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
+ {
+     QEMUFileSocket *s = opaque;
+     ssize_t len;
+     do {
+         len = recv(s->fd, buf, size, 0);
+     } while (len == -1 && socket_error() == EINTR);
+     if (len == -1)
+         len = -socket_error();
+     return len;
+ }
+ static int socket_close(void *opaque)
+ {
+     QEMUFileSocket *s = opaque;
+     qemu_free(s);
+     return 0;
+ }
+ static int popen_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, int size)
+ {
+     QEMUFilePopen *s = opaque;
+     return fwrite(buf, 1, size, s->popen_file);
+ }
+ static int popen_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
+ {
+     QEMUFilePopen *s = opaque;
+     return fread(buf, 1, size, s->popen_file);
+ }
+ static int popen_close(void *opaque)
+ {
+     QEMUFilePopen *s = opaque;
+     pclose(s->popen_file);
+     qemu_free(s);
+     return 0;
+ }
+ QEMUFile *qemu_popen(FILE *popen_file, const char *mode)
+ {
+     QEMUFilePopen *s;
+     if (popen_file == NULL || mode == NULL || (mode[0] != 'r' && mode[0] != 'w') || mode[1] != 0) {
+         fprintf(stderr, "qemu_popen: Argument validity check failed\n");
+         return NULL;
+     }
+     s = qemu_mallocz(sizeof(QEMUFilePopen));
+     if (!s) {
+         fprintf(stderr, "qemu_popen: malloc failed\n");
+         return NULL;
+     }
+     s->popen_file = popen_file;
+     if(mode[0] == 'r') {
+         s->file = qemu_fopen_ops(s, NULL, popen_get_buffer, popen_close, NULL);
+     } else {
+         s->file = qemu_fopen_ops(s, popen_put_buffer, NULL, popen_close, NULL);
+     }
+     fprintf(stderr, "qemu_popen: returning result of qemu_fopen_ops\n");
+     return s->file;
+ }
+ QEMUFile *qemu_popen_cmd(const char *command, const char *mode)
+ {
+     FILE *popen_file;
+     popen_file = popen(command, mode);
+     if(popen_file == NULL) {
+         return NULL;
+     }
+     return qemu_popen(popen_file, mode);
+ }
+ QEMUFile *qemu_fopen_socket(int fd)
+ {
+     QEMUFileSocket *s = qemu_mallocz(sizeof(QEMUFileSocket));
+     if (s == NULL)
+         return NULL;
+     s->fd = fd;
+     s->file = qemu_fopen_ops(s, NULL, socket_get_buffer, socket_close, NULL);
+     return s->file;
+ }
+ typedef struct QEMUFileStdio
+ {
+     FILE *outfile;
+ } QEMUFileStdio;
+ static int file_put_buffer(void *opaque, const uint8_t *buf,
+                             int64_t pos, int size)
+ {
+     QEMUFileStdio *s = opaque;
+     fseek(s->outfile, pos, SEEK_SET);
+     fwrite(buf, 1, size, s->outfile);
+     return size;
+ }
+ static int file_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
+ {
+     QEMUFileStdio *s = opaque;
+     fseek(s->outfile, pos, SEEK_SET);
+     return fread(buf, 1, size, s->outfile);
+ }
+ static int file_close(void *opaque)
+ {
+     QEMUFileStdio *s = opaque;
+     fclose(s->outfile);
+     qemu_free(s);
+     return 0;
+ }
+ QEMUFile *qemu_fopen(const char *filename, const char *mode)
+ {
+     QEMUFileStdio *s;
+     s = qemu_mallocz(sizeof(QEMUFileStdio));
+     if (!s)
+         return NULL;
+     s->outfile = fopen(filename, mode);
+     if (!s->outfile)
+         goto fail;
+     if (!strcmp(mode, "wb"))
+         return qemu_fopen_ops(s, file_put_buffer, NULL, file_close, NULL);
+     else if (!strcmp(mode, "rb"))
+         return qemu_fopen_ops(s, NULL, file_get_buffer, file_close, NULL);
+ fail:
+     if (s->outfile)
+         fclose(s->outfile);
+     qemu_free(s);
+     return NULL;
+ }
+ typedef struct QEMUFileBdrv
+ {
+     BlockDriverState *bs;
+     int64_t base_offset;
+ } QEMUFileBdrv;
+ static int bdrv_put_buffer(void *opaque, const uint8_t *buf,
+                            int64_t pos, int size)
+ {
+     QEMUFileBdrv *s = opaque;
+     bdrv_pwrite(s->bs, s->base_offset + pos, buf, size);
+     return size;
+ }
+ static int bdrv_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
+ {
+     QEMUFileBdrv *s = opaque;
+     return bdrv_pread(s->bs, s->base_offset + pos, buf, size);
+ }
+ static int bdrv_fclose(void *opaque)
+ {
+     QEMUFileBdrv *s = opaque;
+     qemu_free(s);
+     return 0;
+ }
+ static QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int64_t offset, int is_writable)
+ {
+     QEMUFileBdrv *s;
+     s = qemu_mallocz(sizeof(QEMUFileBdrv));
+     if (!s)
+         return NULL;
+     s->bs = bs;
+     s->base_offset = offset;
+     if (is_writable)
+         return qemu_fopen_ops(s, bdrv_put_buffer, NULL, bdrv_fclose, NULL);
+     return qemu_fopen_ops(s, NULL, bdrv_get_buffer, bdrv_fclose, NULL);
+ }
+ QEMUFile *qemu_fopen_ops(void *opaque, QEMUFilePutBufferFunc *put_buffer,
+                          QEMUFileGetBufferFunc *get_buffer,
+                          QEMUFileCloseFunc *close,
+                          QEMUFileRateLimit *rate_limit)
+ {
+     QEMUFile *f;
+     f = qemu_mallocz(sizeof(QEMUFile));
+     if (!f)
+         return NULL;
+     f->opaque = opaque;
+     f->put_buffer = put_buffer;
+     f->get_buffer = get_buffer;
+     f->close = close;
+     f->rate_limit = rate_limit;
+     f->is_write = 0;
+     return f;
+ }
+ int qemu_file_has_error(QEMUFile *f)
+ {
+     return f->has_error;
+ }
+ void qemu_fflush(QEMUFile *f)
+ {
+     if (!f->put_buffer)
+         return;
+     if (f->is_write && f->buf_index > 0) {
+         int len;
+         len = f->put_buffer(f->opaque, f->buf, f->buf_offset, f->buf_index);
+         if (len > 0)
+             f->buf_offset += f->buf_index;
+         else
+             f->has_error = 1;
+         f->buf_index = 0;
+     }
+ }
+ static void qemu_fill_buffer(QEMUFile *f)
+ {
+     int len;
+     if (!f->get_buffer)
+         return;
+     if (f->is_write)
+         abort();
+     len = f->get_buffer(f->opaque, f->buf, f->buf_offset, IO_BUF_SIZE);
+     if (len > 0) {
+         f->buf_index = 0;
+         f->buf_size = len;
+         f->buf_offset += len;
+     } else if (len != -EAGAIN)
+         f->has_error = 1;
+ }
+ int qemu_fclose(QEMUFile *f)
+ {
+     int ret = 0;
+     qemu_fflush(f);
+     if (f->close)
+         ret = f->close(f->opaque);
+     qemu_free(f);
+     return ret;
+ }
+ void qemu_file_put_notify(QEMUFile *f)
+ {
+     f->put_buffer(f->opaque, NULL, 0, 0);
+ }
+ void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size)
+ {
+     int l;
+     if (!f->has_error && f->is_write == 0 && f->buf_index > 0) {
+         fprintf(stderr,
+                 "Attempted to write to buffer while read buffer is not empty\n");
+         abort();
+     }
+     while (!f->has_error && size > 0) {
+         l = IO_BUF_SIZE - f->buf_index;
+         if (l > size)
+             l = size;
+         memcpy(f->buf + f->buf_index, buf, l);
+         f->is_write = 1;
+         f->buf_index += l;
+         buf += l;
+         size -= l;
+         if (f->buf_index >= IO_BUF_SIZE)
+             qemu_fflush(f);
+     }
+ }
+ void qemu_put_byte(QEMUFile *f, int v)
+ {
+     if (!f->has_error && f->is_write == 0 && f->buf_index > 0) {
+         fprintf(stderr,
+                 "Attempted to write to buffer while read buffer is not empty\n");
+         abort();
+     }
+     f->buf[f->buf_index++] = v;
+     f->is_write = 1;
+     if (f->buf_index >= IO_BUF_SIZE)
+         qemu_fflush(f);
+ }
+ int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size1)
+ {
+     int size, l;
+     if (f->is_write)
+         abort();
+     size = size1;
+     while (size > 0) {
+         l = f->buf_size - f->buf_index;
+         if (l == 0) {
+             qemu_fill_buffer(f);
+             l = f->buf_size - f->buf_index;
+             if (l == 0)
+                 break;
+         }
+         if (l > size)
+             l = size;
+         memcpy(buf, f->buf + f->buf_index, l);
+         f->buf_index += l;
+         buf += l;
+         size -= l;
+     }
+     return size1 - size;
+ }
+ int qemu_get_byte(QEMUFile *f)
+ {
+     if (f->is_write)
+         abort();
+     if (f->buf_index >= f->buf_size) {
+         qemu_fill_buffer(f);
+         if (f->buf_index >= f->buf_size)
+             return 0;
+     }
+     return f->buf[f->buf_index++];
+ }
+ int64_t qemu_ftell(QEMUFile *f)
+ {
+     return f->buf_offset - f->buf_size + f->buf_index;
+ }
+ int64_t qemu_fseek(QEMUFile *f, int64_t pos, int whence)
+ {
+     if (whence == SEEK_SET) {
+         /* nothing to do */
+     } else if (whence == SEEK_CUR) {
+         pos += qemu_ftell(f);
+     } else {
+         /* SEEK_END not supported */
+         return -1;
+     }
+     if (f->put_buffer) {
+         qemu_fflush(f);
+         f->buf_offset = pos;
+     } else {
+         f->buf_offset = pos;
+         f->buf_index = 0;
+         f->buf_size = 0;
+     }
+     return pos;
+ }
+ int qemu_file_rate_limit(QEMUFile *f)
+ {
+     if (f->rate_limit)
+         return f->rate_limit(f->opaque);
+     return 0;
+ }
+ void qemu_put_be16(QEMUFile *f, unsigned int v)
+ {
+     qemu_put_byte(f, v >> 8);
+     qemu_put_byte(f, v);
+ }
+ void qemu_put_be32(QEMUFile *f, unsigned int v)
+ {
+     qemu_put_byte(f, v >> 24);
+     qemu_put_byte(f, v >> 16);
+     qemu_put_byte(f, v >> 8);
+     qemu_put_byte(f, v);
+ }
+ void qemu_put_be64(QEMUFile *f, uint64_t v)
+ {
+     qemu_put_be32(f, v >> 32);
+     qemu_put_be32(f, v);
+ }
+ unsigned int qemu_get_be16(QEMUFile *f)
+ {
+     unsigned int v;
+     v = qemu_get_byte(f) << 8;
+     v |= qemu_get_byte(f);
+     return v;
+ }
+ unsigned int qemu_get_be32(QEMUFile *f)
+ {
+     unsigned int v;
+     v = qemu_get_byte(f) << 24;
+     v |= qemu_get_byte(f) << 16;
+     v |= qemu_get_byte(f) << 8;
+     v |= qemu_get_byte(f);
+     return v;
+ }
+ uint64_t qemu_get_be64(QEMUFile *f)
+ {
+     uint64_t v;
+     v = (uint64_t)qemu_get_be32(f) << 32;
+     v |= qemu_get_be32(f);
+     return v;
+ }
+ typedef struct SaveStateEntry {
+     char idstr[256];
+     int instance_id;
+     int version_id;
+     int section_id;
+     SaveLiveStateHandler *save_live_state;
+     SaveStateHandler *save_state;
+     LoadStateHandler *load_state;
+     void *opaque;
+     struct SaveStateEntry *next;
+ } SaveStateEntry;
+ static SaveStateEntry *first_se;
+ /* TODO: Individual devices generally have very little idea about the rest
+    of the system, so instance_id should be removed/replaced.
+    Meanwhile pass -1 as instance_id if you do not already have a clearly
+    distinguishing id for all instances of your device class. */
+ int register_savevm_live(const char *idstr,
+                          int instance_id,
+                          int version_id,
+                          SaveLiveStateHandler *save_live_state,
+                          SaveStateHandler *save_state,
+                          LoadStateHandler *load_state,
+                          void *opaque)
+ {
+     SaveStateEntry *se, **pse;
+     static int global_section_id;
+     se = qemu_malloc(sizeof(SaveStateEntry));
+     if (!se)
+         return -1;
+     pstrcpy(se->idstr, sizeof(se->idstr), idstr);
+     se->instance_id = (instance_id == -1) ? 0 : instance_id;
+     se->version_id = version_id;
+     se->section_id = global_section_id++;
+     se->save_live_state = save_live_state;
+     se->save_state = save_state;
+     se->load_state = load_state;
+     se->opaque = opaque;
+     se->next = NULL;
+     /* add at the end of list */
+     pse = &first_se;
+     while (*pse != NULL) {
+         if (instance_id == -1
+                 && strcmp(se->idstr, (*pse)->idstr) == 0
+                 && se->instance_id <= (*pse)->instance_id)
+             se->instance_id = (*pse)->instance_id + 1;
+         pse = &(*pse)->next;
+     }
+     *pse = se;
+     return 0;
+ }
+ int register_savevm(const char *idstr,
+                     int instance_id,
+                     int version_id,
+                     SaveStateHandler *save_state,
+                     LoadStateHandler *load_state,
+                     void *opaque)
+ {
+     return register_savevm_live(idstr, instance_id, version_id,
+                                 NULL, save_state, load_state, opaque);
+ }
+ #define QEMU_VM_FILE_MAGIC           0x5145564d
+ #define QEMU_VM_FILE_VERSION_COMPAT  0x00000002
+ #define QEMU_VM_FILE_VERSION         0x00000003
+ #define QEMU_VM_EOF                  0x00
+ #define QEMU_VM_SECTION_START        0x01
+ #define QEMU_VM_SECTION_PART         0x02
+ #define QEMU_VM_SECTION_END          0x03
+ #define QEMU_VM_SECTION_FULL         0x04
+ int qemu_savevm_state_begin(QEMUFile *f)
+ {
+     SaveStateEntry *se;
+     qemu_put_be32(f, QEMU_VM_FILE_MAGIC);
+     qemu_put_be32(f, QEMU_VM_FILE_VERSION);
+     for (se = first_se; se != NULL; se = se->next) {
+         int len;
+         if (se->save_live_state == NULL)
+             continue;
+         /* Section type */
+         qemu_put_byte(f, QEMU_VM_SECTION_START);
+         qemu_put_be32(f, se->section_id);
+         /* ID string */
+         len = strlen(se->idstr);
+         qemu_put_byte(f, len);
+         qemu_put_buffer(f, (uint8_t *)se->idstr, len);
+         qemu_put_be32(f, se->instance_id);
+         qemu_put_be32(f, se->version_id);
+         se->save_live_state(f, QEMU_VM_SECTION_START, se->opaque);
+     }
+     if (qemu_file_has_error(f))
+         return -EIO;
+     return 0;
+ }
+ int qemu_savevm_state_iterate(QEMUFile *f)
+ {
+     SaveStateEntry *se;
+     int ret = 1;
+     for (se = first_se; se != NULL; se = se->next) {
+         if (se->save_live_state == NULL)
+             continue;
+         /* Section type */
+         qemu_put_byte(f, QEMU_VM_SECTION_PART);
+         qemu_put_be32(f, se->section_id);
+         ret &= !!se->save_live_state(f, QEMU_VM_SECTION_PART, se->opaque);
+     }
+     if (ret)
+         return 1;
+     if (qemu_file_has_error(f))
+         return -EIO;
+     return 0;
+ }
+ int qemu_savevm_state_complete(QEMUFile *f)
+ {
+     SaveStateEntry *se;
+     for (se = first_se; se != NULL; se = se->next) {
+         if (se->save_live_state == NULL)
+             continue;
+         /* Section type */
+         qemu_put_byte(f, QEMU_VM_SECTION_END);
+         qemu_put_be32(f, se->section_id);
+         se->save_live_state(f, QEMU_VM_SECTION_END, se->opaque);
+     }
+     for(se = first_se; se != NULL; se = se->next) {
+         int len;
+       if (se->save_state == NULL)
+           continue;
+         /* Section type */
+         qemu_put_byte(f, QEMU_VM_SECTION_FULL);
+         qemu_put_be32(f, se->section_id);
+         /* ID string */
+         len = strlen(se->idstr);
+         qemu_put_byte(f, len);
+         qemu_put_buffer(f, (uint8_t *)se->idstr, len);
+         qemu_put_be32(f, se->instance_id);
+         qemu_put_be32(f, se->version_id);
+         se->save_state(f, se->opaque);
+     }
+     qemu_put_byte(f, QEMU_VM_EOF);
+     if (qemu_file_has_error(f))
+         return -EIO;
+     return 0;
+ }
+ int qemu_savevm_state(QEMUFile *f)
+ {
+     int saved_vm_running;
+     int ret;
+     saved_vm_running = vm_running;
+     vm_stop(0);
+     bdrv_flush_all();
+     ret = qemu_savevm_state_begin(f);
+     if (ret < 0)
+         goto out;
+     do {
+         ret = qemu_savevm_state_iterate(f);
+         if (ret < 0)
+             goto out;
+     } while (ret == 0);
+     ret = qemu_savevm_state_complete(f);
+ out:
+     if (qemu_file_has_error(f))
+         ret = -EIO;
+     if (!ret && saved_vm_running)
+         vm_start();
+     return ret;
+ }
+ static SaveStateEntry *find_se(const char *idstr, int instance_id)
+ {
+     SaveStateEntry *se;
+     for(se = first_se; se != NULL; se = se->next) {
+         if (!strcmp(se->idstr, idstr) &&
+             instance_id == se->instance_id)
+             return se;
+     }
+     return NULL;
+ }
+ typedef struct LoadStateEntry {
+     SaveStateEntry *se;
+     int section_id;
+     int version_id;
+     struct LoadStateEntry *next;
+ } LoadStateEntry;
+ static int qemu_loadvm_state_v2(QEMUFile *f)
+ {
+     SaveStateEntry *se;
+     int len, ret, instance_id, record_len, version_id;
+     int64_t total_len, end_pos, cur_pos;
+     char idstr[256];
+     total_len = qemu_get_be64(f);
+     end_pos = total_len + qemu_ftell(f);
+     for(;;) {
+         if (qemu_ftell(f) >= end_pos)
+             break;
+         len = qemu_get_byte(f);
+         qemu_get_buffer(f, (uint8_t *)idstr, len);
+         idstr[len] = '\0';
+         instance_id = qemu_get_be32(f);
+         version_id = qemu_get_be32(f);
+         record_len = qemu_get_be32(f);
+         cur_pos = qemu_ftell(f);
+         se = find_se(idstr, instance_id);
+         if (!se) {
+             fprintf(stderr, "qemu: warning: instance 0x%x of device '%s' not present in current VM\n",
+                     instance_id, idstr);
+         } else {
+             ret = se->load_state(f, se->opaque, version_id);
+             if (ret < 0) {
+                 fprintf(stderr, "qemu: warning: error while loading state for instance 0x%x of device '%s'\n",
+                         instance_id, idstr);
+             }
+         }
+         /* always seek to exact end of record */
+         qemu_fseek(f, cur_pos + record_len, SEEK_SET);
+     }
+     if (qemu_file_has_error(f))
+         return -EIO;
+     return 0;
+ }
+ int qemu_loadvm_state(QEMUFile *f)
+ {
+     LoadStateEntry *first_le = NULL;
+     uint8_t section_type;
+     unsigned int v;
+     int ret;
+     v = qemu_get_be32(f);
+     if (v != QEMU_VM_FILE_MAGIC)
+         return -EINVAL;
+     v = qemu_get_be32(f);
+     if (v == QEMU_VM_FILE_VERSION_COMPAT)
+         return qemu_loadvm_state_v2(f);
+     if (v != QEMU_VM_FILE_VERSION)
+         return -ENOTSUP;
+     while ((section_type = qemu_get_byte(f)) != QEMU_VM_EOF) {
+         uint32_t instance_id, version_id, section_id;
+         LoadStateEntry *le;
+         SaveStateEntry *se;
+         char idstr[257];
+         int len;
+         switch (section_type) {
+         case QEMU_VM_SECTION_START:
+         case QEMU_VM_SECTION_FULL:
+             /* Read section start */
+             section_id = qemu_get_be32(f);
+             len = qemu_get_byte(f);
+             qemu_get_buffer(f, (uint8_t *)idstr, len);
+             idstr[len] = 0;
+             instance_id = qemu_get_be32(f);
+             version_id = qemu_get_be32(f);
+             /* Find savevm section */
+             se = find_se(idstr, instance_id);
+             if (se == NULL) {
+                 fprintf(stderr, "Unknown savevm section or instance '%s' %d\n", idstr, instance_id);
+                 ret = -EINVAL;
+                 goto out;
+             }
+             /* Validate version */
+             if (version_id > se->version_id) {
+                 fprintf(stderr, "savevm: unsupported version %d for '%s' v%d\n",
+                         version_id, idstr, se->version_id);
+                 ret = -EINVAL;
+                 goto out;
+             }
+             /* Add entry */
+             le = qemu_mallocz(sizeof(*le));
+             if (le == NULL) {
+                 ret = -ENOMEM;
+                 goto out;
+             }
+             le->se = se;
+             le->section_id = section_id;
+             le->version_id = version_id;
+             le->next = first_le;
+             first_le = le;
+             le->se->load_state(f, le->se->opaque, le->version_id);
+             break;
+         case QEMU_VM_SECTION_PART:
+         case QEMU_VM_SECTION_END:
+             section_id = qemu_get_be32(f);
+             for (le = first_le; le && le->section_id != section_id; le = le->next);
+             if (le == NULL) {
+                 fprintf(stderr, "Unknown savevm section %d\n", section_id);
+                 ret = -EINVAL;
+                 goto out;
+             }
+             le->se->load_state(f, le->se->opaque, le->version_id);
+             break;
+         default:
+             fprintf(stderr, "Unknown savevm section type %d\n", section_type);
+             ret = -EINVAL;
+             goto out;
+         }
+     }
+     ret = 0;
+ out:
+     while (first_le) {
+         LoadStateEntry *le = first_le;
+         first_le = first_le->next;
+         qemu_free(le);
+     }
+     if (qemu_file_has_error(f))
+         ret = -EIO;
+     return ret;
+ }
+ /* device can contain snapshots */
+ static int bdrv_can_snapshot(BlockDriverState *bs)
+ {
+     return (bs &&
+             !bdrv_is_removable(bs) &&
+             !bdrv_is_read_only(bs));
+ }
+ /* device must be snapshots in order to have a reliable snapshot */
+ static int bdrv_has_snapshot(BlockDriverState *bs)
+ {
+     return (bs &&
+             !bdrv_is_removable(bs) &&
+             !bdrv_is_read_only(bs));
+ }
+ static BlockDriverState *get_bs_snapshots(void)
+ {
+     BlockDriverState *bs;
+     int i;
+     if (bs_snapshots)
+         return bs_snapshots;
+     for(i = 0; i <= nb_drives; i++) {
+         bs = drives_table[i].bdrv;
+         if (bdrv_can_snapshot(bs))
+             goto ok;
+     }
+     return NULL;
+  ok:
+     bs_snapshots = bs;
+     return bs;
+ }
+ static int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,
+                               const char *name)
+ {
+     QEMUSnapshotInfo *sn_tab, *sn;
+     int nb_sns, i, ret;
+     ret = -ENOENT;
+     nb_sns = bdrv_snapshot_list(bs, &sn_tab);
+     if (nb_sns < 0)
+         return ret;
+     for(i = 0; i < nb_sns; i++) {
+         sn = &sn_tab[i];
+         if (!strcmp(sn->id_str, name) || !strcmp(sn->name, name)) {
+             *sn_info = *sn;
+             ret = 0;
+             break;
+         }
+     }
+     qemu_free(sn_tab);
+     return ret;
+ }
++#ifndef CONFIG_DM
++
+ void do_savevm(const char *name)
+ {
+     BlockDriverState *bs, *bs1;
+     QEMUSnapshotInfo sn1, *sn = &sn1, old_sn1, *old_sn = &old_sn1;
+     int must_delete, ret, i;
+     BlockDriverInfo bdi1, *bdi = &bdi1;
+     QEMUFile *f;
+     int saved_vm_running;
+     uint32_t vm_state_size;
+ #ifdef _WIN32
+     struct _timeb tb;
+ #else
+     struct timeval tv;
+ #endif
+     bs = get_bs_snapshots();
+     if (!bs) {
+         term_printf("No block device can accept snapshots\n");
+         return;
+     }
+     /* ??? Should this occur after vm_stop?  */
+     qemu_aio_flush();
+     saved_vm_running = vm_running;
+     vm_stop(0);
+     must_delete = 0;
+     if (name) {
+         ret = bdrv_snapshot_find(bs, old_sn, name);
+         if (ret >= 0) {
+             must_delete = 1;
+         }
+     }
+     memset(sn, 0, sizeof(*sn));
+     if (must_delete) {
+         pstrcpy(sn->name, sizeof(sn->name), old_sn->name);
+         pstrcpy(sn->id_str, sizeof(sn->id_str), old_sn->id_str);
+     } else {
+         if (name)
+             pstrcpy(sn->name, sizeof(sn->name), name);
+     }
+     /* fill auxiliary fields */
+ #ifdef _WIN32
+     _ftime(&tb);
+     sn->date_sec = tb.time;
+     sn->date_nsec = tb.millitm * 1000000;
+ #else
+     gettimeofday(&tv, NULL);
+     sn->date_sec = tv.tv_sec;
+     sn->date_nsec = tv.tv_usec * 1000;
+ #endif
+     sn->vm_clock_nsec = qemu_get_clock(vm_clock);
+     if (bdrv_get_info(bs, bdi) < 0 || bdi->vm_state_offset <= 0) {
+         term_printf("Device %s does not support VM state snapshots\n",
+                     bdrv_get_device_name(bs));
+         goto the_end;
+     }
+     /* save the VM state */
+     f = qemu_fopen_bdrv(bs, bdi->vm_state_offset, 1);
+     if (!f) {
+         term_printf("Could not open VM state file\n");
+         goto the_end;
+     }
+     ret = qemu_savevm_state(f);
+     vm_state_size = qemu_ftell(f);
+     qemu_fclose(f);
+     if (ret < 0) {
+         term_printf("Error %d while writing VM\n", ret);
+         goto the_end;
+     }
+     /* create the snapshots */
+     for(i = 0; i < nb_drives; i++) {
+         bs1 = drives_table[i].bdrv;
+         if (bdrv_has_snapshot(bs1)) {
+             if (must_delete) {
+                 ret = bdrv_snapshot_delete(bs1, old_sn->id_str);
+                 if (ret < 0) {
+                     term_printf("Error while deleting snapshot on '%s'\n",
+                                 bdrv_get_device_name(bs1));
+                 }
+             }
+             /* Write VM state size only to the image that contains the state */
+             sn->vm_state_size = (bs == bs1 ? vm_state_size : 0);
+             ret = bdrv_snapshot_create(bs1, sn);
+             if (ret < 0) {
+                 term_printf("Error while creating snapshot on '%s'\n",
+                             bdrv_get_device_name(bs1));
+             }
+         }
+     }
+  the_end:
+     if (saved_vm_running)
+         vm_start();
+ }
+ void do_loadvm(const char *name)
+ {
+     BlockDriverState *bs, *bs1;
+     BlockDriverInfo bdi1, *bdi = &bdi1;
+     QEMUSnapshotInfo sn;
+     QEMUFile *f;
+     int i, ret;
+     int saved_vm_running;
+     bs = get_bs_snapshots();
+     if (!bs) {
+         term_printf("No block device supports snapshots\n");
+         return;
+     }
+     /* Flush all IO requests so they don't interfere with the new state.  */
+     qemu_aio_flush();
+     saved_vm_running = vm_running;
+     vm_stop(0);
+     for(i = 0; i <= nb_drives; i++) {
+         bs1 = drives_table[i].bdrv;
+         if (bdrv_has_snapshot(bs1)) {
+             ret = bdrv_snapshot_goto(bs1, name);
+             if (ret < 0) {
+                 if (bs != bs1)
+                     term_printf("Warning: ");
+                 switch(ret) {
+                 case -ENOTSUP:
+                     term_printf("Snapshots not supported on device '%s'\n",
+                                 bdrv_get_device_name(bs1));
+                     break;
+                 case -ENOENT:
+                     term_printf("Could not find snapshot '%s' on device '%s'\n",
+                                 name, bdrv_get_device_name(bs1));
+                     break;
+                 default:
+                     term_printf("Error %d while activating snapshot on '%s'\n",
+                                 ret, bdrv_get_device_name(bs1));
+                     break;
+                 }
+                 /* fatal on snapshot block device */
+                 if (bs == bs1)
+                     goto the_end;
+             }
+         }
+     }
+     if (bdrv_get_info(bs, bdi) < 0 || bdi->vm_state_offset <= 0) {
+         term_printf("Device %s does not support VM state snapshots\n",
+                     bdrv_get_device_name(bs));
+         return;
+     }
+     /* Don't even try to load empty VM states */
+     ret = bdrv_snapshot_find(bs, &sn, name);
+     if ((ret >= 0) && (sn.vm_state_size == 0))
+         goto the_end;
+     /* restore the VM state */
+     f = qemu_fopen_bdrv(bs, bdi->vm_state_offset, 0);
+     if (!f) {
+         term_printf("Could not open VM state file\n");
+         goto the_end;
+     }
+     ret = qemu_loadvm_state(f);
+     qemu_fclose(f);
+     if (ret < 0) {
+         term_printf("Error %d while loading VM state\n", ret);
+     }
+  the_end:
+     if (saved_vm_running)
+         vm_start();
+ }
++#endif /* !CONFIG_DM */
++
+ void do_delvm(const char *name)
+ {
+     BlockDriverState *bs, *bs1;
+     int i, ret;
+     bs = get_bs_snapshots();
+     if (!bs) {
+         term_printf("No block device supports snapshots\n");
+         return;
+     }
+     for(i = 0; i <= nb_drives; i++) {
+         bs1 = drives_table[i].bdrv;
+         if (bdrv_has_snapshot(bs1)) {
+             ret = bdrv_snapshot_delete(bs1, name);
+             if (ret < 0) {
+                 if (ret == -ENOTSUP)
+                     term_printf("Snapshots not supported on device '%s'\n",
+                                 bdrv_get_device_name(bs1));
+                 else
+                     term_printf("Error %d while deleting snapshot on '%s'\n",
+                                 ret, bdrv_get_device_name(bs1));
+             }
+         }
+     }
+ }
+ void do_info_snapshots(void)
+ {
+     BlockDriverState *bs, *bs1;
+     QEMUSnapshotInfo *sn_tab, *sn;
+     int nb_sns, i;
+     char buf[256];
+     bs = get_bs_snapshots();
+     if (!bs) {
+         term_printf("No available block device supports snapshots\n");
+         return;
+     }
+     term_printf("Snapshot devices:");
+     for(i = 0; i <= nb_drives; i++) {
+         bs1 = drives_table[i].bdrv;
+         if (bdrv_has_snapshot(bs1)) {
+             if (bs == bs1)
+                 term_printf(" %s", bdrv_get_device_name(bs1));
+         }
+     }
+     term_printf("\n");
+     nb_sns = bdrv_snapshot_list(bs, &sn_tab);
+     if (nb_sns < 0) {
+         term_printf("bdrv_snapshot_list: error %d\n", nb_sns);
+         return;
+     }
+     term_printf("Snapshot list (from %s):\n", bdrv_get_device_name(bs));
+     term_printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL));
+     for(i = 0; i < nb_sns; i++) {
+         sn = &sn_tab[i];
+         term_printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), sn));
+     }
+     qemu_free(sn_tab);
+ }
diff --cc sdl.c
index 9afd884094a8b8f7200d5b7f8b06da8324a5fd69,2ce6e815224dd28c908e30fa47e1ec991c158a92..e9256732c4189db7bc528e0e649b255a09aa8621
--- 1/sdl.c
--- 2/sdl.c
+++ b/sdl.c
  #include <signal.h>
  #endif
  
 -static SDL_Surface *screen;
 +#ifdef CONFIG_OPENGL
 +#include <SDL_opengl.h>
 +#endif
 +
- static SDL_Surface *screen;
- static SDL_Surface *shared = NULL;
++static DisplayChangeListener *dcl;
++static SDL_Surface *real_screen;
++static SDL_Surface *guest_screen = NULL;
  static int gui_grab; /* if true, all keyboard/mouse events are grabbed */
  static int last_vm_running;
  static int gui_saved_grab;
@@@ -51,281 -46,67 +52,180 @@@ static int width, height
  static SDL_Cursor *sdl_cursor_normal;
  static SDL_Cursor *sdl_cursor_hidden;
  static int absolute_enabled = 0;
 -static int guest_cursor = 0;
 -static int guest_x, guest_y;
 -static SDL_Cursor *guest_sprite = 0;
 +static int opengl_enabled;
 +
- static void sdl_colourdepth(DisplayState *ds, int depth);
 +#ifdef CONFIG_OPENGL
 +static GLint tex_format;
 +static GLint tex_type;
 +static GLuint texture_ref = 0;
 +static GLint gl_format;
++static uint8_t bgr;
 +
- static void opengl_setdata(DisplayState *ds, void *pixels)
++static void opengl_setdata(DisplayState *ds)
 +{
 +    glEnable(GL_TEXTURE_RECTANGLE_ARB);
 +    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
 +    glClearColor(0, 0, 0, 0);
 +    glDisable(GL_BLEND);
 +    glDisable(GL_LIGHTING);
 +    glDisable(GL_DEPTH_TEST);
 +    glDepthMask(GL_FALSE);
 +    glDisable(GL_CULL_FACE);
-     glViewport( 0, 0, screen->w, screen->h);
++    glViewport( 0, 0, real_screen->w, real_screen->h);
 +    glMatrixMode(GL_PROJECTION);
 +    glLoadIdentity();
-     glOrtho(0, screen->w, screen->h, 0, -1,1);
++    glOrtho(0, real_screen->w, real_screen->h, 0, -1,1);
 +    glMatrixMode(GL_MODELVIEW);
 +    glLoadIdentity();
 +    glClear(GL_COLOR_BUFFER_BIT);
-     ds->data = pixels;
 +
 +    if (texture_ref) {
 +        glDeleteTextures(1, &texture_ref);
 +        texture_ref = 0;
 +    }
 +
 +    glGenTextures(1, &texture_ref);
 +    glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture_ref);
 +    glPixelStorei(GL_UNPACK_LSB_FIRST, 1);
-     switch (ds->depth) {
-         case 8:
-             if (ds->palette == NULL) {
-                 tex_format = GL_RGB;
-                 tex_type = GL_UNSIGNED_BYTE_3_3_2;
-             } else {
-                 int i;
-                 GLushort paletter[256], paletteg[256], paletteb[256];
-                 for (i = 0; i < 256; i++) {
-                     uint8_t rgb = ds->palette[i] >> 16;
-                     paletter[i] = ((rgb & 0xe0) >> 5) * 65535 / 7;
-                     paletteg[i] = ((rgb & 0x1c) >> 2) * 65535 / 7;
-                     paletteb[i] = (rgb & 0x3) * 65535 / 3;
-                 }
-                 glPixelMapusv(GL_PIXEL_MAP_I_TO_R, 256, paletter);
-                 glPixelMapusv(GL_PIXEL_MAP_I_TO_G, 256, paletteg);
-                 glPixelMapusv(GL_PIXEL_MAP_I_TO_B, 256, paletteb);
-                 tex_format = GL_COLOR_INDEX;
-                 tex_type = GL_UNSIGNED_BYTE;
-             }
-             break;
++    switch (ds_get_bits_per_pixel(ds)) {
 +        case 16:
 +            tex_format = GL_RGB;
 +            tex_type = GL_UNSIGNED_SHORT_5_6_5;
 +            break;
 +        case 24:
 +            tex_format = GL_BGR;
 +            tex_type = GL_UNSIGNED_BYTE;
 +            break;
 +        case 32:
-             if (!ds->bgr) {
++            if (bgr == (ds->surface->pf.rshift < ds->surface->pf.bshift)) {
 +                tex_format = GL_BGRA;
 +                tex_type = GL_UNSIGNED_BYTE;
 +            } else {
 +                tex_format = GL_RGBA;
 +                tex_type = GL_UNSIGNED_BYTE;                
 +            }
 +            break;
 +    }   
-     glPixelStorei(GL_UNPACK_ROW_LENGTH, (ds->linesize * 8) / ds->depth);
-     glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, gl_format, ds->width, ds->height, 0, tex_format, tex_type, pixels);
++    glPixelStorei(GL_UNPACK_ROW_LENGTH, (ds_get_linesize(ds) / ds_get_bytes_per_pixel(ds)));
++    glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, gl_format, ds_get_width(ds), ds_get_height(ds), 0, tex_format, tex_type, ds_get_data(ds));
 +    glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_PRIORITY, 1.0);
 +    glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 +    glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 +    glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
 +    glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 +    glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
 +}
 +
 +static void opengl_update(DisplayState *ds, int x, int y, int w, int h)
 +{  
-     int bpp = ds->depth / 8;
-     GLvoid *pixels = ds->data + y * ds->linesize + x * bpp;
++    int bpp = ds_get_bytes_per_pixel(ds);
++    GLvoid *pixels = ds_get_data(ds) + y * ds_get_linesize(ds) + x * bpp;
 +    glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture_ref);
-     glPixelStorei(GL_UNPACK_ROW_LENGTH, ds->linesize / bpp);
++    glPixelStorei(GL_UNPACK_ROW_LENGTH, ds_get_linesize(ds) / bpp);
 +    glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, x, y, w, h, tex_format, tex_type, pixels);
 +    glBegin(GL_QUADS);
 +        glTexCoord2d(0, 0);
 +        glVertex2d(0, 0);
-         glTexCoord2d(ds->width, 0);
-         glVertex2d(screen->w, 0);
-         glTexCoord2d(ds->width, ds->height);
-         glVertex2d(screen->w, screen->h);
-         glTexCoord2d(0, ds->height);
-         glVertex2d(0, screen->h);
++        glTexCoord2d(ds_get_width(ds), 0);
++        glVertex2d(real_screen->w, 0);
++        glTexCoord2d(ds_get_width(ds), ds_get_height(ds));
++        glVertex2d(real_screen->w, real_screen->h);
++        glTexCoord2d(0, ds_get_height(ds));
++        glVertex2d(0, real_screen->h);
 +    glEnd();
 +    glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
 +    SDL_GL_SwapBuffers();
 +}
 +#endif
  
  static void sdl_update(DisplayState *ds, int x, int y, int w, int h)
  {
--    //    printf("updating x=%d y=%d w=%d h=%d\n", x, y, w, h);
-     if (shared) {
-         SDL_Rect rec;
-         rec.x = x;
-         rec.y = y;
-         rec.w = w;
-         rec.h = h;
-         SDL_BlitSurface(shared, &rec, screen, &rec);
-     }
-     SDL_Flip(screen);
 -    SDL_UpdateRect(screen, x, y, w, h);
++    SDL_Rect rec;
++    rec.x = x;
++    rec.y = y;
++    rec.w = w;
++    rec.h = h;
++    //    printf("updating x=%d y=%d w=%d h=%d\n", x, y, w, h);i
++
++    SDL_BlitSurface(guest_screen, &rec, real_screen, &rec);
++    SDL_UpdateRect(real_screen, x, y, w, h);
  }
  
- static void sdl_setdata(DisplayState *ds, void *pixels)
 -static void sdl_resize(DisplayState *ds, int w, int h)
++static void sdl_setdata(DisplayState *ds)
 +{
-     uint32_t rmask, gmask, bmask, amask = 0;
-     switch (ds->depth) {
-         case 8:
-             rmask = 0x000000E0;
-             gmask = 0x0000001C;
-             bmask = 0x00000003;
-             break;
-         case 16:
-             rmask = 0x0000F800;
-             gmask = 0x000007E0;
-             bmask = 0x0000001F;
-             break;
-         case 24:
-             rmask = 0x00FF0000;
-             gmask = 0x0000FF00;
-             bmask = 0x000000FF;
-             break;
-         case 32:
-             rmask = 0x00FF0000;
-             gmask = 0x0000FF00;
-             bmask = 0x000000FF;
-             break;
-         default:
-             return;
-     }
-     shared = SDL_CreateRGBSurfaceFrom(pixels, width, height, ds->depth, ds->linesize, rmask , gmask, bmask, amask);
-     if (ds->depth == 8 && ds->palette != NULL) {
-         SDL_Color palette[256];
-         int i;
-         for (i = 0; i < 256; i++) {
-             uint8_t rgb = ds->palette[i] >> 16;
-             palette[i].r = ((rgb & 0xe0) >> 5) * 255 / 7;
-             palette[i].g = ((rgb & 0x1c) >> 2) * 255 / 7;
-             palette[i].b = (rgb & 0x3) * 255 / 3;
-         }
-         SDL_SetColors(shared, palette, 0, 256);
-     }
-     ds->data = pixels;
++    SDL_Rect rec;
++    rec.x = 0;
++    rec.y = 0;
++    rec.w = real_screen->w;
++    rec.h = real_screen->h;
++
++    if (guest_screen != NULL) SDL_FreeSurface(guest_screen);
++
++    guest_screen = SDL_CreateRGBSurfaceFrom(ds_get_data(ds), ds_get_width(ds), ds_get_height(ds),
++                                            ds_get_bits_per_pixel(ds), ds_get_linesize(ds),
++                                            ds->surface->pf.rmask, ds->surface->pf.gmask,
++                                            ds->surface->pf.bmask, ds->surface->pf.amask);
 +}
 +
- static void sdl_resize_shared(DisplayState *ds, int w, int h, int depth, int linesize, void *pixels)
++static void sdl_resize(DisplayState *ds)
  {
      int flags;
  
      //    printf("resizing to %d %d\n", w, h);
-     sdl_colourdepth(ds, depth);
 +#ifdef CONFIG_OPENGL
-     if (ds->shared_buf && opengl_enabled)
++    if (opengl_enabled)
 +        flags = SDL_OPENGL|SDL_RESIZABLE;
 +    else
 +#endif
-         flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL|SDL_DOUBLEBUF|SDL_HWPALETTE;
++        flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL;
  
-     if (gui_fullscreen) {
 -    flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL;
+     if (gui_fullscreen)
          flags |= SDL_FULLSCREEN;
-         flags &= ~SDL_RESIZABLE;
-     }
      if (gui_noframe)
          flags |= SDL_NOFRAME;
  
--    width = w;
--    height = h;
--
-- again:
--    screen = SDL_SetVideoMode(w, h, 0, flags);
--    if (!screen) {
-         fprintf(stderr, "Could not open SDL display: %s\n", SDL_GetError());
++    width = ds_get_width(ds);
++    height = ds_get_height(ds);
++    real_screen = SDL_SetVideoMode(width, height, 0, flags);
++    if (!real_screen) {
 +        if (opengl_enabled) {
 +            /* Fallback to SDL */
 +            opengl_enabled = 0;
-             ds->dpy_update = sdl_update;
-             ds->dpy_setdata = sdl_setdata;
-             ds->dpy_resize_shared = sdl_resize_shared;
-             sdl_resize_shared(ds, w, h, depth, linesize, pixels);
++            dcl->dpy_update = sdl_update;
++            dcl->dpy_setdata = sdl_setdata;
++            sdl_resize(ds);
 +            return;
 +        }
+         fprintf(stderr, "Could not open SDL display\n");
          exit(1);
      }
 -    if (!screen->pixels && (flags & SDL_HWSURFACE) && (flags & SDL_FULLSCREEN)) {
 -        flags &= ~SDL_HWSURFACE;
 -        goto again;
 -    }
  
-     if (!opengl_enabled) {
-         if (!screen->pixels && (flags & SDL_HWSURFACE) && (flags & SDL_FULLSCREEN)) {
-             flags &= ~SDL_HWSURFACE;
-             goto again;
-         }
-         if (!screen->pixels) {
-             fprintf(stderr, "Could not open SDL display: %s\n", SDL_GetError());
-             exit(1);
-         }
 -    if (!screen->pixels) {
 -        fprintf(stderr, "Could not open SDL display\n");
 -        exit(1);
--    }
 -    ds->data = screen->pixels;
 -    ds->linesize = screen->pitch;
 -    ds->depth = screen->format->BitsPerPixel;
 -    /* SDL BitsPerPixel never indicates any values other than
 -       multiples of 8, so we need to check for strange depths. */
 -    if (ds->depth == 16) {
 -        uint32_t mask;
--
-     ds->width = w;
-     ds->height = h;
-     if (!ds->shared_buf) {
-         ds->depth = screen->format->BitsPerPixel;
-       if (screen->format->Bshift > screen->format->Rshift) {
-             ds->bgr = 1;
-         } else {
-             ds->bgr = 0;
-         }
-         shared = NULL;
-         ds->data = screen->pixels;
-         ds->linesize = screen->pitch;
-     } else {
-         ds->linesize = linesize;
 -        mask = screen->format->Rmask;
 -        mask |= screen->format->Gmask;
 -        mask |= screen->format->Bmask;
 -        if ((mask & 0x8000) == 0)
 -            ds->depth = 15;
 -    }
 -    if (ds->depth == 32 && screen->format->Rshift == 0) {
 -        ds->bgr = 1;
 +#ifdef CONFIG_OPENGL
-         switch(screen->format->BitsPerPixel) {
++    if (real_screen->format->Bshift > real_screen->format->Rshift) {
++        bgr = 1;
+     } else {
 -        ds->bgr = 0;
++        bgr = 0;
+     }
 -    ds->width = w;
 -    ds->height = h;
++    switch(real_screen->format->BitsPerPixel) {
 +        case 8:
 +            gl_format = GL_RGB;
 +            break;
 +        case 16:
 +            gl_format = GL_RGB;
 +            break;
 +        case 24:
 +            gl_format = GL_RGB;
 +            break;
 +        case 32:
-             if (!screen->format->Rshift)
++            if (!real_screen->format->Rshift)
 +                gl_format = GL_BGRA;
 +            else
 +                gl_format = GL_RGBA;
 +            break;
-         };
++    };
 +#endif
-     }
-     if (ds->shared_buf) ds->dpy_setdata(ds, pixels);
- }
 +
- static void sdl_resize(DisplayState *ds, int w, int h)
- {
-     sdl_resize_shared(ds, w, h, 0, w * (ds->depth / 8), NULL);
- }
- static void sdl_colourdepth(DisplayState *ds, int depth)
- {
-     if (!depth || !ds->depth) {
-       ds->shared_buf = 0;
-       ds->dpy_update = sdl_update;
-       return;
-     }
-     ds->shared_buf = 1;
-     ds->depth = depth;
- #ifdef CONFIG_OPENGL
-     if (opengl_enabled) {
-         ds->dpy_update = opengl_update;
-     }
- #endif
++    dcl->dpy_setdata(ds);
  }
  
  /* generic keyboard conversion */
@@@ -523,9 -322,8 +423,9 @@@ static void sdl_send_mouse_event(int dx
            absolute_enabled = 1;
        }
  
 -       dx = x * 0x7FFF / (width - 1);
 -       dy = y * 0x7FFF / (height - 1);
 +      SDL_GetMouseState(&dx, &dy);
-         dx = dx * 0x7FFF / (screen->w - 1);
-         dy = dy * 0x7FFF / (screen->h - 1);
++        dx = dx * 0x7FFF / (real_screen->w - 1);
++        dy = dy * 0x7FFF / (real_screen->h - 1);
      } else if (absolute_enabled) {
        sdl_show_cursor();
        absolute_enabled = 0;
  static void toggle_full_screen(DisplayState *ds)
  {
      gui_fullscreen = !gui_fullscreen;
-     sdl_resize_shared(ds, ds->width, ds->height, ds->depth, ds->linesize, ds->data);
 -    sdl_resize(ds, screen->w, screen->h);
++    sdl_resize(ds);
      if (gui_fullscreen) {
          gui_saved_grab = gui_grab;
          sdl_grab_start();
@@@ -565,7 -371,7 +465,7 @@@ static void sdl_refresh(DisplayState *d
      while (SDL_PollEvent(ev)) {
          switch (ev->type) {
          case SDL_VIDEOEXPOSE:
-             ds->dpy_update(ds, 0, 0, ds->width, ds->height);
 -            sdl_update(ds, 0, 0, screen->w, screen->h);
++            dcl->dpy_update(ds, 0, 0, ds_get_width(ds), ds_get_height(ds));
              break;
          case SDL_KEYDOWN:
          case SDL_KEYUP:
                  !ev->active.gain && !gui_fullscreen_initial_grab) {
                  sdl_grab_end();
              }
 -            if (ev->active.state & SDL_APPACTIVE) {
 -                if (ev->active.gain) {
 -                    /* Back to default interval */
 -                    ds->gui_timer_interval = 0;
 -                    ds->idle = 0;
 -                } else {
 -                    /* Sleeping interval */
 -                    ds->gui_timer_interval = 500;
 -                    ds->idle = 1;
 -                }
 +          if (ev->active.state & SDL_APPACTIVE) {
 +              if (ev->active.gain) {
 +                  /* Back to default interval */
-                   ds->gui_timer_interval = 0;
-                   ds->idle = 0;
++                  dcl->gui_timer_interval = 0;
++                  dcl->idle = 0;
 +              } else {
 +                  /* Sleeping interval */
-                   ds->gui_timer_interval = 500;
-                   ds->idle = 1;
++                  dcl->gui_timer_interval = 500;
++                  dcl->idle = 1;
 +              }
 +          }
 +            break;
 +#ifdef CONFIG_OPENGL
 +        case SDL_VIDEORESIZE:
 +        {
-             if (ds->shared_buf && opengl_enabled) {
++            if (opengl_enabled) {
 +                SDL_ResizeEvent *rev = &ev->resize;
-                 screen = SDL_SetVideoMode(rev->w, rev->h, 0, SDL_OPENGL|SDL_RESIZABLE);
-                 opengl_setdata(ds, ds->data);
-                 opengl_update(ds, 0, 0, ds->width, ds->height);
++                real_screen = SDL_SetVideoMode(rev->w, rev->h, 0, SDL_OPENGL|SDL_RESIZABLE);
++                opengl_setdata(ds);
++                opengl_update(ds, 0, 0, ds_get_width(ds), ds_get_height(ds));
              }
              break;
 +        }
 +#endif
          default:
              break;
          }
@@@ -785,23 -639,15 +685,27 @@@ void sdl_display_init(DisplayState *ds
          fprintf(stderr, "Could not initialize SDL - exiting\n");
          exit(1);
      }
 +#ifndef _WIN32
 +    /* NOTE: we still want Ctrl-C to work, so we undo the SDL redirections */
 +    signal(SIGINT, SIG_DFL);
 +    signal(SIGQUIT, SIG_DFL);
 +#endif
  
--    ds->dpy_update = sdl_update;
--    ds->dpy_resize = sdl_resize;
-     ds->dpy_resize_shared = sdl_resize_shared;
--    ds->dpy_refresh = sdl_refresh;
-     ds->dpy_setdata = sdl_setdata;
 -    ds->dpy_fill = sdl_fill;
 -    ds->mouse_set = sdl_mouse_warp;
 -    ds->cursor_define = sdl_mouse_define;
++    dcl = qemu_mallocz(sizeof(DisplayChangeListener));
++    if (!dcl)
++        exit(1);
++    dcl->dpy_update = sdl_update;
++    dcl->dpy_resize = sdl_resize;
++    dcl->dpy_refresh = sdl_refresh;
++    dcl->dpy_setdata = sdl_setdata;
 +#ifdef CONFIG_OPENGL
-     if (opengl_enabled)
-         ds->dpy_setdata = opengl_setdata;
++    if (opengl_enabled) {
++        dcl->dpy_update = opengl_update;
++        dcl->dpy_setdata = opengl_setdata;
++    }
 +#endif
++    register_displaychangelistener(ds, dcl);
  
--    sdl_resize(ds, 640, 400);
      sdl_update_caption();
      SDL_EnableKeyRepeat(250, 50);
      gui_grab = 0;
diff --cc sysemu.h
index 6b3dd8386a3990c2f29e96affe8e60b7f669362f,55f8d79da8e3c612faaa48c6a308c54bfd9f8ff4..2bb6c3f66f936e026b8fd54217e7032364035d23
+++ b/sysemu.h
@@@ -123,8 -126,7 +126,8 @@@ extern unsigned int nb_prom_envs
  #endif
  
  typedef enum {
-     IF_IDE, IF_SCSI, IF_FLOPPY, IF_PFLASH, IF_MTD, IF_SD
 +    IF_BLKTAP,
+     IF_IDE, IF_SCSI, IF_FLOPPY, IF_PFLASH, IF_MTD, IF_SD, IF_VIRTIO
  } BlockInterfaceType;
  
  typedef struct DriveInfo {
diff --cc usb-linux.c
Simple merge
diff --cc vl.c
index dd5d155b318ba43e0d35aaa438ebbd72469f2a4b,2452d0f7d95ee34b951164859d0fe55d53b1e7cf..7be1ade835f3207e7735ddfcba9907f468dff26f
--- 1/vl.c
--- 2/vl.c
+++ b/vl.c
  #include "gdbstub.h"
  #include "qemu-timer.h"
  #include "qemu-char.h"
+ #include "cache-utils.h"
  #include "block.h"
  #include "audio/audio.h"
 +#include "qemu-xen.h"
  #include "migration.h"
+ #include "kvm.h"
+ #include "balloon.h"
  
  #include <unistd.h>
 +#include <stdlib.h>
  #include <fcntl.h>
  #include <signal.h>
  #include <time.h>
@@@ -189,10 -188,9 +197,11 @@@ static IOPortWriteFunc *ioport_write_ta
     to store the VM snapshots */
  DriveInfo drives_table[MAX_DRIVES+1];
  int nb_drives;
 +/* point to the block driver where the snapshots are managed */
 +static BlockDriverState *bs_snapshots;
+ static int vga_ram_size;
  enum vga_retrace_method vga_retrace_method = VGA_RETRACE_DUMB;
static DisplayState display_state;
+ DisplayState display_state;
  int nographic;
  static int curses;
  const char* keyboard_layout = NULL;
@@@ -217,28 -214,22 +225,32 @@@ int graphic_height = 600
  int graphic_depth = 15;
  #endif
  static int full_screen = 0;
+ #ifdef CONFIG_SDL
  static int no_frame = 0;
+ #endif
  int no_quit = 0;
 +#ifdef CONFIG_OPENGL
 +int opengl_enabled = 1;
 +#else
 +int opengl_enabled = 0;
 +#endif
 +static const char *direct_pci;
 +static int nb_pci_emulation = 0;
 +static char pci_emulation_config_text[MAX_PCI_EMULATION][256];
 +PCI_EMULATION_INFO *PciEmulationInfoHead = NULL;
  CharDriverState *serial_hds[MAX_SERIAL_PORTS];
  CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];
+ CharDriverState *virtcon_hds[MAX_VIRTIO_CONSOLES];
  #ifdef TARGET_I386
  int win2k_install_hack = 0;
+ int rtc_td_hack = 0;
  #endif
  int usb_enabled = 0;
- static VLANState *first_vlan;
  int smp_cpus = 1;
  const char *vnc_display;
 +int vncunused;
  int acpi_enabled = 1;
+ int no_hpet = 0;
  int fd_bootchk = 1;
  int no_reboot = 0;
  int no_shutdown = 0;
@@@ -277,24 -268,6 +289,8 @@@ static QEMUTimer *icount_vm_timer
  
  uint8_t qemu_uuid[16];
  
- #define TFR(expr) do { if ((expr) != -1) break; } while (errno == EINTR)
 +#include "xen-vl-extra.c"
 +
- typedef struct IOHandlerRecord {
-     int fd;
-     IOCanRWHandler *fd_read_poll;
-     IOHandler *fd_read;
-     IOHandler *fd_write;
-     int deleted;
-     void *opaque;
-     /* temporary data */
-     struct pollfd *ufd;
-     struct IOHandlerRecord *next;
- } IOHandlerRecord;
- static IOHandlerRecord *first_io_handler;
  /***********************************************************/
  /* x86 ISA bus support */
  
@@@ -1317,7 -1288,6 +1323,7 @@@ static int timer_load(QEMUFile *f, voi
      return 0;
  }
  
- #ifndef CONFIG_DM
++#ifndef CONFIG_DM /* ends after end of win32_rearm_timer */
  #ifdef _WIN32
  void CALLBACK host_alarm_handler(UINT uTimerID, UINT uMsg,
                                   DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)
@@@ -1725,9 -1732,8 +1768,9 @@@ static void win32_rearm_timer(struct qe
  }
  
  #endif /* _WIN32 */
 +#endif /* !CONFIG_DM */
  
- static void init_timer_alarm(void)
+ static int init_timer_alarm(void)
  {
      struct qemu_alarm_timer *t = NULL;
      int i, err = -1;
@@@ -8398,23 -3891,22 +3949,23 @@@ static void help(int exitcode
             "                hostname 'host' to DHCP clients\n"
  #endif
  #ifdef _WIN32
-            "-net tap[,vlan=n],ifname=name\n"
+            "-net tap[,vlan=n][,name=str],ifname=name\n"
             "                connect the host TAP network interface to VLAN 'n'\n"
  #else
-            "-net tap[,vlan=n][,fd=h][,ifname=name][,script=file][,downscript=dfile][,scriptarg=extraargument]\n"
 -           "-net tap[,vlan=n][,name=str][,fd=h][,ifname=name][,script=file][,downscript=dfile]\n"
++           "-net tap[,vlan=n][,name=str][,fd=h][,ifname=name][,script=file][,downscript=dfile][,scriptarg=extraargument]\n"
             "                connect the host TAP network interface to VLAN 'n' and use the\n"
             "                network scripts 'file' (default=%s)\n"
             "                and 'dfile' (default=%s);\n"
             "                use '[down]script=no' to disable script execution;\n"
 +           "                use 'scriptarg=...' to pass an additional (nonempty) argument;\n"
             "                use 'fd=h' to connect to an already opened TAP interface\n"
  #endif
-            "-net socket[,vlan=n][,fd=h][,listen=[host]:port][,connect=host:port]\n"
+            "-net socket[,vlan=n][,name=str][,fd=h][,listen=[host]:port][,connect=host:port]\n"
             "                connect the vlan 'n' to another VLAN using a socket connection\n"
-            "-net socket[,vlan=n][,fd=h][,mcast=maddr:port]\n"
+            "-net socket[,vlan=n][,name=str][,fd=h][,mcast=maddr:port]\n"
             "                connect the vlan 'n' to multicast maddr and port\n"
  #ifdef CONFIG_VDE
-            "-net vde[,vlan=n][,sock=socketpath][,port=n][,group=groupname][,mode=octalmode]\n"
+            "-net vde[,vlan=n][,name=str][,sock=socketpath][,port=n][,group=groupname][,mode=octalmode]\n"
             "                connect the vlan 'n' to port 'n' of a vde switch running\n"
             "                on host and listening for incoming connections on 'socketpath'.\n"
             "                Use group 'groupname' and mode 'octalmode' to change default\n"
             "-kernel-kqemu   enable KQEMU full virtualization (default is user mode only)\n"
             "-no-kqemu       disable KQEMU kernel module usage\n"
  #endif
+ #ifdef CONFIG_KVM
+            "-enable-kvm     enable KVM full virtualization support\n"
+ #endif
  #ifdef TARGET_I386
 +           "-std-vga        simulate a standard VGA card with VESA Bochs Extensions\n"
 +           "                (default is CL-GD5446 PCI VGA)\n"
 +           "-videoram       set amount of memory available to virtual video adapter\n"
             "-no-acpi        disable ACPI\n"
+            "-no-hpet        disable HPET\n"
  #endif
  #ifdef CONFIG_CURSES
             "-curses         use a curses/ncurses interface instead of SDL\n"
@@@ -8551,12 -4054,10 +4117,13 @@@ enum 
      QEMU_OPTION_localtime,
      QEMU_OPTION_g,
      QEMU_OPTION_vga,
 +    QEMU_OPTION_std_vga,
 +    QEMU_OPTION_videoram,
      QEMU_OPTION_echr,
      QEMU_OPTION_monitor,
 +    QEMU_OPTION_domainname,
      QEMU_OPTION_serial,
+     QEMU_OPTION_virtiocon,
      QEMU_OPTION_parallel,
      QEMU_OPTION_loadvm,
      QEMU_OPTION_full_screen,
      QEMU_OPTION_usbdevice,
      QEMU_OPTION_smp,
      QEMU_OPTION_vnc,
 +    QEMU_OPTION_vncunused,
      QEMU_OPTION_no_acpi,
+     QEMU_OPTION_no_hpet,
      QEMU_OPTION_curses,
      QEMU_OPTION_no_reboot,
      QEMU_OPTION_no_shutdown,
@@@ -8674,8 -4167,8 +4248,9 @@@ static const QEMUOption qemu_options[] 
      { "vga", HAS_ARG, QEMU_OPTION_vga },
      { "echr", HAS_ARG, QEMU_OPTION_echr },
      { "monitor", HAS_ARG, QEMU_OPTION_monitor },
 +    { "domain-name", 1, QEMU_OPTION_domainname },
      { "serial", HAS_ARG, QEMU_OPTION_serial },
+     { "virtioconsole", HAS_ARG, QEMU_OPTION_virtiocon },
      { "parallel", HAS_ARG, QEMU_OPTION_parallel },
      { "loadvm", HAS_ARG, QEMU_OPTION_loadvm },
      { "full-screen", 0, QEMU_OPTION_full_screen },
      { "alt-grab", 0, QEMU_OPTION_alt_grab },
      { "no-quit", 0, QEMU_OPTION_no_quit },
  #endif
 +#ifdef CONFIG_OPENGL
 +    { "disable-opengl", 0, QEMU_OPTION_disable_opengl },
 +#endif
 +    { "vcpus", 1, QEMU_OPTION_vcpus },
 +    { "acpi", 0, QEMU_OPTION_acpi }, /* deprecated, for xend compatibility */
 +    { "direct_pci", HAS_ARG, QEMU_OPTION_direct_pci },
 +    { "pciemulation", HAS_ARG, QEMU_OPTION_pci_emulation },
      { "pidfile", HAS_ARG, QEMU_OPTION_pidfile },
      { "win2k-hack", 0, QEMU_OPTION_win2k_hack },
+     { "rtc-td-hack", 0, QEMU_OPTION_rtc_td_hack },
      { "usbdevice", HAS_ARG, QEMU_OPTION_usbdevice },
      { "smp", HAS_ARG, QEMU_OPTION_smp },
      { "vnc", HAS_ARG, QEMU_OPTION_vnc },
@@@ -9022,43 -4517,13 +4616,44 @@@ int main(int argc, char **argv, char **
      const char *usb_devices[MAX_USB_CMDLINE];
      int usb_devices_index;
      int fds[2];
 +#ifndef CONFIG_STUBDOM
 +    struct rlimit rl;
 +#endif
      int tb_size;
      const char *pid_file = NULL;
-     VLANState *vlan;
      int autostart;
      const char *incoming = NULL;
  
 +    logfile = stderr; /* initial value */
 +
 +#if !defined(__sun__) && !defined(CONFIG_STUBDOM)
 +    /* Maximise rlimits. Needed where default constraints are tight (*BSD). */
 +    if (getrlimit(RLIMIT_STACK, &rl) != 0) {
 +       perror("getrlimit(RLIMIT_STACK)");
 +       exit(1);
 +    }
 +    rl.rlim_cur = rl.rlim_max;
 +    if (setrlimit(RLIMIT_STACK, &rl) != 0)
 +       perror("setrlimit(RLIMIT_STACK)");
 +    if (getrlimit(RLIMIT_DATA, &rl) != 0) {
 +       perror("getrlimit(RLIMIT_DATA)");
 +       exit(1);
 +    }
 +    rl.rlim_cur = rl.rlim_max;
 +    if (setrlimit(RLIMIT_DATA, &rl) != 0)
 +       perror("setrlimit(RLIMIT_DATA)");
 +    rl.rlim_cur = RLIM_INFINITY;
 +    rl.rlim_max = RLIM_INFINITY;
 +    if (setrlimit(RLIMIT_RSS, &rl) != 0)
 +       perror("setrlimit(RLIMIT_RSS)");
 +    rl.rlim_cur = RLIM_INFINITY;
 +    rl.rlim_max = RLIM_INFINITY;
 +    if (setrlimit(RLIMIT_MEMLOCK, &rl) != 0)
 +       perror("setrlimit(RLIMIT_MEMLOCK)");
 + #endif
 + 
+     qemu_cache_utils_init(envp);
      LIST_INIT (&vm_change_state_head);
  #ifndef _WIN32
      {
      machine = first_machine;
      cpu_model = NULL;
      initrd_filename = NULL;
--    ram_size = 0;
 -    vga_ram_size = VGA_RAM_SIZE;
++    ram_size = VGA_RAM_SIZE;
  #ifdef CONFIG_GDBSTUB
      use_gdbstub = 0;
      gdbstub_port = DEFAULT_GDBSTUB_PORT;
              case QEMU_OPTION_semihosting:
                  semihosting_enabled = 1;
                  break;
 +            case QEMU_OPTION_domainname: /* depricated, use -name instead */
              case QEMU_OPTION_name:
                  qemu_name = optarg;
 +                snprintf(domain_name, sizeof(domain_name),
 +                         "Xen-%s", optarg);
                  break;
- #ifdef TARGET_SPARC
+ #if defined(TARGET_SPARC) || defined(TARGET_PPC)
              case QEMU_OPTION_prom_env:
                  if (nb_prom_envs >= MAX_PROM_ENVS) {
                      fprintf(stderr, "Too many prom variables\n");
          if (net_client_parse(net_clients[i]) < 0)
              exit(1);
      }
-     for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) {
-         if (vlan->nb_guest_devs == 0 && vlan->nb_host_devs == 0)
-             continue;
-         if (vlan->nb_guest_devs == 0)
-             fprintf(stderr, "Warning: vlan %d with no nics\n", vlan->id);
-         if (vlan->nb_host_devs == 0)
-             fprintf(stderr,
-                     "Warning: vlan %d is not connected to host network\n",
-                     vlan->id);
-     }
+     net_client_check();
  
 -#ifdef TARGET_I386
 +#if defined(TARGET_I386) && !defined(CONFIG_DM)
      /* XXX: this should be moved in the PC machine instantiation code */
      if (net_boot != 0) {
          int netroms = 0;
            exit(1);
        }
      }
 +
 +#endif
 +
 +#if defined (__ia64__)
 +    if (ram_size > VGA_IO_START)
 +        ram_size += VGA_IO_SIZE; /* skip VGA I/O hole */
 +    if (ram_size > MMIO_START)
 +        ram_size += 1 * MEM_G; /* skip 3G-4G MMIO, LEGACY_IO_SPACE etc. */
  #endif
  
+     /* init the bluetooth world */
+     for (i = 0; i < nb_bt_opts; i++)
+         if (bt_parse(bt_opts[i]))
+             exit(1);
      /* init the memory */
 -    phys_ram_size = machine->ram_require & ~RAMSIZE_FIXED;
 +
 +    /* If we're on cirrus, set vga_ram_size to 4M whatever the videoram option might have set it to */
 +    if ( cirrus_vga_enabled && vga_ram_size != 4 * 1024 * 1024 )
 +    {
 +       fprintf(stderr,"-videoram option does not work with cirrus vga device model. Videoram set to 4M.\n");
 +       vga_ram_size = 4 * 1024 * 1024;
 +    }
 +
 +    phys_ram_size = (machine->ram_require + vga_ram_size) & ~RAMSIZE_FIXED;
  
      if (machine->ram_require & RAMSIZE_FIXED) {
          if (ram_size > 0) {
          }
      }
  
 +    for (i = 0; i < nb_pci_emulation; i++) {
 +        if(pci_emulation_add(pci_emulation_config_text[i]) < 0) {
 +            fprintf(stderr, "Warning: could not add PCI device %s\n",
 +                    pci_emulation_config_text[i]);
 +        }
 +    }
 +
 +    if (strlen(direct_pci_str) > 0)
 +        direct_pci = direct_pci_str;
 +
+     for(i = 0; i < MAX_VIRTIO_CONSOLES; i++) {
+         const char *devname = virtio_consoles[i];
+         if (devname && strcmp(devname, "none")) {
+             char label[32];
+             snprintf(label, sizeof(label), "virtcon%d", i);
+             virtcon_hds[i] = qemu_chr_open(label, devname);
+             if (!virtcon_hds[i]) {
+                 fprintf(stderr, "qemu: could not open virtio console '%s'\n",
+                         devname);
+                 exit(1);
+             }
+             if (strstart(devname, "vc", 0))
+                 qemu_chr_printf(virtcon_hds[i], "virtio console%d\r\n", i);
+         }
+     }
+     if (kvm_enabled()) {
+         int ret;
+         ret = kvm_init(smp_cpus);
+         if (ret < 0) {
+             fprintf(stderr, "failed to initialize KVM\n");
+             exit(1);
+         }
+     }
      machine->init(ram_size, vga_ram_size, boot_devices, ds,
 -                  kernel_filename, kernel_cmdline, initrd_filename, cpu_model);
 +                  kernel_filename, kernel_cmdline, initrd_filename, cpu_model,
 +                direct_pci);
  
+     /* Set KVM's vcpu state to qemu's initial CPUState. */
+     if (kvm_enabled()) {
+         int ret;
+         ret = kvm_sync_vcpus();
+         if (ret < 0) {
+             fprintf(stderr, "failed to initialize vcpus\n");
+             exit(1);
+         }
+     }
      /* init USB devices */
      if (usb_enabled) {
          for(i = 0; i < usb_devices_index; i++) {
diff --cc vnc.c
index 02d3b1d16e085a582211ddc8fc7012160648cbbf,e1ff4edd754651065f1f3ea3e6d8582de4cb75b2..52e46274ff85fa06ec126e0a1b5b9166811d75e4
--- 1/vnc.c
--- 2/vnc.c
+++ b/vnc.c
@@@ -74,6 -56,6 +74,12 @@@ static void vnc_debug_gnutls_log(int le
  #define VNC_DEBUG(fmt, ...) do { } while (0)
  #endif
  
++#define count_bits(c, v) { \
++    for (c = 0; v; v >>= 1) \
++    { \
++        c += v & 1; \
++    } \
++}
  
  typedef struct Buffer
  {
@@@ -162,18 -123,12 +168,15 @@@ struct VncStat
      int lsock;
      int csock;
      DisplayState *ds;
 -    int need_update;
--    int width;
--    int height;
 -    uint32_t dirty_row[VNC_MAX_HEIGHT][VNC_DIRTY_WORDS];
 -    char *old_data;
 -    int depth; /* internal VNC frame buffer byte per pixel */
 +    uint64_t *dirty_row;      /* screen regions which are possibly dirty */
 +    int dirty_pixel_shift;
 +    uint64_t *update_row;     /* outstanding updates */
 +    int has_update;           /* there's outstanding updates in the
 +                               * visible area */
 +
 +    int update_requested;       /* the client requested an update */
 +
 +    uint8_t *old_data;
-     int depth; /* internal VNC frame buffer byte per pixel */
      int has_resize;
      int has_hextile;
      int has_pointer_type_change;
      /* current output mode information */
      VncWritePixels *write_pixels;
      VncSendHextileTile *send_hextile_tile;
--    int pix_bpp, pix_big_endian;
-     int red_shift, red_max, red_shift1, red_max1;
-     int green_shift, green_max, green_shift1, green_max1;
-     int blue_shift, blue_max, blue_shift1, blue_max1;
 -    int client_red_shift, client_red_max, server_red_shift, server_red_max;
 -    int client_green_shift, client_green_max, server_green_shift, server_green_max;
 -    int client_blue_shift, client_blue_max, server_blue_shift, server_blue_max;
 -
 -    CaptureVoiceOut *audio_cap;
 -    struct audsettings as;
++    DisplaySurface clientds, serverds;
  
      VncReadEvent *read_handler;
      size_t read_handler_expect;
  };
  
  static VncState *vnc_state; /* needed for info vnc */
++static DisplayChangeListener *dcl;
 +
 +#define DIRTY_PIXEL_BITS 64
 +#define X2DP_DOWN(vs, x) ((x) >> (vs)->dirty_pixel_shift)
 +#define X2DP_UP(vs, x) \
 +  (((x) + (1ULL << (vs)->dirty_pixel_shift) - 1) >> (vs)->dirty_pixel_shift)
 +#define DP2X(vs, x) ((x) << (vs)->dirty_pixel_shift)
  
  void do_info_vnc(void)
  {
@@@ -268,18 -210,11 +269,18 @@@ static void vnc_write_s32(VncState *vs
  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_update_client(void *opaque);
  static void vnc_client_read(void *opaque);
 -
 -static void vnc_colordepth(DisplayState *ds, int depth);
 -
 +static void framebuffer_set_updated(VncState *vs, int x, int y, int w, int h);
 +static void pixel_format_message (VncState *vs);
 +static void enqueue_framebuffer_update(VncState *vs, int x, int y, int w, int h, int32_t encoding);
 +static void dequeue_framebuffer_update(VncState *vs);
 +static int is_empty_queue(VncState *vs);
 +static void free_queue(VncState *vs);
- static void vnc_colourdepth(DisplayState *ds, int depth);
++static void vnc_colordepth(DisplayState *ds);
 +
 +#if 0
  static inline void vnc_set_bit(uint32_t *d, int k)
  {
      d[k >> 5] |= 1 << (k & 0x1f);
@@@ -320,42 -255,29 +321,42 @@@ static inline int vnc_and_bits(const ui
      }
      return 0;
  }
 +#endif
  
 -static void vnc_dpy_update(DisplayState *ds, int x, int y, int w, int h)
 +static void set_bits_in_row(VncState *vs, uint64_t *row,
 +                          int x, int y, int w, int h)
  {
 -    VncState *vs = ds->opaque;
 -    int i;
 +    int x1, x2;
 +    uint64_t mask;
  
 -    h += y;
 +    if (w == 0)
 +      return;
  
 -    /* round x down to ensure the loop only spans one 16-pixel block per,
 -       iteration.  otherwise, if (x % 16) != 0, the last iteration may span
 -       two 16-pixel blocks but we only mark the first as dirty
 -    */
 -    w += (x % 16);
 -    x -= (x % 16);
 +    x1 = X2DP_DOWN(vs, x);
 +    x2 = X2DP_UP(vs, x + w);
  
 -    x = MIN(x, vs->width);
 -    y = MIN(y, vs->height);
 -    w = MIN(x + w, vs->width) - x;
 -    h = MIN(h, vs->height);
 +    if (X2DP_UP(vs, w) != DIRTY_PIXEL_BITS)
 +      mask = ((1ULL << (x2 - x1)) - 1) << x1;
 +    else
 +      mask = ~(0ULL);
  
-     if (h > vs->ds->height)
-         h = vs->ds->height;
 +    h += y;
++    if (h > ds_get_height(vs->ds))
++        h = ds_get_height(vs->ds);
      for (; y < h; y++)
 -      for (i = 0; i < w; i += 16)
 -          vnc_set_bit(vs->dirty_row[y], (x + i) / 16);
 +      row[y] |= mask;
 +}
 +
 +static void vnc_dpy_update(DisplayState *ds, int x, int y, int w, int h)
 +{
 +    VncState *vs = ds->opaque;
 +
-     x = MIN(x, vs->width);
-     y = MIN(y, vs->height);
-     w = MIN(w, vs->width - x);
-     h = MIN(h, vs->height - y);
++    x = MIN(x, vs->serverds.width);
++    y = MIN(y, vs->serverds.height);
++    w = MIN(w, vs->serverds.width - x);
++    h = MIN(h, vs->serverds.height - y);
 +
 +    set_bits_in_row(vs, vs->dirty_row, x, y, w, h);
  }
  
  static void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
      vnc_write_s32(vs, encoding);
  }
  
- static void vnc_dpy_resize_shared(DisplayState *ds, int w, int h, int depth, int linesize, void *pixels)
 -static void vnc_dpy_resize(DisplayState *ds, int w, int h)
++static void vnc_dpy_resize(DisplayState *ds)
  {
-     static int allocated;
      int size_changed;
      VncState *vs = ds->opaque;
 +    int o;
  
-     vnc_colourdepth(ds, depth);
-     if (!ds->shared_buf) {
-         ds->linesize = w * vs->depth;
-         if (allocated)
-             ds->data = qemu_realloc(ds->data,  h * ds->linesize);
-         else
-             ds->data = malloc(h * ds->linesize);
-         allocated = 1;
-     } else {
-         ds->linesize = linesize;
-         if (allocated) {
-             free(ds->data);
-             allocated = 0;
-         }
-     }
-     vs->old_data = qemu_realloc(vs->old_data, h * ds->linesize);
-     vs->dirty_row = qemu_realloc(vs->dirty_row, h * sizeof(vs->dirty_row[0]));
-     vs->update_row = qemu_realloc(vs->update_row, h * sizeof(vs->dirty_row[0]));
 -    ds->data = qemu_realloc(ds->data, w * h * vs->depth);
 -    vs->old_data = qemu_realloc(vs->old_data, w * h * vs->depth);
++    vs->old_data = qemu_realloc(vs->old_data, ds_get_height(ds) * ds_get_linesize(ds));
++    vs->dirty_row = qemu_realloc(vs->dirty_row, ds_get_height(ds) * sizeof(vs->dirty_row[0]));
++    vs->update_row = qemu_realloc(vs->update_row, ds_get_height(ds) * sizeof(vs->dirty_row[0]));
  
-     if (ds->data == NULL || vs->old_data == NULL ||
-       vs->dirty_row == NULL || vs->update_row == NULL) {
 -    if (ds->data == NULL || vs->old_data == NULL) {
++    if (vs->old_data == NULL || vs->dirty_row == NULL || vs->update_row == NULL) {
        fprintf(stderr, "vnc: memory allocation failed\n");
        exit(1);
      }
  
--    if (ds->depth != vs->depth * 8) {
--        ds->depth = vs->depth * 8;
++    if (ds_get_bytes_per_pixel(ds) != vs->serverds.pf.bytes_per_pixel)
          console_color_init(ds);
--    }
--    size_changed = ds->width != w || ds->height != h;
--    ds->width = w;
--    ds->height = h;
 -    ds->linesize = w * vs->depth;
 -    if (size_changed) {
 -        vs->width = ds->width;
 -        vs->height = ds->height;
 -        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);
++    vnc_colordepth(ds);
++    size_changed = ds_get_width(ds) != vs->serverds.width ||
++                   ds_get_height(ds) != vs->serverds.height;
++    vs->serverds = *(ds->surface);
 +    if (vs->csock != -1 && vs->has_resize && size_changed) {
-         vs->width = ds->width;
-         vs->height = ds->height;
 +        if (vs->update_requested) {
 +          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_framebuffer_update(vs, 0, 0, ds_get_width(ds), ds_get_height(ds), -223);
 +          vnc_flush(vs);
 +            vs->update_requested--;
 +        } else {
-             enqueue_framebuffer_update(vs, 0, 0, ds->width, ds->height, -223);
++            enqueue_framebuffer_update(vs, 0, 0, ds_get_width(ds), ds_get_height(ds), -223);
          }
      }
 -
 -    memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row));
 -    memset(vs->old_data, 42, ds_get_linesize(vs->ds) * ds_get_height(vs->ds));
 +    vs->dirty_pixel_shift = 0;
-     for (o = DIRTY_PIXEL_BITS; o < ds->width; o *= 2)
++    for (o = DIRTY_PIXEL_BITS; o < ds_get_width(ds); o *= 2)
 +      vs->dirty_pixel_shift++;
-     framebuffer_set_updated(vs, 0, 0, ds->width, ds->height);
-     if (ds->shared_buf) ds->data = pixels;
- }
- static void vnc_dpy_resize(DisplayState *ds, int w, int h)
- {
-     vnc_dpy_resize_shared(ds, w, h, 0, w * (ds->depth / 8), NULL);
++    framebuffer_set_updated(vs, 0, 0, ds_get_width(ds), ds_get_height(ds));
  }
  
  /* fastest code */
@@@ -445,29 -339,40 +420,40 @@@ static void vnc_convert_pixel(VncState 
  {
      uint8_t r, g, b;
  
-     r = ((v >> vs->red_shift1) & vs->red_max1) * (vs->red_max + 1) / (vs->red_max1 + 1);
-     g = ((v >> vs->green_shift1) & vs->green_max1) * (vs->green_max + 1) / (vs->green_max1 + 1);
-     b = ((v >> vs->blue_shift1) & vs->blue_max1) * (vs->blue_max + 1) / (vs->blue_max1 + 1);
 -    r = ((v >> vs->server_red_shift) & vs->server_red_max) * (vs->client_red_max + 1) /
 -        (vs->server_red_max + 1);
 -    g = ((v >> vs->server_green_shift) & vs->server_green_max) * (vs->client_green_max + 1) /
 -        (vs->server_green_max + 1);
 -    b = ((v >> vs->server_blue_shift) & vs->server_blue_max) * (vs->client_blue_max + 1) /
 -        (vs->server_blue_max + 1);
 -    v = (r << vs->client_red_shift) |
 -        (g << vs->client_green_shift) |
 -        (b << vs->client_blue_shift);
--    switch(vs->pix_bpp) {
++    r = ((((v & vs->serverds.pf.rmask) >> vs->serverds.pf.rshift) << vs->clientds.pf.rbits) >>
++        vs->serverds.pf.rbits);
++    g = ((((v & vs->serverds.pf.gmask) >> vs->serverds.pf.gshift) << vs->clientds.pf.gbits) >>
++        vs->serverds.pf.gbits);
++    b = ((((v & vs->serverds.pf.bmask) >> vs->serverds.pf.bshift) << vs->clientds.pf.bbits) >>
++        vs->serverds.pf.bbits);
++    v = (r << vs->clientds.pf.rshift) |
++        (g << vs->clientds.pf.gshift) |
++        (b << vs->clientds.pf.bshift);
++    switch(vs->clientds.pf.bytes_per_pixel) {
      case 1:
-         buf[0] = (r << vs->red_shift) | (g << vs->green_shift) | (b << vs->blue_shift);
 -        buf[0] = v;
++        buf[0] = v; 
          break;
      case 2:
-     {
-         uint16_t *p = (uint16_t *) buf;
-         *p = (r << vs->red_shift) | (g << vs->green_shift) | (b << vs->blue_shift);
--        if (vs->pix_big_endian) {
-             *p = htons(*p);
++        if (vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) {
+             buf[0] = v >> 8;
+             buf[1] = v;
+         } else {
+             buf[1] = v >> 8;
+             buf[0] = v;
          }
-     }
          break;
      default:
      case 4:
-     {
-         uint32_t *p = (uint32_t *) buf;
-         *p = (r << vs->red_shift) | (g << vs->green_shift) | (b << vs->blue_shift);
--        if (vs->pix_big_endian) {
-             *p = htonl(*p);
++        if (vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) {
+             buf[0] = v >> 24;
+             buf[1] = v >> 16;
+             buf[2] = v >> 8;
+             buf[3] = v;
+         } else {
+             buf[3] = v >> 24;
+             buf[2] = v >> 16;
+             buf[1] = v >> 8;
+             buf[0] = v;
          }
          break;
      }
@@@ -478,29 -382,29 +463,29 @@@ static void vnc_write_pixels_generic(Vn
  {
      uint8_t buf[4];
  
--    if (vs->depth == 4) {
++    if (vs->serverds.pf.bytes_per_pixel == 4) {
          uint32_t *pixels = pixels1;
          int n, i;
          n = size >> 2;
          for(i = 0; i < n; i++) {
              vnc_convert_pixel(vs, buf, pixels[i]);
--            vnc_write(vs, buf, vs->pix_bpp);
++            vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);
          }
--    } else if (vs->depth == 2) {
++    } else if (vs->serverds.pf.bytes_per_pixel == 2) {
          uint16_t *pixels = pixels1;
          int n, i;
          n = size >> 1;
          for(i = 0; i < n; i++) {
              vnc_convert_pixel(vs, buf, pixels[i]);
--            vnc_write(vs, buf, vs->pix_bpp);
++            vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);
          }
--    } else if (vs->depth == 1) {
++    } else if (vs->serverds.pf.bytes_per_pixel == 1) {
          uint8_t *pixels = pixels1;
          int n, i;
          n = size;
          for(i = 0; i < n; i++) {
              vnc_convert_pixel(vs, buf, pixels[i]);
--            vnc_write(vs, buf, vs->pix_bpp);
++            vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);
          }
      } else {
          fprintf(stderr, "vnc_write_pixels_generic: VncState color depth not supported\n");
@@@ -514,10 -418,10 +499,10 @@@ static void send_framebuffer_update_raw
  
      vnc_framebuffer_update(vs, x, y, w, h, 0);
  
-     row = vs->ds->data + y * vs->ds->linesize + x * vs->depth;
 -    row = ds_get_data(vs->ds) + y * ds_get_linesize(vs->ds) + x * vs->depth;
++    row = ds_get_data(vs->ds) + y * ds_get_linesize(vs->ds) + x * ds_get_bytes_per_pixel(vs->ds);
      for (i = 0; i < h; i++) {
--      vs->write_pixels(vs, row, w * vs->depth);
-       row += vs->ds->linesize;
++      vs->write_pixels(vs, row, w * ds_get_bytes_per_pixel(vs->ds));
+       row += ds_get_linesize(vs->ds);
      }
  }
  
@@@ -565,8 -469,8 +550,8 @@@ static void send_framebuffer_update_hex
  
      vnc_framebuffer_update(vs, x, y, w, h, 5);
  
-     last_fg = (void *) malloc(vs->depth);
-     last_bg = (void *) malloc(vs->depth);
 -    last_fg = (uint8_t *) malloc(vs->depth);
 -    last_bg = (uint8_t *) malloc(vs->depth);
++    last_fg = (void *) malloc(vs->serverds.pf.bytes_per_pixel);
++    last_bg = (void *) malloc(vs->serverds.pf.bytes_per_pixel);
      has_fg = has_bg = 0;
      for (j = y; j < (y + h); j += 16) {
        for (i = x; i < (x + w); i += 16) {
@@@ -589,66 -494,46 +574,35 @@@ static void send_framebuffer_update(Vnc
  
  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;
--    uint8_t *src_row;
--    uint8_t *dst_row;
-     uint8_t *old_row;
 -    char *old_row;
--    int y = 0;
-     int pitch = ds->linesize;
 -    int pitch = ds_get_linesize(ds);
      VncState *vs = ds->opaque;
 +    int updating_client = 1;
  
-     if (ds->shared_buf) {
-         framebuffer_set_updated(vs, dst_x, dst_y, w, h);
-         return;
 -    vnc_update_client(vs);
 -
 -    if (dst_y > src_y) {
 -      y = h - 1;
 -      pitch = -pitch;
--    }
 -
 -    src = (ds_get_linesize(ds) * (src_y + y) + vs->depth * src_x);
 -    dst = (ds_get_linesize(ds) * (dst_y + y) + vs->depth * dst_x);
--
 -    src_row = ds_get_data(ds) + src;
 -    dst_row = ds_get_data(ds) + dst;
 -    old_row = vs->old_data + dst;
 +    if (!vs->update_requested ||
 +        src_x < vs->visible_x || src_y < vs->visible_y ||
 +      dst_x < vs->visible_x || dst_y < vs->visible_y ||
 +      (src_x + w) > (vs->visible_x + vs->visible_w) ||
 +      (src_y + h) > (vs->visible_y + vs->visible_h) ||
 +      (dst_x + w) > (vs->visible_x + vs->visible_w) ||
 +      (dst_y + h) > (vs->visible_y + vs->visible_h))
 +      updating_client = 0;
  
 -    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;
 -    }
 +    if (updating_client)
-       _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_update_client(vs);
  
 -    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);
 +    if (updating_client && vs->csock != -1 && !vs->has_update) {
 +      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);
 +        vs->update_requested--;
 +    } else
 +      framebuffer_set_updated(vs, dst_x, dst_y, w, h);
  }
  
 -static int find_dirty_height(VncState *vs, int y, int last_x, int x)
 +static int find_update_height(VncState *vs, int y, int maxy, int last_x, int x)
  {
      int h;
  
      return h;
  }
  
 -static void vnc_update_client(void *opaque)
 +static void _vnc_update_client(void *opaque)
  {
      VncState *vs = opaque;
-     int tile_bytes = vs->depth * DP2X(vs, 1);
 +    int64_t now;
 +    int y;
 +    uint8_t *row;
 +    uint8_t *old_row;
 +    uint64_t width_mask;
 +    int n_rectangles;
 +    int saved_offset;
 +    int maxx, maxy;
++    int tile_bytes = vs->serverds.pf.bytes_per_pixel * DP2X(vs, 1);
 +
 +    if (!vs->update_requested || vs->csock == -1)
 +      return;
 +    while (!is_empty_queue(vs) && vs->update_requested) {
 +        int enc = vs->upqueue.queue_end->enc; 
 +        dequeue_framebuffer_update(vs);
 +        switch (enc) {
 +            case 0x574D5669:
 +                pixel_format_message(vs);
 +                break;
 +            default:
 +                break;
 +        }
 +        vs->update_requested--;
 +    }
 +    if (!vs->update_requested) return;
  
 -    if (vs->need_update && vs->csock != -1) {
 -      int y;
 -      uint8_t *row;
 -      char *old_row;
 -      uint32_t width_mask[VNC_DIRTY_WORDS];
 -      int n_rectangles;
 -      int saved_offset;
 -      int has_dirty = 0;
 -
 -        vga_hw_update();
 -
 -        vnc_set_bits(width_mask, (vs->width / 16), VNC_DIRTY_WORDS);
 -
 -      /* Walk through the dirty map and eliminate tiles that
 -         really aren't dirty */
 -      row = ds_get_data(vs->ds);
 -      old_row = vs->old_data;
 -
 -      for (y = 0; y < vs->height; y++) {
 -          if (vnc_and_bits(vs->dirty_row[y], width_mask, VNC_DIRTY_WORDS)) {
 -              int x;
 -              uint8_t *ptr;
 -              char *old_ptr;
 -
 -              ptr = row;
 -              old_ptr = (char*)old_row;
 -
 -              for (x = 0; x < ds_get_width(vs->ds); x += 16) {
 -                  if (memcmp(old_ptr, ptr, 16 * vs->depth) == 0) {
 -                      vnc_clear_bit(vs->dirty_row[y], (x / 16));
 -                  } else {
 -                      has_dirty = 1;
 -                      memcpy(old_ptr, ptr, 16 * vs->depth);
 -                  }
 +    now = qemu_get_clock(rt_clock);
  
-     if (vs->width != DP2X(vs, DIRTY_PIXEL_BITS))
-       width_mask = (1ULL << X2DP_UP(vs, vs->ds->width)) - 1;
 -                  ptr += 16 * vs->depth;
 -                  old_ptr += 16 * vs->depth;
 -              }
 -          }
++    if (vs->serverds.width != DP2X(vs, DIRTY_PIXEL_BITS))
++      width_mask = (1ULL << X2DP_UP(vs, ds_get_width(vs->ds))) - 1;
 +    else
 +      width_mask = ~(0ULL);
  
 -          row += ds_get_linesize(vs->ds);
 -          old_row += ds_get_linesize(vs->ds);
 -      }
 +    /* Walk through the dirty map and eliminate tiles that really
 +       aren't dirty */
-     row = vs->ds->data;
++    row = ds_get_data(vs->ds);
 +    old_row = vs->old_data;
  
-     for (y = 0; y < vs->ds->height; y++) {
 -      if (!has_dirty && !vs->audio_cap) {
 -          qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock) + VNC_REFRESH_INTERVAL);
 -          return;
 -      }
++    for (y = 0; y < ds_get_height(vs->ds); y++) {
 +      if (vs->dirty_row[y] & width_mask) {
 +          int x;
 +          uint8_t *ptr, *old_ptr;
  
 -      /* 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);
 +          ptr = row;
 +          old_ptr = old_row;
  
-           for (x = 0; x < X2DP_UP(vs, vs->ds->width); x++) {
 -      for (y = 0; y < vs->height; y++) {
 -          int x;
 -          int last_x = -1;
 -          for (x = 0; x < vs->width / 16; x++) {
 -              if (vnc_get_bit(vs->dirty_row[y], x)) {
 -                  if (last_x == -1) {
 -                      last_x = x;
++          for (x = 0; x < X2DP_UP(vs, ds_get_width(vs->ds)); x++) {
 +              if (vs->dirty_row[y] & (1ULL << x)) {
 +                  if (memcmp(old_ptr, ptr, tile_bytes)) {
 +                      vs->has_update = 1;
 +                      vs->update_row[y] |= (1ULL << x);
 +                      memcpy(old_ptr, ptr, tile_bytes);
                    }
 -                  vnc_clear_bit(vs->dirty_row[y], 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);
 +                  vs->dirty_row[y] &= ~(1ULL << x);
 +              }
 +
 +              ptr += tile_bytes;
 +              old_ptr += tile_bytes;
 +          }
 +      }
 +  
-       row += vs->ds->linesize;
-       old_row += vs->ds->linesize;
++      row += ds_get_linesize(vs->ds);
++      old_row += ds_get_linesize(vs->ds);
 +    }
 +
-     if (!vs->has_update || vs->visible_y >= vs->ds->height ||
-       vs->visible_x >= vs->ds->width)
++    if (!vs->has_update || vs->visible_y >= ds_get_height(vs->ds) ||
++      vs->visible_x >= ds_get_width(vs->ds))
 +      goto backoff;
 +
 +    /* 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);
 +    
 +    maxy = vs->visible_y + vs->visible_h;
-     if (maxy > vs->ds->height)
-       maxy = vs->ds->height;
++    if (maxy > ds_get_height(vs->ds))
++      maxy = ds_get_height(vs->ds);
 +    maxx = vs->visible_x + vs->visible_w;
-     if (maxx > vs->ds->width)
-       maxx = vs->ds->width;
++    if (maxx > ds_get_width(vs->ds))
++      maxx = ds_get_width(vs->ds);
 +
 +    for (y = vs->visible_y; y < maxy; y++) {
 +      int x;
 +      int last_x = -1;
 +      for (x = X2DP_DOWN(vs, vs->visible_x);
 +           x < X2DP_UP(vs, maxx); x++) {
 +          if (vs->update_row[y] & (1ULL << x)) {
 +              if (last_x == -1)
 +                  last_x = x;
 +              vs->update_row[y] &= ~(1ULL << x);
 +          } else {
 +              if (last_x != -1) {
 +                  int h = find_update_height(vs, y, maxy, last_x, x);
 +                  if (h != 0) {
 +                      send_framebuffer_update(vs, DP2X(vs, last_x), y,
 +                                              DP2X(vs, (x - last_x)), h);
                        n_rectangles++;
                    }
 -                  last_x = -1;
                }
 +              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);
 +      }
 +      if (last_x != -1) {
 +          int h = find_update_height(vs, y, maxy, last_x, x);
 +          if (h != 0) {
 +              send_framebuffer_update(vs, DP2X(vs, last_x), y,
 +                                      DP2X(vs, (x - last_x)), h);
                n_rectangles++;
            }
        }
 -      vs->output.buffer[saved_offset] = (n_rectangles >> 8) & 0xFF;
 -      vs->output.buffer[saved_offset + 1] = n_rectangles & 0xFF;
 -      vnc_flush(vs);
 -
      }
 +    vs->output.buffer[saved_offset] = (n_rectangles >> 8) & 0xFF;
 +    vs->output.buffer[saved_offset + 1] = n_rectangles & 0xFF;
  
 -    if (vs->csock != -1) {
 -        qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock) + VNC_REFRESH_INTERVAL);
 +    if (n_rectangles == 0) {
 +        vs->output.offset = saved_offset - 2;
 +      goto backoff;
 +    } else
 +        vs->update_requested--;
 +
 +    vs->has_update = 0;
 +    vnc_flush(vs);
 +    vs->last_update_time = now;
-     vs->ds->idle = 0;
++    dcl->idle = 0;
 +
 +    vs->timer_interval /= 2;
 +    if (vs->timer_interval < VNC_REFRESH_INTERVAL_BASE)
 +      vs->timer_interval = VNC_REFRESH_INTERVAL_BASE;
 +
 +    return;
 +
 + backoff:
 +    /* No update -> back off a bit */
 +    vs->timer_interval += VNC_REFRESH_INTERVAL_INC;
 +    if (vs->timer_interval > VNC_REFRESH_INTERVAL_MAX) {
 +      vs->timer_interval = VNC_REFRESH_INTERVAL_MAX;
 +      if (now - vs->last_update_time >= VNC_MAX_UPDATE_INTERVAL) {
 +            if (!vs->update_requested) {
-                 vs->ds->idle = 1;
++                dcl->idle = 1;
 +            } else {
 +                /* Send a null update.  If the client is no longer
 +                   interested (e.g. minimised) it'll ignore this, and we
 +                   can stop scanning the buffer until it sends another
 +                   update request. */
 +                /* It turns out that there's a bug in realvncviewer 4.1.2
 +                   which means that if you send a proper null update (with
 +                   no update rectangles), it gets a bit out of sync and
 +                   never sends any further requests, regardless of whether
 +                   it needs one or not.  Fix this by sending a single 1x1
 +                   update rectangle instead. */
 +                vnc_write_u8(vs, 0);
 +                vnc_write_u8(vs, 0);
 +                vnc_write_u16(vs, 1);
 +                send_framebuffer_update(vs, 0, 0, 1, 1);
 +                vnc_flush(vs);
 +                vs->last_update_time = now;
 +                vs->update_requested--;
 +                return;
 +            }
 +      }
      }
 +    qemu_mod_timer(vs->timer, now + vs->timer_interval);
 +    return;
 +}
 +
 +static void vnc_update_client(void *opaque)
 +{
 +    VncState *vs = opaque;
 +
 +    vga_hw_update();
 +    _vnc_update_client(vs);
 +}
  
 +static void vnc_timer_init(VncState *vs)
 +{
 +    if (vs->timer == NULL) {
 +      vs->timer = qemu_new_timer(rt_clock, vnc_update_client, vs);
 +      vs->timer_interval = VNC_REFRESH_INTERVAL_BASE;
 +    }
  }
  
  static int vnc_listen_poll(void *opaque)
@@@ -992,11 -770,10 +946,11 @@@ static int vnc_client_io_error(VncStat
        qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL);
        closesocket(vs->csock);
        vs->csock = -1;
--      vs->ds->idle = 1;
++      dcl->idle = 1;
        buffer_reset(&vs->input);
        buffer_reset(&vs->output);
 -      vs->need_update = 0;
 +        free_queue(vs);
 +        vs->update_requested = 0;
  #ifdef CONFIG_VNC_TLS
        if (vs->tls_session) {
            gnutls_deinit(vs->tls_session);
@@@ -1208,18 -984,12 +1162,18 @@@ static void client_cut_text(VncState *v
  static void check_pointer_type_change(VncState *vs, int absolute)
  {
      if (vs->has_pointer_type_change && vs->absolute != absolute) {
 -      vnc_write_u8(vs, 0);
 -      vnc_write_u8(vs, 0);
 -      vnc_write_u16(vs, 1);
 -      vnc_framebuffer_update(vs, absolute, 0,
 +        if (vs->update_requested) {
 +          vnc_write_u8(vs, 0);
 +          vnc_write_u8(vs, 0);
 +          vnc_write_u16(vs, 1);
 +          vnc_framebuffer_update(vs, absolute, 0,
-                              vs->ds->width, vs->ds->height, -257);
+                              ds_get_width(vs->ds), ds_get_height(vs->ds), -257);
 -      vnc_flush(vs);
 +          vnc_flush(vs);
 +            vs->update_requested--;
 +        } else {
 +            enqueue_framebuffer_update(vs, absolute, 0,
-                                vs->ds->width, vs->ds->height, -257);
++                               ds_get_width(vs->ds), ds_get_height(vs->ds), -257);
 +        }
      }
      vs->absolute = absolute;
  }
@@@ -1241,8 -1011,8 +1195,8 @@@ static void pointer_event(VncState *vs
        dz = 1;
  
      if (vs->absolute) {
-         kbd_mouse_event(x * 0x7FFF / (vs->ds->width - 1),
-                         y * 0x7FFF / (vs->ds->height - 1),
 -      kbd_mouse_event(x * 0x7FFF / (ds_get_width(vs->ds) - 1),
 -                      y * 0x7FFF / (ds_get_height(vs->ds) - 1),
++        kbd_mouse_event(x * 0x7FFF / (ds_get_width(vs->ds) - 1),
++                        y * 0x7FFF / (ds_get_height(vs->ds) - 1),
                        dz, buttons);
      } else if (vs->has_pointer_type_change) {
        x -= 0x7FFF;
@@@ -1568,7 -1226,7 +1522,7 @@@ static void set_encodings(VncState *vs
      vs->has_pointer_type_change = 0;
      vs->has_WMVi = 0;
      vs->absolute = -1;
--    vs->ds->dpy_copy = NULL;
++    dcl->dpy_copy = NULL;
  
      for (i = n_encodings - 1; i >= 0; i--) {
        switch (encodings[i]) {
            vs->has_hextile = 0;
            break;
        case 1: /* CopyRect */
--          vs->ds->dpy_copy = vnc_copy;
++          dcl->dpy_copy = vnc_copy;
            break;
        case 5: /* Hextile */
            vs->has_hextile = 1;
      check_pointer_type_change(vs, kbd_mouse_is_absolute());
  }
  
++static void set_pixel_conversion(VncState *vs)
++{
++    if ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) ==
++        (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG) && 
++        !memcmp(&(vs->clientds.pf), &(vs->ds->surface->pf), sizeof(PixelFormat))) {
++        vs->write_pixels = vnc_write_pixels_copy;
++        switch (vs->ds->surface->pf.bits_per_pixel) {
++            case 8:
++                vs->send_hextile_tile = send_hextile_tile_8;
++                break;
++            case 16:
++                vs->send_hextile_tile = send_hextile_tile_16;
++                break;
++            case 32:
++                vs->send_hextile_tile = send_hextile_tile_32;
++                break;
++        }
++    } else {
++        vs->write_pixels = vnc_write_pixels_generic;
++        switch (vs->ds->surface->pf.bits_per_pixel) {
++            case 8:
++                vs->send_hextile_tile = send_hextile_tile_generic_8;
++                break;
++            case 16:
++                vs->send_hextile_tile = send_hextile_tile_generic_16;
++                break;
++            case 32:
++                vs->send_hextile_tile = send_hextile_tile_generic_32;
++                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)
  {
--    int host_big_endian_flag;
--
--#ifdef WORDS_BIGENDIAN
--    host_big_endian_flag = 1;
--#else
--    host_big_endian_flag = 0;
--#endif
      if (!true_color_flag) {
--    fail:
        vnc_client_error(vs);
          return;
      }
--    if (bits_per_pixel == 32 &&
-         bits_per_pixel == vs->depth * 8 && 
 -        bits_per_pixel == vs->depth * 8 &&
--        host_big_endian_flag == big_endian_flag &&
--        red_max == 0xff && green_max == 0xff && blue_max == 0xff &&
--        red_shift == 16 && green_shift == 8 && blue_shift == 0) {
 -        vs->depth = 4;
--        vs->write_pixels = vnc_write_pixels_copy;
--        vs->send_hextile_tile = send_hextile_tile_32;
-     } else 
 -    } else
--    if (bits_per_pixel == 16 &&
--        bits_per_pixel == vs->depth * 8 && 
--        host_big_endian_flag == big_endian_flag &&
--        red_max == 31 && green_max == 63 && blue_max == 31 &&
--        red_shift == 11 && green_shift == 5 && blue_shift == 0) {
 -        vs->depth = 2;
--        vs->write_pixels = vnc_write_pixels_copy;
--        vs->send_hextile_tile = send_hextile_tile_16;
-     } else 
-     if (bits_per_pixel == 8 && 
 -    } else
 -    if (bits_per_pixel == 8 &&
--        bits_per_pixel == vs->depth * 8 &&
--        red_max == 7 && green_max == 7 && blue_max == 3 &&
--        red_shift == 5 && green_shift == 2 && blue_shift == 0) {
--        vs->depth = 1;
--        vs->write_pixels = vnc_write_pixels_copy;
--        vs->send_hextile_tile = send_hextile_tile_8;
-     } else 
 -    } else
--    {
--        /* generic and slower case */
--        if (bits_per_pixel != 8 &&
--            bits_per_pixel != 16 &&
--            bits_per_pixel != 32)
--            goto fail;
--        if (vs->depth == 4) {
--            vs->send_hextile_tile = send_hextile_tile_generic_32;
--        } else if (vs->depth == 2) {
-             vs->send_hextile_tile = send_hextile_tile_generic_16;
 -           vs->send_hextile_tile = send_hextile_tile_generic_16;
--        } else {
--            vs->send_hextile_tile = send_hextile_tile_generic_8;
--        }
-             
 -
--        vs->pix_big_endian = big_endian_flag;
--        vs->write_pixels = vnc_write_pixels_generic;
--    }
-  
-     vs->red_shift = red_shift;
-     vs->red_max = red_max;
-     vs->green_shift = green_shift;
-     vs->green_max = green_max;
-     vs->blue_shift = blue_shift;
-     vs->blue_max = blue_max;
-     vs->pix_bpp = bits_per_pixel / 8;
 -    vs->client_red_shift = red_shift;
 -    vs->client_red_max = red_max;
 -    vs->client_green_shift = green_shift;
 -    vs->client_green_max = green_max;
 -    vs->client_blue_shift = blue_shift;
 -    vs->client_blue_max = blue_max;
 -    vs->pix_bpp = bits_per_pixel / 8;
++    vs->clientds = vs->serverds;
++    vs->clientds.pf.rmax = red_max;
++    count_bits(vs->clientds.pf.rbits, red_max);
++    vs->clientds.pf.rshift = red_shift;
++    vs->clientds.pf.rmask = red_max << red_shift;
++    vs->clientds.pf.gmax = green_max;
++    count_bits(vs->clientds.pf.gbits, green_max);
++    vs->clientds.pf.gshift = green_shift;
++    vs->clientds.pf.gmask = green_max << green_shift;
++    vs->clientds.pf.bmax = blue_max;
++    count_bits(vs->clientds.pf.bbits, blue_max);
++    vs->clientds.pf.bshift = blue_shift;
++    vs->clientds.pf.bmask = blue_max << blue_shift;
++    vs->clientds.pf.bits_per_pixel = bits_per_pixel;
++    vs->clientds.pf.bytes_per_pixel = bits_per_pixel / 8;
++    vs->clientds.pf.depth = bits_per_pixel == 32 ? 24 : bits_per_pixel;
++    vs->clientds.flags = big_endian_flag ? QEMU_BIG_ENDIAN_FLAG : 0x00;
++
++    set_pixel_conversion(vs);
+     vga_hw_invalidate();
+     vga_hw_update();
  }
  
  static void pixel_format_message (VncState *vs) {
      char pad[3] = { 0, 0, 0 };
  
--    vnc_write_u8(vs, vs->depth * 8); /* bits-per-pixel */
--    if (vs->depth == 4) vnc_write_u8(vs, 24); /* depth */
--    else vnc_write_u8(vs, vs->depth * 8); /* depth */
++    vnc_write_u8(vs, vs->ds->surface->pf.bits_per_pixel); /* bits-per-pixel */
++    vnc_write_u8(vs, vs->ds->surface->pf.depth); /* depth */
  
  #ifdef WORDS_BIGENDIAN
      vnc_write_u8(vs, 1);             /* big-endian-flag */
      vnc_write_u8(vs, 0);             /* big-endian-flag */
  #endif
      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 */
++    vnc_write_u16(vs, vs->ds->surface->pf.rmax);     /* red-max */
++    vnc_write_u16(vs, vs->ds->surface->pf.gmax);     /* green-max */
++    vnc_write_u16(vs, vs->ds->surface->pf.bmax);     /* blue-max */
++    vnc_write_u8(vs, vs->ds->surface->pf.rshift);    /* red-shift */
++    vnc_write_u8(vs, vs->ds->surface->pf.gshift);    /* green-shift */
++    vnc_write_u8(vs, vs->ds->surface->pf.bshift);    /* blue-shift */
++    if (vs->ds->surface->pf.bits_per_pixel == 32)
          vs->send_hextile_tile = send_hextile_tile_32;
--    } 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->ds->surface->pf.bits_per_pixel == 16)
          vs->send_hextile_tile = send_hextile_tile_16;
--    } else if (vs->depth == 1) {
--        /* XXX: change QEMU pixel 8 bit pixel format to match the VNC one ? */
--        vnc_write_u16(vs, 7);        /* 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 */
++    else if (vs->ds->surface->pf.bits_per_pixel == 8)
          vs->send_hextile_tile = send_hextile_tile_8;
--    }
-     vs->red_max = vs->red_max1;
-     vs->green_max = vs->green_max1;
-     vs->blue_max = vs->blue_max1;
-     vs->red_shift = vs->red_shift1;
-     vs->green_shift = vs->green_shift1;
-     vs->blue_shift = vs->blue_shift1;
 -    vs->client_red_max = vs->server_red_max;
 -    vs->client_green_max = vs->server_green_max;
 -    vs->client_blue_max = vs->server_blue_max;
 -    vs->client_red_shift = vs->server_red_shift;
 -    vs->client_green_shift = vs->server_green_shift;
 -    vs->client_blue_shift = vs->server_blue_shift;
--    vs->pix_bpp = vs->depth * 8;
++    vs->clientds = *(vs->ds->surface);
++    vs->clientds.flags &= ~QEMU_ALLOCATED_FLAG;
      vs->write_pixels = vnc_write_pixels_copy;
-         
      vnc_write(vs, pad, 3);           /* padding */
  }
  
- static void vnc_dpy_setdata(DisplayState *ds, void *pixels)
 -static void vnc_colordepth(DisplayState *ds, int depth)
++static void vnc_dpy_setdata(DisplayState *ds)
  {
-     ds->data = pixels;
 -    int host_big_endian_flag;
 -    struct VncState *vs = ds->opaque;
 -
 -    switch (depth) {
 -        case 24:
 -            if (ds->depth == 32) return;
 -            depth = 32;
 -            break;
 -        case 15:
 -        case 8:
 -        case 0:
 -            return;
 -        default:
 -            break;
 -    }
++    /* We don't have to do anything */
 +}
  
- static void vnc_colourdepth(DisplayState *ds, int depth)
 -#ifdef WORDS_BIGENDIAN
 -    host_big_endian_flag = 1;
 -#else
 -    host_big_endian_flag = 0;
 -#endif   
 -    
 -    switch (depth) {
 -        case 8:
 -            vs->depth = depth / 8;
 -            vs->server_red_max = 7;
 -            vs->server_green_max = 7;
 -            vs->server_blue_max = 3;
 -            vs->server_red_shift = 5;
 -            vs->server_green_shift = 2;
 -            vs->server_blue_shift = 0;
 -            break;
 -        case 16:
 -            vs->depth = depth / 8;
 -            vs->server_red_max = 31;
 -            vs->server_green_max = 63;
 -            vs->server_blue_max = 31;
 -            vs->server_red_shift = 11;
 -            vs->server_green_shift = 5;
 -            vs->server_blue_shift = 0;
 -            break;
 -        case 32:
 -            vs->depth = 4;
 -            vs->server_red_max = 255;
 -            vs->server_green_max = 255;
 -            vs->server_blue_max = 255;
 -            vs->server_red_shift = 16;
 -            vs->server_green_shift = 8;
 -            vs->server_blue_shift = 0;
 -            break;
 -        default:
 -            return;
 -    }
++static void vnc_colordepth(DisplayState *ds)
 +{
-     int host_big_endian_flag;
 +    struct VncState *vs = ds->opaque;
  
-     switch (depth) {
-         case 24:
-             ds->shared_buf = 0;
-             if (ds->depth == 32) return;
-             depth = 32;
-             break;
-         case 8:
-         case 0:
-             ds->shared_buf = 0;
-             return;
-         default:
-             ds->shared_buf = 1;
-             break;
-     }
- #ifdef WORDS_BIGENDIAN
-     host_big_endian_flag = 1;
- #else
-     host_big_endian_flag = 0;
- #endif   
-     
-     switch (depth) {
-         case 8:
-             vs->depth = depth / 8;
-             vs->red_max1 = 7;
-             vs->green_max1 = 7;
-             vs->blue_max1 = 3;
-             vs->red_shift1 = 5;
-             vs->green_shift1 = 2;
-             vs->blue_shift1 = 0;
-             break;
-         case 16:
-             vs->depth = depth / 8;
-             vs->red_max1 = 31;
-             vs->green_max1 = 63;
-             vs->blue_max1 = 31;
-             vs->red_shift1 = 11;
-             vs->green_shift1 = 5;
-             vs->blue_shift1 = 0;
-             break;
-         case 32:
-             vs->depth = 4;
-             vs->red_max1 = 255;
-             vs->green_max1 = 255;
-             vs->blue_max1 = 255;
-             vs->red_shift1 = 16;
-             vs->green_shift1 = 8;
-             vs->blue_shift1 = 0;
-             break;
-         default:
-             return;
-     }
 -    if (vs->csock != -1 && vs->has_WMVi) {
 +    if (vs->switchbpp) {
 +        vnc_client_error(vs);
 +    } else if (vs->csock != -1 && vs->has_WMVi) {
          /* Sending a WMVi message to notify the client*/
 -        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, 0x574D5669);
 -        pixel_format_message(vs);
 -        vnc_flush(vs);
 -    } else {
 -        if (vs->pix_bpp == 4 && vs->depth == 4 &&
 -                host_big_endian_flag == vs->pix_big_endian &&
 -                vs->client_red_max == 0xff && vs->client_green_max == 0xff && vs->client_blue_max == 0xff &&
 -                vs->client_red_shift == 16 && vs->client_green_shift == 8 && vs->client_blue_shift == 0) {
 -            vs->write_pixels = vnc_write_pixels_copy;
 -            vs->send_hextile_tile = send_hextile_tile_32;
 -        } else if (vs->pix_bpp == 2 && vs->depth == 2 &&
 -                host_big_endian_flag == vs->pix_big_endian &&
 -                vs->client_red_max == 31 && vs->client_green_max == 63 && vs->client_blue_max == 31 &&
 -                vs->client_red_shift == 11 && vs->client_green_shift == 5 && vs->client_blue_shift == 0) {
 -            vs->write_pixels = vnc_write_pixels_copy;
 -            vs->send_hextile_tile = send_hextile_tile_16;
 -        } else if (vs->pix_bpp == 1 && vs->depth == 1 &&
 -                host_big_endian_flag == vs->pix_big_endian &&
 -                vs->client_red_max == 7 && vs->client_green_max == 7 && vs->client_blue_max == 3 &&
 -                vs->client_red_shift == 5 && vs->client_green_shift == 2 && vs->client_blue_shift == 0) {
 -            vs->write_pixels = vnc_write_pixels_copy;
 -            vs->send_hextile_tile = send_hextile_tile_8;
 +        if (vs->update_requested) {
 +            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, 0x574D5669);
++            vnc_framebuffer_update(vs, 0, 0, ds_get_width(ds), ds_get_height(ds), 0x574D5669);
 +            pixel_format_message(vs);
 +            vnc_flush(vs);
 +            vs->update_requested--;
          } else {
-             enqueue_framebuffer_update(vs, 0, 0, ds->width, ds->height, 0x574D5669);
 -            if (vs->depth == 4) {
 -                vs->send_hextile_tile = send_hextile_tile_generic_32;
 -            } else if (vs->depth == 2) {
 -                vs->send_hextile_tile = send_hextile_tile_generic_16;
 -            } else {
 -                vs->send_hextile_tile = send_hextile_tile_generic_8;
 -            }
 -            vs->write_pixels = vnc_write_pixels_generic;
++            enqueue_framebuffer_update(vs, 0, 0, ds_get_width(ds), ds_get_height(ds), 0x574D5669);
          }
-         if (vs->pix_bpp == 4 && vs->depth == 4 &&
-             host_big_endian_flag == vs->pix_big_endian &&
-             vs->red_max == 0xff && vs->green_max == 0xff && vs->blue_max == 0xff &&
-             vs->red_shift == 16 && vs->green_shift == 8 && vs->blue_shift == 0) {
-             vs->write_pixels = vnc_write_pixels_copy;
-             vs->send_hextile_tile = send_hextile_tile_32;
-         } else if (vs->pix_bpp == 2 && vs->depth == 2 &&
-             host_big_endian_flag == vs->pix_big_endian &&
-             vs->red_max == 31 && vs->green_max == 63 && vs->blue_max == 31 &&
-             vs->red_shift == 11 && vs->green_shift == 5 && vs->blue_shift == 0) {
-             vs->write_pixels = vnc_write_pixels_copy;
-             vs->send_hextile_tile = send_hextile_tile_16;
-         } else if (vs->pix_bpp == 1 && vs->depth == 1 &&
-             host_big_endian_flag == vs->pix_big_endian &&
-             vs->red_max == 7 && vs->green_max == 7 && vs->blue_max == 3 &&
-             vs->red_shift == 5 && vs->green_shift == 2 && vs->blue_shift == 0) {
-             vs->write_pixels = vnc_write_pixels_copy;
-             vs->send_hextile_tile = send_hextile_tile_8;
-         } else {
-             if (vs->depth == 4) {
-                 vs->send_hextile_tile = send_hextile_tile_generic_32;
-             } else if (vs->depth == 2) {
-                 vs->send_hextile_tile = send_hextile_tile_generic_16;
-             } else {
-                 vs->send_hextile_tile = send_hextile_tile_generic_8;
-             }
-             vs->write_pixels = vnc_write_pixels_generic;
-         }
 +    } else {
++        set_pixel_conversion(vs);
      }
  }
  
@@@ -1912,14 -1621,13 +1765,12 @@@ static int protocol_client_msg(VncStat
  
  static int protocol_client_init(VncState *vs, uint8_t *data, size_t len)
  {
 -    char buf[1024];
 -    int size;
 +    size_t l;
 +
 +    vga_hw_update();
  
-     vs->width = vs->ds->width;
-     vs->height = vs->ds->height;
-     vnc_write_u16(vs, vs->ds->width);
-     vnc_write_u16(vs, vs->ds->height);
 -    vs->width = ds_get_width(vs->ds);
 -    vs->height = ds_get_height(vs->ds);
+     vnc_write_u16(vs, ds_get_width(vs->ds));
+     vnc_write_u16(vs, ds_get_height(vs->ds));
  
      pixel_format_message(vs);
  
@@@ -2535,19 -2263,7 +2386,19 @@@ static void vnc_listen_read(void *opaqu
  
      vs->csock = accept(vs->lsock, (struct sockaddr *)&addr, &addrlen);
      if (vs->csock != -1) {
 -        vnc_connect(vs);
 +      VNC_DEBUG("New client on socket %d\n", vs->csock);
-       vs->ds->idle = 0;
++      dcl->idle = 0;
 +        socket_set_nonblock(vs->csock);
 +      qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, opaque);
 +      vnc_write(vs, "RFB 003.008\n", 12);
 +      vnc_flush(vs);
 +      vnc_read_when(vs, protocol_version, 12);
-       framebuffer_set_updated(vs, 0, 0, vs->ds->width, vs->ds->height);
++      framebuffer_set_updated(vs, 0, 0, ds_get_width(vs->ds), ds_get_height(vs->ds));
 +      vs->has_resize = 0;
 +      vs->has_hextile = 0;
 +        vs->update_requested = 0;
-       vs->ds->dpy_copy = NULL;
++      dcl->dpy_copy = NULL;
 +      vnc_timer_init(vs);
      }
  }
  
@@@ -2558,11 -2272,11 +2409,12 @@@ void vnc_display_init(DisplayState *ds
      VncState *vs;
  
      vs = qemu_mallocz(sizeof(VncState));
--    if (!vs)
++    dcl = qemu_mallocz(sizeof(DisplayChangeListener));
++    if (!vs || !dcl)
        exit(1);
  
      ds->opaque = vs;
--    ds->idle = 1;
++    dcl->idle = 1;
      vnc_state = vs;
      vs->display = NULL;
      vs->password = NULL;
  
      vs->ds = ds;
  
 -    if (keyboard_layout)
 -        vs->kbd_layout = init_keyboard_layout(keyboard_layout);
 -    else
 -        vs->kbd_layout = init_keyboard_layout("en-us");
 +    if (!keyboard_layout)
 +      keyboard_layout = "en-us";
  
 +    vs->kbd_layout = init_keyboard_layout(keyboard_layout);
      if (!vs->kbd_layout)
        exit(1);
 +    vs->modifiers_state[0x45] = 1; /* NumLock on - on boot */
  
 -    vs->timer = qemu_new_timer(rt_clock, vnc_update_client, vs);
 -
--    vs->ds->data = NULL;
--    vs->ds->dpy_update = vnc_dpy_update;
--    vs->ds->dpy_resize = vnc_dpy_resize;
-     vs->ds->dpy_setdata = vnc_dpy_setdata;
-     vs->ds->dpy_resize_shared = vnc_dpy_resize_shared;
--    vs->ds->dpy_refresh = NULL;
--
-     vs->ds->width = 640;
-     vs->ds->height = 400;
-     vs->ds->linesize = 640 * 4;
-     vnc_dpy_resize_shared(ds, ds->width, ds->height, 24, ds->linesize, NULL);
 -    vnc_colordepth(vs->ds, 32);
 -    vnc_dpy_resize(vs->ds, 640, 400);
 -
 -    vs->as.freq = 44100;
 -    vs->as.nchannels = 2;
 -    vs->as.fmt = AUD_FMT_S16;
 -    vs->as.endianness = 0;
++    dcl->dpy_update = vnc_dpy_update;
++    dcl->dpy_resize = vnc_dpy_resize;
++    dcl->dpy_setdata = vnc_dpy_setdata;
++    dcl->dpy_refresh = NULL;
++    register_displaychangelistener(ds, dcl);
  }
  
  #ifdef CONFIG_VNC_TLS
diff --cc vnchextile.h
Simple merge
diff --cc xen-vl-extra.c
index d9e11fb70f2b5c05c347ad362091a138b20df072,0000000000000000000000000000000000000000..d01bf4715b8c56175945e0e0931901189debb9af
mode 100644,000000..100644
--- /dev/null
@@@ -1,102 -1,0 +1,133 @@@
 +/*
 + * We #include this from vl.c.
 + *
 + * This is a bit yucky, but it means that the line numbers and other
 + * textual differences in vl.c remain small.
 + */
 +/* There is no need for multiple-inclusion protection since
 + * there is only one place where this file is included. */
 +
 +#include "qemu-xen.h"
 +
 +/* We use simpler state save/load functions for Xen */
 +
 +void do_savevm(const char *name)
 +{
 +    QEMUFile *f;
 +    int saved_vm_running, ret;
 +
 +    f = qemu_fopen(name, "wb");
 +    
 +    /* ??? Should this occur after vm_stop?  */
 +    qemu_aio_flush();
 +
 +    saved_vm_running = vm_running;
 +    vm_stop(0);
 +
 +    if (!f) {
 +        fprintf(logfile, "Failed to open savevm file '%s'\n", name);
 +        goto the_end;
 +    }
 +    
 +    ret = qemu_savevm_state(f);
 +    qemu_fclose(f);
 +
 +    if (ret < 0)
 +        fprintf(logfile, "Error %d while writing VM to savevm file '%s'\n",
 +                ret, name);
 +
 + the_end:
 +    if (saved_vm_running)
 +        vm_start();
 +
 +    return;
 +}
 +void do_loadvm(const char *name)
 +{
 +    QEMUFile *f;
 +    int saved_vm_running, ret;
 +
 +    /* Flush all IO requests so they don't interfere with the new state.  */
 +    qemu_aio_flush();
 +
 +    saved_vm_running = vm_running;
 +    vm_stop(0);
 +
 +    /* restore the VM state */
 +    f = qemu_fopen(name, "rb");
 +    if (!f) {
 +        fprintf(logfile, "Could not open VM state file\n");
 +        goto the_end;
 +    }
 +
 +    ret = qemu_loadvm_state(f);
 +    qemu_fclose(f);
 +    if (ret < 0) {
 +        fprintf(logfile, "Error %d while loading savevm file '%s'\n",
 +                ret, name);
 +        goto the_end; 
 +    }
 +
 +#if 0 
 +    /* del tmp file */
 +    if (unlink(name) == -1)
 +        fprintf(stderr, "delete tmp qemu state file failed.\n");
 +#endif
 +
 +
 + the_end:
 +    if (saved_vm_running)
 +        vm_start();
 +}
 +
 +struct qemu_alarm_timer;
 +static int unix_start_timer(struct qemu_alarm_timer *t) { return 0; }
 +static void unix_stop_timer(struct qemu_alarm_timer *t) { }
 +
 +#ifdef CONFIG_STUBDOM
 +#include <netfront.h>
 +static int tap_open(char *ifname, int ifname_size)
 +{
 +    char nodename[64];
 +    static int num = 1; // 0 is for our own TCP/IP networking
 +    snprintf(nodename, sizeof(nodename), "device/vif/%d", num++);
 +    return netfront_tap_open(nodename);
 +}
 +
 +#undef DEFAULT_NETWORK_SCRIPT
 +#define DEFAULT_NETWORK_SCRIPT ""
 +#undef DEFAULT_NETWORK_DOWN_SCRIPT
 +#define DEFAULT_NETWORK_DOWN_SCRIPT ""
 +#endif
 +
++#ifdef CONFIG_PASSTHROUGH
++void do_pci_del(char *devname)
++{
++    int pci_slot;
++    pci_slot = bdf_to_slot(devname);
++
++    acpi_php_del(pci_slot);
++}
++
++void do_pci_add(char *devname)
++{
++    int pci_slot;
++
++    pci_slot = insert_to_pci_slot(devname);
++
++    acpi_php_add(pci_slot);
++}
++
++static int pci_emulation_add(char *config_text)
++{
++    PCI_EMULATION_INFO *new;
++    if ((new = qemu_mallocz(sizeof(PCI_EMULATION_INFO))) == NULL) {
++        return -1;
++    }
++    parse_pci_emulation_info(config_text, new);
++    new->next = PciEmulationInfoHead;
++    PciEmulationInfoHead = new;
++    return 0;
++}
++
++#endif