diff --git a/qemu-fix-display-breakage.patch b/qemu-fix-display-breakage.patch new file mode 100644 index 0000000..d2e6de1 --- /dev/null +++ b/qemu-fix-display-breakage.patch @@ -0,0 +1,543 @@ +From 8ad63a93a482d5c3354b97463633394456a157d5 Mon Sep 17 00:00:00 2001 +From: Avi Kivity +Date: Thu, 2 Apr 2009 22:17:50 +0300 +Subject: [PATCH 1/1] kvm: qemu: Fix display breakage when resizing the screen + +When the vga resolution changes, a new display surface is not allocated +immediately; instead that is deferred until the next update. However, +if we're running without a display client attached, that won't happen +and the next bitblt is likely to cause a segfault by overflowing the +display surface. + +Fix by reallocating the display immediately when the resolution changes. + +Signed-off-by: Avi Kivity +--- + qemu/hw/cirrus_vga.c | 10 ++- + qemu/hw/vga.c | 205 +++++++++++++++++++++++++++++-------------------- + qemu/hw/vga_int.h | 4 + + 3 files changed, 134 insertions(+), 85 deletions(-) + +diff --git a/qemu/hw/cirrus_vga.c b/qemu/hw/cirrus_vga.c +index 0ab0f14..7bd0482 100644 +--- a/qemu/hw/cirrus_vga.c ++++ b/qemu/hw/cirrus_vga.c +@@ -1399,6 +1399,8 @@ cirrus_hook_write_sr(CirrusVGAState * s, unsigned reg_index, int reg_value) + break; + } + ++ vga_update_resolution((VGAState *)s); ++ + return CIRRUS_HOOK_HANDLED; + } + +@@ -1426,6 +1428,7 @@ static void cirrus_write_hidden_dac(CirrusVGAState * s, int reg_value) + #endif + } + s->cirrus_hidden_dac_lockindex = 0; ++ vga_update_resolution((VGAState *)s); + } + + /*************************************** +@@ -1712,6 +1715,8 @@ cirrus_hook_write_cr(CirrusVGAState * s, unsigned reg_index, int reg_value) + break; + } + ++ vga_update_resolution((VGAState *)s); ++ + return CIRRUS_HOOK_HANDLED; + } + +@@ -2839,6 +2844,7 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) + if (s->ar_flip_flop == 0) { + val &= 0x3f; + s->ar_index = val; ++ vga_update_resolution((VGAState *)s); + } else { + index = s->ar_index & 0x1f; + switch (index) { +@@ -2932,6 +2938,7 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) + /* can always write bit 4 of CR7 */ + if (s->cr_index == 7) + s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10); ++ vga_update_resolution((VGAState *)s); + return; + } + switch (s->cr_index) { +@@ -3166,7 +3173,8 @@ static int cirrus_vga_load(QEMUFile *f, void *opaque, int version_id) + + cirrus_update_memory_access(s); + /* force refresh */ +- s->graphic_mode = -1; ++ vga_update_resolution((VGAState *)s); ++ s->want_full_update = 1; + cirrus_update_bank_ptr(s, 0); + cirrus_update_bank_ptr(s, 1); + return 0; +diff --git a/qemu/hw/vga.c b/qemu/hw/vga.c +index d4fddf9..9a950d3 100644 +--- a/qemu/hw/vga.c ++++ b/qemu/hw/vga.c +@@ -37,6 +37,10 @@ + + //#define DEBUG_BOCHS_VBE + ++#define GMODE_TEXT 0 ++#define GMODE_GRAPH 1 ++#define GMODE_BLANK 2 ++ + /* force some bits to zero */ + const uint8_t sr_mask[8] = { + (uint8_t)~0xfc, +@@ -394,6 +398,7 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) + if (s->ar_flip_flop == 0) { + val &= 0x3f; + s->ar_index = val; ++ vga_update_resolution(s); + } else { + index = s->ar_index & 0x1f; + switch(index) { +@@ -434,6 +439,7 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) + #endif + s->sr[s->sr_index] = val & sr_mask[s->sr_index]; + if (s->sr_index == 1) s->update_retrace_info(s); ++ vga_update_resolution(s); + break; + case 0x3c7: + s->dac_read_index = val; +@@ -461,6 +467,7 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) + printf("vga: write GR%x = 0x%02x\n", s->gr_index, val); + #endif + s->gr[s->gr_index] = val & gr_mask[s->gr_index]; ++ vga_update_resolution(s); + break; + case 0x3b4: + case 0x3d4: +@@ -476,6 +483,7 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) + /* can always write bit 4 of CR7 */ + if (s->cr_index == 7) + s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10); ++ vga_update_resolution(s); + return; + } + switch(s->cr_index) { +@@ -503,6 +511,7 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) + s->update_retrace_info(s); + break; + } ++ vga_update_resolution(s); + break; + case 0x3ba: + case 0x3da: +@@ -582,11 +591,13 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) + if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) { + s->vbe_regs[s->vbe_index] = val; + } ++ vga_update_resolution(s); + break; + case VBE_DISPI_INDEX_YRES: + if (val <= VBE_DISPI_MAX_YRES) { + s->vbe_regs[s->vbe_index] = val; + } ++ vga_update_resolution(s); + break; + case VBE_DISPI_INDEX_BPP: + if (val == 0) +@@ -595,6 +606,7 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) + val == 16 || val == 24 || val == 32) { + s->vbe_regs[s->vbe_index] = val; + } ++ vga_update_resolution(s); + break; + case VBE_DISPI_INDEX_BANK: + if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) { +@@ -663,6 +675,7 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) + } + s->dac_8bit = (val & VBE_DISPI_8BIT_DAC) > 0; + s->vbe_regs[s->vbe_index] = val; ++ vga_update_resolution(s); + break; + case VBE_DISPI_INDEX_VIRT_WIDTH: + { +@@ -683,6 +696,7 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) + s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h; + s->vbe_line_offset = line_offset; + } ++ vga_update_resolution(s); + break; + case VBE_DISPI_INDEX_X_OFFSET: + case VBE_DISPI_INDEX_Y_OFFSET: +@@ -697,6 +711,7 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) + s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3); + s->vbe_start_addr >>= 2; + } ++ vga_update_resolution(s); + break; + default: + break; +@@ -1300,7 +1315,6 @@ static void vga_draw_text(VGAState *s, int full_update) + s->plane_updated = 0; + full_update = 1; + } +- full_update |= update_basic_params(s); + + line_offset = s->line_offset; + s1 = s->vram_ptr + (s->start_addr * 4); +@@ -1312,18 +1326,6 @@ static void vga_draw_text(VGAState *s, int full_update) + return; + } + +- if (width != s->last_width || height != s->last_height || +- cw != s->last_cw || cheight != s->last_ch || s->last_depth) { +- 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->rgb_to_pixel = + rgb_to_pixel_dup_table[get_depth_index(s->ds)]; + full_update |= update_palette16(s); +@@ -1580,40 +1582,20 @@ static void vga_sync_dirty_bitmap(VGAState *s) + vga_dirty_log_start(s); + } + +-/* +- * graphic modes +- */ +-static void vga_draw_graphic(VGAState *s, int full_update) ++static void vga_update_resolution_graphics(VGAState *s) + { +- int y1, y, update, linesize, y_start, double_scan, mask, depth; +- int width, height, shift_control, line_offset, bwidth, bits; ++ int depth = s->get_bpp(s); ++ int width, height, shift_control, double_scan; + int disp_width, multi_scan, multi_run; +- uint8_t *d; +- uint32_t v, addr1, addr; +- long page0, page1, page_min, page_max; +- vga_draw_line_func *vga_draw_line; +- +- full_update |= update_basic_params(s); +- +- if (!full_update) +- vga_sync_dirty_bitmap(s); + + s->get_resolution(s, &width, &height); +- disp_width = width; + + shift_control = (s->gr[0x05] >> 5) & 3; + double_scan = (s->cr[0x09] >> 7); +- if (shift_control != 1) { +- multi_scan = (((s->cr[0x09] & 0x1f) + 1) << double_scan) - 1; +- } else { +- /* in CGA modes, multi_scan is ignored */ +- /* XXX: is it correct ? */ +- multi_scan = double_scan; +- } +- multi_run = multi_scan; ++ + if (shift_control != s->shift_control || + double_scan != s->double_scan) { +- full_update = 1; ++ s->want_full_update = 1; + s->shift_control = shift_control; + s->double_scan = double_scan; + } +@@ -1627,12 +1609,25 @@ static void vga_draw_graphic(VGAState *s, int full_update) + disp_width <<= 1; + } + } ++ disp_width = width; ++ ++ if (shift_control != 1) { ++ multi_scan = (((s->cr[0x09] & 0x1f) + 1) << double_scan) - 1; ++ } else { ++ /* in CGA modes, multi_scan is ignored */ ++ /* XXX: is it correct ? */ ++ multi_scan = double_scan; ++ } ++ ++ multi_run = multi_scan; + +- depth = s->get_bpp(s); + if (s->line_offset != s->last_line_offset || + disp_width != s->last_width || + height != s->last_height || +- s->last_depth != depth) { ++ s->last_depth != depth || ++ s->multi_run != multi_run || ++ s->multi_scan != multi_scan || ++ s->want_full_update) { + #if defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) + if (depth == 16 || depth == 32) { + #else +@@ -1659,8 +1654,74 @@ static void vga_draw_graphic(VGAState *s, int full_update) + 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) && ++ s->multi_run = multi_run; ++ s->multi_scan = multi_scan; ++ s->want_full_update = 1; ++ } ++} ++ ++static void vga_update_resolution_text(VGAState *s) ++{ ++ int width, height, cw, cheight; ++ ++ vga_get_text_resolution(s, &width, &height, &cw, &cheight); ++ if (width != s->last_width || height != s->last_height || ++ cw != s->last_cw || cheight != s->last_ch || s->last_depth) { ++ 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; ++ s->want_full_update = 1; ++ } ++} ++ ++void vga_update_resolution(VGAState *s) ++{ ++ int graphic_mode; ++ ++ if (!(s->ar_index & 0x20)) { ++ graphic_mode = GMODE_BLANK; ++ } else { ++ graphic_mode = s->gr[6] & 1; ++ } ++ if (graphic_mode != s->graphic_mode) { ++ s->graphic_mode = graphic_mode; ++ s->want_full_update = 1; ++ } ++ s->want_full_update |= update_basic_params(s); ++ switch (graphic_mode) { ++ case GMODE_TEXT: ++ vga_update_resolution_text(s); ++ break; ++ case GMODE_GRAPH: ++ vga_update_resolution_graphics(s); ++ break; ++ } ++} ++ ++/* ++ * graphic modes ++ */ ++static void vga_draw_graphic(VGAState *s, int full_update) ++{ ++ int y1, y, update, linesize, y_start, mask; ++ int width, height, line_offset, bwidth, bits; ++ int multi_run; ++ uint8_t *d; ++ uint32_t v, addr1, addr; ++ long page0, page1, page_min, page_max; ++ vga_draw_line_func *vga_draw_line; ++ ++ if (!full_update) ++ vga_sync_dirty_bitmap(s); ++ ++ s->get_resolution(s, &width, &height); ++ multi_run = s->multi_run; ++ 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); +@@ -1669,7 +1730,7 @@ static void vga_draw_graphic(VGAState *s, int full_update) + s->rgb_to_pixel = + rgb_to_pixel_dup_table[get_depth_index(s->ds)]; + +- if (shift_control == 0) { ++ if (s->shift_control == 0) { + full_update |= update_palette16(s); + if (s->sr[0x01] & 8) { + v = VGA_DRAW_LINE4D2; +@@ -1677,7 +1738,7 @@ static void vga_draw_graphic(VGAState *s, int full_update) + v = VGA_DRAW_LINE4; + } + bits = 4; +- } else if (shift_control == 1) { ++ } else if (s->shift_control == 1) { + full_update |= update_palette16(s); + if (s->sr[0x01] & 8) { + v = VGA_DRAW_LINE2D2; +@@ -1773,7 +1834,7 @@ static void vga_draw_graphic(VGAState *s, int full_update) + if (y_start >= 0) { + /* flush to display */ + dpy_update(s->ds, 0, y_start, +- disp_width, y - y_start); ++ s->last_width, y - y_start); + y_start = -1; + } + } +@@ -1782,7 +1843,7 @@ static void vga_draw_graphic(VGAState *s, int full_update) + if ((y1 & mask) == mask) + addr1 += line_offset; + y1++; +- multi_run = multi_scan; ++ multi_run = s->multi_scan; + } else { + multi_run--; + } +@@ -1794,7 +1855,7 @@ static void vga_draw_graphic(VGAState *s, int full_update) + if (y_start >= 0) { + /* flush to display */ + dpy_update(s->ds, 0, y_start, +- disp_width, y - y_start); ++ s->last_width, y - y_start); + } + /* reset modified pages */ + if (page_max != -1) { +@@ -1831,29 +1892,17 @@ static void vga_draw_blank(VGAState *s, int full_update) + s->last_scr_width, s->last_scr_height); + } + +-#define GMODE_TEXT 0 +-#define GMODE_GRAPH 1 +-#define GMODE_BLANK 2 +- + static void vga_update_display(void *opaque) + { + VGAState *s = (VGAState *)opaque; +- int full_update, graphic_mode; ++ int full_update; + + if (ds_get_bits_per_pixel(s->ds) == 0) { + /* nothing to do */ + } else { +- full_update = 0; +- if (!(s->ar_index & 0x20)) { +- graphic_mode = GMODE_BLANK; +- } else { +- graphic_mode = s->gr[6] & 1; +- } +- if (graphic_mode != s->graphic_mode) { +- s->graphic_mode = graphic_mode; +- full_update = 1; +- } +- switch(graphic_mode) { ++ full_update = s->want_full_update; ++ s->want_full_update = 0; ++ switch(s->graphic_mode) { + case GMODE_TEXT: + vga_draw_text(s, full_update); + break; +@@ -1876,8 +1925,8 @@ static void vga_invalidate_display(void *opaque) + { + VGAState *s = (VGAState *)opaque; + +- s->last_width = -1; +- s->last_height = -1; ++ vga_update_resolution(s); ++ s->want_full_update = 1; + } + + void vga_reset(void *opaque) +@@ -1921,7 +1970,6 @@ void vga_reset(void *opaque) + s->vbe_bank_mask = (s->vram_size >> 16) - 1; + #endif + memset(s->font_offsets, '\0', sizeof(s->font_offsets)); +- s->graphic_mode = -1; /* force full update */ + s->shift_control = 0; + s->double_scan = 0; + s->line_offset = 0; +@@ -1947,6 +1995,7 @@ void vga_reset(void *opaque) + memset(&s->retrace_info, 0, sizeof (s->retrace_info)); + break; + } ++ vga_update_resolution(s); + } + + #define TEXTMODE_X(x) ((x) % width) +@@ -1965,24 +2014,9 @@ static void vga_update_text(void *opaque, console_ch_t *chardata) + char msg_buffer[80]; + int full_update = 0; + +- if (!(s->ar_index & 0x20)) { +- graphic_mode = GMODE_BLANK; +- } else { +- graphic_mode = s->gr[6] & 1; +- } +- if (graphic_mode != s->graphic_mode) { +- s->graphic_mode = graphic_mode; +- full_update = 1; +- } +- if (s->last_width == -1) { +- s->last_width = 0; +- full_update = 1; +- } +- + switch (graphic_mode) { + case GMODE_TEXT: + /* TODO: update palette */ +- full_update |= update_basic_params(s); + + /* total width & height */ + cheight = (s->cr[9] & 0x1f) + 1; +@@ -2224,7 +2258,8 @@ static int vga_load(QEMUFile *f, void *opaque, int version_id) + #endif + + /* force refresh */ +- s->graphic_mode = -1; ++ vga_update_resolution(s); ++ s->want_full_update = 1; + return 0; + } + +@@ -2418,7 +2453,8 @@ void vga_bios_init(VGAState *s) + memcpy(s->palette, palette_model, 192); + + s->bank_offset = 0; +- s->graphic_mode = -1; ++ vga_update_resolution(s); ++ s->want_full_update = 1; + + /* TODO: add vbe support if enabled */ + } +@@ -2803,7 +2839,8 @@ static void vga_screen_dump_common(VGAState *s, const char *filename, + ds->surface = qemu_create_displaysurface(w, h, 32, 4 * w); + + s->ds = ds; +- s->graphic_mode = -1; ++ vga_update_resolution(s); ++ s->want_full_update = 1; + vga_update_display(s); + + ppm_save(filename, ds->surface); +diff --git a/qemu/hw/vga_int.h b/qemu/hw/vga_int.h +index 8ba8a60..71ffeb5 100644 +--- a/qemu/hw/vga_int.h ++++ b/qemu/hw/vga_int.h +@@ -147,8 +147,11 @@ typedef void (* vga_update_retrace_info_fn)(struct VGAState *s); + DisplayState *ds; \ + uint32_t font_offsets[2]; \ + int graphic_mode; \ ++ int want_full_update; \ + uint8_t shift_control; \ + uint8_t double_scan; \ ++ uint8_t multi_run; \ ++ uint8_t multi_scan; \ + uint32_t line_offset; \ + uint32_t line_compare; \ + uint32_t start_addr; \ +@@ -195,6 +198,7 @@ void vga_common_init(VGAState *s, 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_update_resolution(VGAState *s); + + void vga_dirty_log_start(VGAState *s); + void vga_dirty_log_stop(VGAState *s); +-- +1.6.0.6 + diff --git a/qemu.spec b/qemu.spec index 2a89c0d..9f87c6e 100644 --- a/qemu.spec +++ b/qemu.spec @@ -1,7 +1,7 @@ Summary: QEMU is a FAST! processor emulator Name: qemu Version: 0.10 -Release: 4%{?dist} +Release: 5%{?dist} # I have mistakenly thought the revision name would be 1.0. # So 0.10 series get Epoch = 1 Epoch: 2 @@ -35,6 +35,7 @@ Patch10: qemu-fix-debuginfo.patch Patch11: qemu-fix-gcc.patch Patch12: qemu-roms-more-room.patch Patch13: qemu-bios-bigger-roms.patch +Patch14: qemu-fix-display-breakage.patch BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) BuildRequires: SDL-devel zlib-devel which texi2html gnutls-devel cyrus-sasl-devel @@ -212,6 +213,7 @@ such as kvmtrace and kvm_stat. %patch11 -p1 %patch12 -p1 %patch13 -p1 +%patch14 -p1 %build # systems like rhel build system does not have a recent enough linker so @@ -231,8 +233,6 @@ else fi %ifarch %{ix86} x86_64 -# build kvm -echo "%{name}-%{version}" > $(pwd)/kernel/.kernelrelease # sdl outputs to alsa or pulseaudio directly depending on what the system has configured # alsa works, but causes huge CPU load due to bugs # oss works, but is very problematic because it grabs exclusive control of the device causing other apps to go haywire @@ -244,7 +244,7 @@ echo "%{name}-%{version}" > $(pwd)/kernel/.kernelrelease --qemu-ldflags=$extraldflags \ --qemu-cflags="$RPM_OPT_FLAGS" -make %{?_smp_mflags} $buildldflags +make V=1 %{?_smp_mflags} $buildldflags cp qemu/x86_64-softmmu/qemu-system-x86_64 qemu-kvm cp user/kvmtrace . cp user/kvmtrace_format . @@ -455,6 +455,11 @@ fi %{_mandir}/man1/qemu-img.1* %changelog +* Fri Apr 3 2009 Mark McLoughlin - 2:0.10-5 +- Fix vga segfault under kvm-autotest (#494002) +- Kill kernelrelease hack; it's not needed +- Build with "make V=1" for more verbose logs + * Thu Apr 02 2009 Glauber Costa - 2:0.10-4 - Support botting gpxe roms.