Skip to content

Commit d634c88

Browse files
zbalatonkraxel
authored andcommitted
ati-vga: Support unaligned access to hardware cursor registers
This fixes horizontal mouse movement and pointer color with MacOS that writes these registers with access size less than 4 so previously only the last portion of access was effective overwriting previous partial writes. Signed-off-by: BALATON Zoltan <[email protected]> Message-id: ba1d5ba97f246e8807f86f1243c2bdc6497dc8f2.1592737958.git.balaton@eik.bme.hu Signed-off-by: Gerd Hoffmann <[email protected]>
1 parent 9982c60 commit d634c88

File tree

1 file changed

+58
-29
lines changed

1 file changed

+58
-29
lines changed

hw/display/ati.c

Lines changed: 58 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -389,22 +389,28 @@ static uint64_t ati_mm_read(void *opaque, hwaddr addr, unsigned int size)
389389
case 0xf00 ... 0xfff:
390390
val = pci_default_read_config(&s->dev, addr - 0xf00, size);
391391
break;
392-
case CUR_OFFSET:
393-
val = s->regs.cur_offset;
394-
break;
395-
case CUR_HORZ_VERT_POSN:
396-
val = s->regs.cur_hv_pos;
397-
val |= s->regs.cur_offset & BIT(31);
392+
case CUR_OFFSET ... CUR_OFFSET + 3:
393+
val = ati_reg_read_offs(s->regs.cur_offset, addr - CUR_OFFSET, size);
394+
break;
395+
case CUR_HORZ_VERT_POSN ... CUR_HORZ_VERT_POSN + 3:
396+
val = ati_reg_read_offs(s->regs.cur_hv_pos,
397+
addr - CUR_HORZ_VERT_POSN, size);
398+
if (addr + size > CUR_HORZ_VERT_POSN + 3) {
399+
val |= (s->regs.cur_offset & BIT(31)) >> (4 - size);
400+
}
398401
break;
399-
case CUR_HORZ_VERT_OFF:
400-
val = s->regs.cur_hv_offs;
401-
val |= s->regs.cur_offset & BIT(31);
402+
case CUR_HORZ_VERT_OFF ... CUR_HORZ_VERT_OFF + 3:
403+
val = ati_reg_read_offs(s->regs.cur_hv_offs,
404+
addr - CUR_HORZ_VERT_OFF, size);
405+
if (addr + size > CUR_HORZ_VERT_OFF + 3) {
406+
val |= (s->regs.cur_offset & BIT(31)) >> (4 - size);
407+
}
402408
break;
403-
case CUR_CLR0:
404-
val = s->regs.cur_color0;
409+
case CUR_CLR0 ... CUR_CLR0 + 3:
410+
val = ati_reg_read_offs(s->regs.cur_color0, addr - CUR_CLR0, size);
405411
break;
406-
case CUR_CLR1:
407-
val = s->regs.cur_color1;
412+
case CUR_CLR1 ... CUR_CLR1 + 3:
413+
val = ati_reg_read_offs(s->regs.cur_color1, addr - CUR_CLR1, size);
408414
break;
409415
case DST_OFFSET:
410416
val = s->regs.dst_offset;
@@ -679,48 +685,71 @@ static void ati_mm_write(void *opaque, hwaddr addr,
679685
case 0xf00 ... 0xfff:
680686
/* read-only copy of PCI config space so ignore writes */
681687
break;
682-
case CUR_OFFSET:
683-
if (s->regs.cur_offset != (data & 0x87fffff0)) {
684-
s->regs.cur_offset = data & 0x87fffff0;
688+
case CUR_OFFSET ... CUR_OFFSET + 3:
689+
{
690+
uint32_t t = s->regs.cur_offset;
691+
692+
ati_reg_write_offs(&t, addr - CUR_OFFSET, data, size);
693+
t &= 0x87fffff0;
694+
if (s->regs.cur_offset != t) {
695+
s->regs.cur_offset = t;
685696
ati_cursor_define(s);
686697
}
687698
break;
688-
case CUR_HORZ_VERT_POSN:
689-
s->regs.cur_hv_pos = data & 0x3fff0fff;
690-
if (data & BIT(31)) {
691-
s->regs.cur_offset |= data & BIT(31);
699+
}
700+
case CUR_HORZ_VERT_POSN ... CUR_HORZ_VERT_POSN + 3:
701+
{
702+
uint32_t t = s->regs.cur_hv_pos | (s->regs.cur_offset & BIT(31));
703+
704+
ati_reg_write_offs(&t, addr - CUR_HORZ_VERT_POSN, data, size);
705+
s->regs.cur_hv_pos = t & 0x3fff0fff;
706+
if (t & BIT(31)) {
707+
s->regs.cur_offset |= t & BIT(31);
692708
} else if (s->regs.cur_offset & BIT(31)) {
693709
s->regs.cur_offset &= ~BIT(31);
694710
ati_cursor_define(s);
695711
}
696712
if (!s->cursor_guest_mode &&
697-
(s->regs.crtc_gen_cntl & CRTC2_CUR_EN) && !(data & BIT(31))) {
713+
(s->regs.crtc_gen_cntl & CRTC2_CUR_EN) && !(t & BIT(31))) {
698714
dpy_mouse_set(s->vga.con, s->regs.cur_hv_pos >> 16,
699715
s->regs.cur_hv_pos & 0xffff, 1);
700716
}
701717
break;
718+
}
702719
case CUR_HORZ_VERT_OFF:
703-
s->regs.cur_hv_offs = data & 0x3f003f;
704-
if (data & BIT(31)) {
705-
s->regs.cur_offset |= data & BIT(31);
720+
{
721+
uint32_t t = s->regs.cur_hv_offs | (s->regs.cur_offset & BIT(31));
722+
723+
ati_reg_write_offs(&t, addr - CUR_HORZ_VERT_OFF, data, size);
724+
s->regs.cur_hv_offs = t & 0x3f003f;
725+
if (t & BIT(31)) {
726+
s->regs.cur_offset |= t & BIT(31);
706727
} else if (s->regs.cur_offset & BIT(31)) {
707728
s->regs.cur_offset &= ~BIT(31);
708729
ati_cursor_define(s);
709730
}
710731
break;
711-
case CUR_CLR0:
712-
if (s->regs.cur_color0 != (data & 0xffffff)) {
713-
s->regs.cur_color0 = data & 0xffffff;
732+
}
733+
case CUR_CLR0 ... CUR_CLR0 + 3:
734+
{
735+
uint32_t t = s->regs.cur_color0;
736+
737+
ati_reg_write_offs(&t, addr - CUR_CLR0, data, size);
738+
t &= 0xffffff;
739+
if (s->regs.cur_color0 != t) {
740+
s->regs.cur_color0 = t;
714741
ati_cursor_define(s);
715742
}
716743
break;
717-
case CUR_CLR1:
744+
}
745+
case CUR_CLR1 ... CUR_CLR1 + 3:
718746
/*
719747
* Update cursor unconditionally here because some clients set up
720748
* other registers before actually writing cursor data to memory at
721749
* offset so we would miss cursor change unless always updating here
722750
*/
723-
s->regs.cur_color1 = data & 0xffffff;
751+
ati_reg_write_offs(&s->regs.cur_color1, addr - CUR_CLR1, data, size);
752+
s->regs.cur_color1 &= 0xffffff;
724753
ati_cursor_define(s);
725754
break;
726755
case DST_OFFSET:

0 commit comments

Comments
 (0)