aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2017-10-19 10:53:19 +0100
committerPeter Maydell <peter.maydell@linaro.org>2017-10-19 10:53:19 +0100
commit73b733e6907e1193e562f498272108c95c00868c (patch)
tree7fb8e53203ed2b441225e65a9bc209e7b97f8d8c /hw
parent861cd431c99e56ddb5953ca1da164a9c32b477ca (diff)
parenteb38e1bc3740725ca29a535351de94107ec58d51 (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>
Diffstat (limited to 'hw')
-rw-r--r--hw/display/cirrus_vga.c6
-rw-r--r--hw/display/vga.c33
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 {