@@ -82,6 +82,8 @@ struct vmsvga_state_s {
uint32_t irq_mask;
uint32_t irq_status;
uint32_t display_id;
+ uint32_t pitchlock;
+ int use_pitchlock;
};
#define TYPE_VMWARE_SVGA "vmware-svga"
@@ -1198,9 +1200,10 @@ static uint32_t vmsvga_value_read(void *opaque, uint32_t address)
break;
case SVGA_REG_BYTES_PER_LINE:
- if (s->new_width) {
- ret = (s->new_depth * s->new_width) / 8;
- } else {
+ ret = (s->use_pitchlock >= 0) ?
+ s->pitchlock :
+ ((s->new_depth * s->new_width) / 8);
+ if (!ret) {
ret = surface_stride(surface);
}
break;
@@ -1242,6 +1245,7 @@ static uint32_t vmsvga_value_read(void *opaque, uint32_t address)
caps |= SVGA_CAP_EXTENDED_FIFO;
caps |= SVGA_CAP_IRQMASK;
caps |= SVGA_CAP_DISPLAY_TOPOLOGY;
+ caps |= SVGA_CAP_PITCHLOCK;
ret = caps;
break;
@@ -1294,11 +1298,14 @@ static uint32_t vmsvga_value_read(void *opaque, uint32_t address)
break;
case SVGA_REG_NUM_DISPLAYS:
- case SVGA_REG_PITCHLOCK:
case SVGA_PALETTE_BASE ... SVGA_PALETTE_END:
ret = 0;
break;
+ case SVGA_REG_PITCHLOCK:
+ ret = s->pitchlock;
+ break;
+
case SVGA_REG_IRQMASK:
ret = s->irq_mask;
break;
@@ -1394,6 +1401,13 @@ static void vmsvga_value_write(void *opaque, uint32_t address, uint32_t value)
if (value <= SVGA_MAX_WIDTH) {
s->new_width = value;
s->invalidated = 1;
+ /* This is a hack used to drop effective pitchlock setting
+ * when guest writes screen width without prior write to
+ * the pitchlock register.
+ */
+ if (s->use_pitchlock >= 0) {
+ s->use_pitchlock--;
+ }
} else {
printf("%s: Bad width: %i\n", __func__, value);
}
@@ -1464,10 +1478,15 @@ static void vmsvga_value_write(void *opaque, uint32_t address, uint32_t value)
case SVGA_REG_DEPTH:
case SVGA_REG_MEM_REGS:
case SVGA_REG_NUM_DISPLAYS:
- case SVGA_REG_PITCHLOCK:
case SVGA_PALETTE_BASE ... SVGA_PALETTE_END:
break;
+ case SVGA_REG_PITCHLOCK:
+ s->pitchlock = value;
+ s->use_pitchlock = (value > 0) ? 1 : -1;
+ s->invalidated = 1;
+ break;
+
case SVGA_REG_IRQMASK:
s->irq_mask = value;
break;
@@ -1540,16 +1559,20 @@ static void vmsvga_bios_write(void *opaque, uint32_t address, uint32_t data)
static inline void vmsvga_check_size(struct vmsvga_state_s *s)
{
DisplaySurface *surface = qemu_console_surface(s->vga.con);
+ uint32_t new_stride;
+ new_stride = (s->use_pitchlock >= 0) ?
+ s->pitchlock :
+ ((s->new_depth * s->new_width) / 8);
if (s->new_width != surface_width(surface) ||
s->new_height != surface_height(surface) ||
+ (new_stride != surface_stride(surface)) ||
s->new_depth != surface_bits_per_pixel(surface)) {
- int stride = (s->new_depth * s->new_width) / 8;
pixman_format_code_t format =
qemu_default_pixman_format(s->new_depth, true);
trace_vmware_setmode(s->new_width, s->new_height, s->new_depth);
surface = qemu_create_displaysurface_from(s->new_width, s->new_height,
- format, stride,
+ format, new_stride,
s->vga.vram_ptr);
dpy_gfx_replace_surface(s->vga.con, surface);
s->invalidated = 1;
@@ -1598,6 +1621,8 @@ static void vmsvga_reset(DeviceState *dev)
s->irq_status = 0;
s->last_fifo_cursor_count = 0;
s->display_id = SVGA_ID_INVALID;
+ s->pitchlock = 0;
+ s->use_pitchlock = -1;
vga_dirty_log_start(&s->vga);
}
@@ -1633,6 +1658,8 @@ static int vmsvga_post_load(void *opaque, int version_id)
s->irq_status = 0;
s->last_fifo_cursor_count = 0;
s->display_id = SVGA_ID_INVALID;
+ s->pitchlock = 0;
+ s->use_pitchlock = -1;
}
return 0;
@@ -1664,6 +1691,8 @@ static const VMStateDescription vmstate_vmware_vga_internal = {
VMSTATE_UINT32_V(irq_status, struct vmsvga_state_s, 1),
VMSTATE_UINT32_V(last_fifo_cursor_count, struct vmsvga_state_s, 1),
VMSTATE_UINT32_V(display_id, struct vmsvga_state_s, 1),
+ VMSTATE_UINT32_V(pitchlock, struct vmsvga_state_s, 1),
+ VMSTATE_INT32_V(use_pitchlock, struct vmsvga_state_s, 1),
VMSTATE_END_OF_LIST()
}
};