From: Ian Jackson Date: Thu, 12 Mar 2009 17:29:18 +0000 (+0000) Subject: Merge branch 'qemu' X-Git-Tag: xen-3.4.0-rc2~71 X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=149b4ff3ca594f66719d415bafec74f11d1a3051;p=qemu-xen-4.0-testing.git Merge branch 'qemu' 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 --- 149b4ff3ca594f66719d415bafec74f11d1a3051 diff --cc .gitignore index 9e3690a8,34079433..fb0617cf --- a/.gitignore +++ b/.gitignore @@@ -32,15 -31,8 +31,18 @@@ qemu-nbd.po *.vr *.d *.o +*.orig *~ + + .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 - dyngen-xen +dist - - i386-dm/gdbstub-xml.c diff --cc Makefile index e31fe822,4db9dcc8..c8314c69 --- a/Makefile +++ 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 0d1ea15d,a97edd7b..7e9cbda6 --- a/Makefile.target +++ b/Makefile.target @@@ -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 block-raw-posix.c index 0237039a,7a895b45..4c1fec4c --- a/block-raw-posix.c +++ b/block-raw-posix.c @@@ -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 console.c index 85945491,4e088d7a..147daf16 --- a/console.c +++ 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; @@@ -533,8 -556,8 +550,7 @@@ 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++) { @@@ -586,8 -626,8 +610,8 @@@ 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; @@@ -1187,27 -1224,27 +1230,40 @@@ 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; @@@ -1253,6 -1292,6 +1311,7 @@@ 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; @@@ -1280,32 -1340,32 +1360,247 @@@ 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 cutils.c index 97d6080d,9617e083..6136e8dc --- a/cutils.c +++ 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 hw/cirrus_vga.c index e1a416b8,f9ad4795..cb22c389 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@@ -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; + uint8_t vga_acc = 0; - uint64_t t; int ret; - if (version_id > 2) + if (version_id > 3) return -EINVAL; if (s->pci_dev && version_id >= 2) { @@@ -3151,28 -3163,7 +3197,29 @@@ 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_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, 2, cirrus_vga_save, cirrus_vga_load, 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; + pci_conf[0x2c] = 0x53; /* subsystem vendor: XenSource */ + pci_conf[0x2d] = 0x58; + pci_conf[0x2e] = 0x01; /* subsystem device */ + pci_conf[0x2f] = 0x00; + - /* setup VGA */ - s = &d->cirrus_vga; + 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/ide.c index da7057ca,41f94d95..42920b07 --- a/hw/ide.c +++ b/hw/ide.c @@@ -2907,103 -2755,6 +2938,46 @@@ static void ide_reset(IDEState *s s->media_changed = 0; } +/* 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); +} + - - 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; - } - static void ide_init2(IDEState *ide_state, BlockDriverState *hd0, BlockDriverState *hd1, qemu_irq irq) diff --cc hw/iommu.c index 0ad697de,82a49328..b4ca11a0 --- a/hw/iommu.c +++ b/hw/iommu.c @@@ -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 */ +#if defined(__i386__) || defined(__x86_64__) - #define PAGE_SHIFT 12 + #define IOMMU_PAGE_SHIFT 12 +#elif defined(__ia64__) - #define PAGE_SHIFT 14 ++#define IOMMU_PAGE_SHIFT 14 +#endif - #define PAGE_SIZE (1 << PAGE_SHIFT) - #define PAGE_MASK (PAGE_SIZE - 1) + #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 5f13f799,9f50dcbd..db2882df --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@@ -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 } diff --cc hw/mips_mipssim.c index 4c636dbb,83f1a63e..2c48b00e --- a/hw/mips_mipssim.c +++ b/hw/mips_mipssim.c @@@ -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 670a1eab,c12ab54b..9bf748d2 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@@ -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 0d131183,a85730f8..0cb1c4aa --- a/hw/ne2000.c +++ b/hw/ne2000.c @@@ -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 f0492c8a,d64e4426..2ffbefdb --- a/hw/pc.c +++ b/hw/pc.c @@@ -32,10 -32,11 +32,14 @@@ #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 */ @@@ -1138,12 -1086,28 +1141,35 @@@ } } + 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 a6000003,5dc77098..0a8f8e3d --- a/hw/pc.h +++ 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 e72c6694,62b957a2..50b40093 --- a/hw/pci.c +++ b/hw/pci.c @@@ -25,10 -25,8 +25,11 @@@ #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 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 int pci_irq_index; 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 a527a397,76f4474a..7645cd43 --- a/hw/pci.h +++ 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/rtl8139.c index c464d6f6,70cb080d..31913f51 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@@ -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 974a826b,87bcf3d8..d7999834 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@@ -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 +#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/sun4u.c index 216629f6,91e7538d..ed8ab508 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@@ -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 4e4e1e14,76fdce69..4f793e95 --- a/hw/usb-hid.c +++ b/hw/usb-hid.c @@@ -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 d1d61ea1,bf84c246..13519255 --- a/hw/vga.c +++ 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; @@@ -1319,24 -1304,8 +1316,24 @@@ 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; @@@ -1346,7 -1315,7 +1343,7 @@@ 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; } + if (shift_control == 1 && (s->sr[0x01] & 8)) { + disp_width <<= 1; + } + - ds_depth = s->ds->depth; ++ ds_depth = ds_get_bits_per_pixel(s->ds); + depth = s->get_bpp(s); - 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); ++ 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); @@@ -1696,9 -1670,18 +1705,9 @@@ 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; @@@ -1757,10 -1692,10 +1766,10 @@@ 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; @@@ -1788,15 -1723,13 +1797,15 @@@ 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); + /* 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 (s->ds->depth == 8) + 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; @@@ -2061,7 -2056,7 +2072,9 @@@ 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; @@@ -2517,26 -2255,17 +2530,24 @@@ 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; @@@ -2611,15 -2415,38 +2622,15 @@@ 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, @@@ -2628,7 -2455,7 +2639,7 @@@ 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) { @@@ -2643,13 -2470,12 +2654,13 @@@ 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; @@@ -2686,79 -2507,125 +2697,86 @@@ /********************************************************/ /* 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 d914b62e,39b7367d..c9be893d --- a/hw/vga_int.h +++ b/hw/vga_int.h @@@ -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 loader.c index 173cea11,8ecb61d5..de5c6230 --- a/loader.c +++ 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 nbd.c index a9b9401f,77b3e169..9d2fcd3a --- a/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 00000000,86ee7d54..99430155 mode 000000,100644..100644 --- a/net.c +++ b/net.c @@@ -1,0 -1,1806 +1,1846 @@@ + /* + * 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 + #include + #include + #include + #include + #include + #include + + #ifndef _WIN32 + #include + #include + #include + #include + #include + #include + #include + #include + #include + #ifdef __NetBSD__ + #include + #endif + #ifdef __linux__ + #include + #endif + #include + #include + #include + #include + #ifdef _BSD + #include + #ifdef __FreeBSD__ + #include + #else + #include + #endif + #elif defined (__GLIBC__) && defined (__FreeBSD_kernel__) + #include + #else + #ifdef __linux__ + #include + #include + #include + + /* For the benefit of older linux systems which don't supply it, + we use a local copy of hpet.h. */ + /* #include */ + #include "hpet.h" + + #include + #include + #endif + #ifdef __sun__ + #include + #include + #include + #include + #include + #include + #include + #include // must come after ip.h + #include + #include + #include + #include + #include + #endif + #endif + #endif + + #include "qemu_socket.h" + + #if defined(CONFIG_SLIRP) + #include "libslirp.h" + #endif + + #if defined(__OpenBSD__) + #include + #endif + + #if defined(CONFIG_VDE) + #include + #endif + + #ifdef _WIN32 + #include + #include + #include + #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 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 '~') + 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; + } + -static int get_str_sep(char *buf, int buf_size, const char **pp, int sep) ++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 *)𝔦 + 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; + } -#else ++#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 + -static int launch_script(const char *setup_script, const char *ifname, int fd) ++static int launch_script(const char *setup_script, const char *ifname, ++ const char *script_arg, int fd) + { + int pid, status; - char *args[3]; ++ 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, - const char *setup_script, const char *down_script) ++ 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') { - if (launch_script(setup_script, ifname, fd)) ++ 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]; - char setup_script[1024], down_script[1024]; ++ 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); + } - ret = net_tap_init(vlan, device, name, ifname, setup_script, 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 0d7ce779,291807a6..1662724c --- a/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 qemu-char.c index 00000000,0a01e16d..054bea95 mode 000000,100644..100644 --- a/qemu-char.c +++ b/qemu-char.c @@@ -1,0 -1,2216 +1,2226 @@@ + /* + * 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 + #include + #include + #include + #include + #include + #include + + #ifndef _WIN32 + #include + #include + #include + #include + #include + #include + #include + #include + #include + #ifdef __NetBSD__ + #include + #endif + #ifdef __linux__ + #include + #endif + #include + #include + #include + #include + #ifdef _BSD + #include + #ifdef __FreeBSD__ + #include + #include + #include + #else + #include + #endif + #elif defined (__GLIBC__) && defined (__FreeBSD_kernel__) + #include + #else + #ifdef __linux__ + #include + + #include + #include + #endif + #ifdef __sun__ + #include + #include + #include + #include + #include + #include + #include + #include // must come after ip.h + #include + #include + #include + #include + #include + #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 _WIN32 ++#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 savevm.c index 00000000,729e8497..3dc887d2 mode 000000,100644..100644 --- a/savevm.c +++ 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 + #include + #include + #include + #include + #include + #include + + #ifndef _WIN32 + #include + #include + #include + #include + #include + #include + #include + #include + #include + #if defined(__NetBSD__) + #include + #endif + #ifdef __linux__ + #include + #endif + #include + #include + #include + #include + #ifdef _BSD + #include + #ifdef __FreeBSD__ + #include + #else + #include + #endif + #elif defined (__GLIBC__) && defined (__FreeBSD_kernel__) + #include + #else + #ifdef __linux__ + #include + #include + #include + #endif + #endif + #endif + + #ifdef _WIN32 + #include + #include + #include + #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 9afd8840,2ce6e815..e9256732 --- a/sdl.c +++ b/sdl.c @@@ -31,12 -31,7 +31,13 @@@ #include #endif -static SDL_Surface *screen; +#ifdef CONFIG_OPENGL +#include +#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; @@@ -537,7 -342,7 +437,7 @@@ 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: @@@ -722,30 -523,18 +622,30 @@@ !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 6b3dd838,55f8d79d..2bb6c3f6 --- a/sysemu.h +++ b/sysemu.h @@@ -123,8 -126,7 +126,8 @@@ extern unsigned int nb_prom_envs #endif typedef enum { + IF_BLKTAP, - IF_IDE, IF_SCSI, IF_FLOPPY, IF_PFLASH, IF_MTD, IF_SD + IF_IDE, IF_SCSI, IF_FLOPPY, IF_PFLASH, IF_MTD, IF_SD, IF_VIRTIO } BlockInterfaceType; typedef struct DriveInfo { diff --cc vl.c index dd5d155b,2452d0f7..7be1ade8 --- a/vl.c +++ b/vl.c @@@ -38,13 -36,14 +38,16 @@@ #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 +#include #include #include #include @@@ -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" @@@ -8454,11 -3956,12 +4015,15 @@@ "-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, @@@ -8577,8 -4074,8 +4146,9 @@@ 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 }, @@@ -8684,15 -4177,9 +4259,16 @@@ { "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 { @@@ -9094,7 -4559,8 +4689,7 @@@ 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; @@@ -9638,13 -5093,10 +5268,13 @@@ 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"); @@@ -9858,18 -5310,9 +5502,9 @@@ 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; @@@ -9896,26 -5339,15 +5531,31 @@@ 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) { @@@ -10083,20 -5491,46 +5727,57 @@@ } } + 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 02d3b1d1,e1ff4edd..52e46274 --- a/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; @@@ -214,10 -165,13 +217,7 @@@ /* 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; @@@ -232,12 -180,6 +232,13 @@@ }; 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); + h += y; - if (h > vs->ds->height) - h = vs->ds->height; ++ 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, @@@ -369,69 -291,41 +370,43 @@@ 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; @@@ -663,190 -548,100 +617,190 @@@ return h; } -static void vnc_update_client(void *opaque) +static void _vnc_update_client(void *opaque) { VncState *vs = opaque; + 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->depth * DP2X(vs, 1); ++ 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]) { @@@ -1576,7 -1234,7 +1530,7 @@@ 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; @@@ -1597,81 -1262,86 +1551,79 @@@ 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 */ @@@ -1679,150 -1349,137 +1631,51 @@@ 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); } + } else { - 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; - } ++ 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; @@@ -2574,25 -2288,28 +2426,19 @@@ 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 xen-vl-extra.c index d9e11fb7,00000000..d01bf471 mode 100644,000000..100644 --- a/xen-vl-extra.c +++ b/xen-vl-extra.c @@@ -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 +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