diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2017-10-19 10:53:19 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2017-10-19 10:53:19 +0100 |
commit | 73b733e6907e1193e562f498272108c95c00868c (patch) | |
tree | 7fb8e53203ed2b441225e65a9bc209e7b97f8d8c | |
parent | 861cd431c99e56ddb5953ca1da164a9c32b477ca (diff) | |
parent | eb38e1bc3740725ca29a535351de94107ec58d51 (diff) |
Merge remote-tracking branch 'remotes/kraxel/tags/vga-20171017-pull-request' into staging
cirrus: bugfixes, with some vga cleanups.
# gpg: Signature made Tue 17 Oct 2017 09:24:37 BST
# gpg: using RSA key 0x4CB6D8EED3E87138
# gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>"
# gpg: aka "Gerd Hoffmann <gerd@kraxel.org>"
# gpg: aka "Gerd Hoffmann (private) <kraxel@gmail.com>"
# Primary key fingerprint: A032 8CFF B93A 17A7 9901 FE7D 4CB6 D8EE D3E8 7138
* remotes/kraxel/tags/vga-20171017-pull-request:
cirrus: fix oob access in mode4and5 write functions
vga: add ram_addr_t cast
vga: handle cirrus vbe mode wraparounds.
vga: drop line_offset variable
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r-- | hw/display/cirrus_vga.c | 6 | ||||
-rw-r--r-- | hw/display/vga.c | 33 |
2 files changed, 25 insertions, 14 deletions
diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c index b4d579857a..bc32bf1e39 100644 --- a/hw/display/cirrus_vga.c +++ b/hw/display/cirrus_vga.c @@ -2038,15 +2038,14 @@ static void cirrus_mem_writeb_mode4and5_8bpp(CirrusVGAState * s, unsigned val = mem_value; uint8_t *dst; - dst = s->vga.vram_ptr + (offset &= s->cirrus_addr_mask); for (x = 0; x < 8; x++) { + dst = s->vga.vram_ptr + ((offset + x) & s->cirrus_addr_mask); if (val & 0x80) { *dst = s->cirrus_shadow_gr1; } else if (mode == 5) { *dst = s->cirrus_shadow_gr0; } val <<= 1; - dst++; } memory_region_set_dirty(&s->vga.vram, offset, 8); } @@ -2060,8 +2059,8 @@ static void cirrus_mem_writeb_mode4and5_16bpp(CirrusVGAState * s, unsigned val = mem_value; uint8_t *dst; - dst = s->vga.vram_ptr + (offset &= s->cirrus_addr_mask); for (x = 0; x < 8; x++) { + dst = s->vga.vram_ptr + ((offset + 2 * x) & s->cirrus_addr_mask & ~1); if (val & 0x80) { *dst = s->cirrus_shadow_gr1; *(dst + 1) = s->vga.gr[0x11]; @@ -2070,7 +2069,6 @@ static void cirrus_mem_writeb_mode4and5_16bpp(CirrusVGAState * s, *(dst + 1) = s->vga.gr[0x10]; } val <<= 1; - dst += 2; } memory_region_set_dirty(&s->vga.vram, offset, 16); } diff --git a/hw/display/vga.c b/hw/display/vga.c index ed24ef7076..1d19f6bc48 100644 --- a/hw/display/vga.c +++ b/hw/display/vga.c @@ -1464,14 +1464,14 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) { DisplaySurface *surface = qemu_console_surface(s->con); int y1, y, update, linesize, y_start, double_scan, mask, depth; - int width, height, shift_control, line_offset, bwidth, bits; - ram_addr_t page0, page1; + int width, height, shift_control, bwidth, bits; + ram_addr_t page0, page1, region_start, region_end; DirtyBitmapSnapshot *snap = NULL; int disp_width, multi_scan, multi_run; uint8_t *d; uint32_t v, addr1, addr; vga_draw_line_func *vga_draw_line = NULL; - bool share_surface; + bool share_surface, force_shadow = false; pixman_format_code_t format; #ifdef HOST_WORDS_BIGENDIAN bool byteswap = !s->big_endian_fb; @@ -1484,6 +1484,15 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) s->get_resolution(s, &width, &height); disp_width = width; + region_start = (s->start_addr * 4); + region_end = region_start + (ram_addr_t)s->line_offset * height; + if (region_end > s->vbe_size) { + /* wraps around (can happen with cirrus vbe modes) */ + region_start = 0; + region_end = s->vbe_size; + force_shadow = true; + } + shift_control = (s->gr[VGA_GFX_MODE] >> 5) & 3; double_scan = (s->cr[VGA_CRTC_MAX_SCAN] >> 7); if (shift_control != 1) { @@ -1523,7 +1532,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) format = qemu_default_pixman_format(depth, !byteswap); if (format) { share_surface = dpy_gfx_check_format(s->con, format) - && !s->force_shadow; + && !s->force_shadow && !force_shadow; } else { share_surface = false; } @@ -1614,7 +1623,6 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) s->cursor_invalidate(s); } - line_offset = s->line_offset; #if 0 printf("w=%d h=%d v=%d line_offset=%d cr[0x09]=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=0x%02x\n", width, height, v, line_offset, s->cr[9], s->cr[VGA_CRTC_MODE], @@ -1628,8 +1636,6 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) y1 = 0; if (!full_update) { - ram_addr_t region_start = addr1; - ram_addr_t region_end = addr1 + line_offset * height; vga_sync_dirty_bitmap(s); if (s->line_compare < height) { /* split screen mode */ @@ -1652,10 +1658,17 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) addr = (addr & ~0x8000) | ((y1 & 2) << 14); } update = full_update; - page0 = addr; - page1 = addr + bwidth - 1; + page0 = addr & s->vbe_size_mask; + page1 = (addr + bwidth - 1) & s->vbe_size_mask; if (full_update) { update = 1; + } else if (page1 < page0) { + /* scanline wraps from end of video memory to the start */ + assert(force_shadow); + update = memory_region_snapshot_get_dirty(&s->vram, snap, + page0, 0); + update |= memory_region_snapshot_get_dirty(&s->vram, snap, + page1, 0); } else { update = memory_region_snapshot_get_dirty(&s->vram, snap, page0, page1 - page0); @@ -1681,7 +1694,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) if (!multi_run) { mask = (s->cr[VGA_CRTC_MODE] & 3) ^ 3; if ((y1 & mask) == mask) - addr1 += line_offset; + addr1 += s->line_offset; y1++; multi_run = multi_scan; } else { |