4 * Copyright (c) 2003 Fabrice Bellard
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 #include "qemu/osdep.h"
26 #include "qemu/units.h"
27 #include "sysemu/reset.h"
28 #include "qapi/error.h"
29 #include "hw/display/vga.h"
30 #include "hw/pci/pci.h"
33 #include "ui/pixel_ops.h"
34 #include "ui/console.h"
35 #include "qemu/timer.h"
36 #include "hw/xen/xen.h"
37 #include "migration/vmstate.h"
40 //#define DEBUG_VGA_MEM
41 //#define DEBUG_VGA_REG
45 /* 16 state changes per vertical frame @60 Hz */
46 #define VGA_TEXT_CURSOR_PERIOD_MS (1000 * 2 * 16 / 60)
49 * Video Graphics Array (VGA)
51 * Chipset docs for original IBM VGA:
52 * http://www.mcamafia.de/pdf/ibm_vgaxga_trm2.pdf
55 * http://www.osdever.net/FreeVGA/home.htm
57 * Standard VGA features and Bochs VBE extensions are implemented.
60 /* force some bits to zero */
61 const uint8_t sr_mask
[8] = {
72 const uint8_t gr_mask
[16] = {
91 #define cbswap_32(__x) \
93 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
94 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
95 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
96 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
99 #define PAT(x) cbswap_32(x)
111 #define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
113 #define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
116 static const uint32_t mask16
[16] = {
140 #define PAT(x) cbswap_32(x)
143 static uint32_t expand4
[256];
144 static uint16_t expand2
[256];
145 static uint8_t expand4to8
[16];
147 static void vbe_update_vgaregs(VGACommonState
*s
);
149 static inline bool vbe_enabled(VGACommonState
*s
)
151 return s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
;
154 static inline uint8_t sr(VGACommonState
*s
, int idx
)
156 return vbe_enabled(s
) ? s
->sr_vbe
[idx
] : s
->sr
[idx
];
159 static void vga_update_memory_access(VGACommonState
*s
)
161 hwaddr base
, offset
, size
;
163 if (s
->legacy_address_space
== NULL
) {
167 if (s
->has_chain4_alias
) {
168 memory_region_del_subregion(s
->legacy_address_space
, &s
->chain4_alias
);
169 object_unparent(OBJECT(&s
->chain4_alias
));
170 s
->has_chain4_alias
= false;
171 s
->plane_updated
= 0xf;
173 if ((sr(s
, VGA_SEQ_PLANE_WRITE
) & VGA_SR02_ALL_PLANES
) ==
174 VGA_SR02_ALL_PLANES
&& sr(s
, VGA_SEQ_MEMORY_MODE
) & VGA_SR04_CHN_4M
) {
176 switch ((s
->gr
[VGA_GFX_MISC
] >> 2) & 3) {
184 offset
= s
->bank_offset
;
196 assert(offset
+ size
<= s
->vram_size
);
197 memory_region_init_alias(&s
->chain4_alias
, memory_region_owner(&s
->vram
),
198 "vga.chain4", &s
->vram
, offset
, size
);
199 memory_region_add_subregion_overlap(s
->legacy_address_space
, base
,
200 &s
->chain4_alias
, 2);
201 s
->has_chain4_alias
= true;
205 static void vga_dumb_update_retrace_info(VGACommonState
*s
)
210 static void vga_precise_update_retrace_info(VGACommonState
*s
)
213 int hretr_start_char
;
214 int hretr_skew_chars
;
218 int vretr_start_line
;
227 const int clk_hz
[] = {25175000, 28322000, 25175000, 25175000};
228 int64_t chars_per_sec
;
229 struct vga_precise_retrace
*r
= &s
->retrace_info
.precise
;
231 htotal_chars
= s
->cr
[VGA_CRTC_H_TOTAL
] + 5;
232 hretr_start_char
= s
->cr
[VGA_CRTC_H_SYNC_START
];
233 hretr_skew_chars
= (s
->cr
[VGA_CRTC_H_SYNC_END
] >> 5) & 3;
234 hretr_end_char
= s
->cr
[VGA_CRTC_H_SYNC_END
] & 0x1f;
236 vtotal_lines
= (s
->cr
[VGA_CRTC_V_TOTAL
] |
237 (((s
->cr
[VGA_CRTC_OVERFLOW
] & 1) |
238 ((s
->cr
[VGA_CRTC_OVERFLOW
] >> 4) & 2)) << 8)) + 2;
239 vretr_start_line
= s
->cr
[VGA_CRTC_V_SYNC_START
] |
240 ((((s
->cr
[VGA_CRTC_OVERFLOW
] >> 2) & 1) |
241 ((s
->cr
[VGA_CRTC_OVERFLOW
] >> 6) & 2)) << 8);
242 vretr_end_line
= s
->cr
[VGA_CRTC_V_SYNC_END
] & 0xf;
244 clocking_mode
= (sr(s
, VGA_SEQ_CLOCK_MODE
) >> 3) & 1;
245 clock_sel
= (s
->msr
>> 2) & 3;
246 dots
= (s
->msr
& 1) ? 8 : 9;
248 chars_per_sec
= clk_hz
[clock_sel
] / dots
;
250 htotal_chars
<<= clocking_mode
;
252 r
->total_chars
= vtotal_lines
* htotal_chars
;
254 r
->ticks_per_char
= NANOSECONDS_PER_SECOND
/ (r
->total_chars
* r
->freq
);
256 r
->ticks_per_char
= NANOSECONDS_PER_SECOND
/ chars_per_sec
;
259 r
->vstart
= vretr_start_line
;
260 r
->vend
= r
->vstart
+ vretr_end_line
+ 1;
262 r
->hstart
= hretr_start_char
+ hretr_skew_chars
;
263 r
->hend
= r
->hstart
+ hretr_end_char
+ 1;
264 r
->htotal
= htotal_chars
;
267 div2
= (s
->cr
[VGA_CRTC_MODE
] >> 2) & 1;
268 sldiv2
= (s
->cr
[VGA_CRTC_MODE
] >> 3) & 1;
278 "div2 = %d sldiv2 = %d\n"
279 "clocking_mode = %d\n"
280 "clock_sel = %d %d\n"
282 "ticks/char = %" PRId64
"\n"
284 (double) NANOSECONDS_PER_SECOND
/ (r
->ticks_per_char
* r
->total_chars
),
302 static uint8_t vga_precise_retrace(VGACommonState
*s
)
304 struct vga_precise_retrace
*r
= &s
->retrace_info
.precise
;
305 uint8_t val
= s
->st01
& ~(ST01_V_RETRACE
| ST01_DISP_ENABLE
);
307 if (r
->total_chars
) {
308 int cur_line
, cur_line_char
, cur_char
;
311 cur_tick
= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
);
313 cur_char
= (cur_tick
/ r
->ticks_per_char
) % r
->total_chars
;
314 cur_line
= cur_char
/ r
->htotal
;
316 if (cur_line
>= r
->vstart
&& cur_line
<= r
->vend
) {
317 val
|= ST01_V_RETRACE
| ST01_DISP_ENABLE
;
319 cur_line_char
= cur_char
% r
->htotal
;
320 if (cur_line_char
>= r
->hstart
&& cur_line_char
<= r
->hend
) {
321 val
|= ST01_DISP_ENABLE
;
327 return s
->st01
^ (ST01_V_RETRACE
| ST01_DISP_ENABLE
);
331 static uint8_t vga_dumb_retrace(VGACommonState
*s
)
333 return s
->st01
^ (ST01_V_RETRACE
| ST01_DISP_ENABLE
);
336 int vga_ioport_invalid(VGACommonState
*s
, uint32_t addr
)
338 if (s
->msr
& VGA_MIS_COLOR
) {
340 return (addr
>= 0x3b0 && addr
<= 0x3bf);
343 return (addr
>= 0x3d0 && addr
<= 0x3df);
347 uint32_t vga_ioport_read(void *opaque
, uint32_t addr
)
349 VGACommonState
*s
= opaque
;
352 if (vga_ioport_invalid(s
, addr
)) {
357 if (s
->ar_flip_flop
== 0) {
364 index
= s
->ar_index
& 0x1f;
365 if (index
< VGA_ATT_C
) {
378 val
= s
->sr
[s
->sr_index
];
380 printf("vga: read SR%x = 0x%02x\n", s
->sr_index
, val
);
387 val
= s
->dac_write_index
;
390 val
= s
->palette
[s
->dac_read_index
* 3 + s
->dac_sub_index
];
391 if (++s
->dac_sub_index
== 3) {
392 s
->dac_sub_index
= 0;
406 val
= s
->gr
[s
->gr_index
];
408 printf("vga: read GR%x = 0x%02x\n", s
->gr_index
, val
);
417 val
= s
->cr
[s
->cr_index
];
419 printf("vga: read CR%x = 0x%02x\n", s
->cr_index
, val
);
424 /* just toggle to fool polling */
425 val
= s
->st01
= s
->retrace(s
);
433 trace_vga_std_read_io(addr
, val
);
437 void vga_ioport_write(void *opaque
, uint32_t addr
, uint32_t val
)
439 VGACommonState
*s
= opaque
;
442 /* check port range access depending on color/monochrome mode */
443 if (vga_ioport_invalid(s
, addr
)) {
446 trace_vga_std_write_io(addr
, val
);
450 if (s
->ar_flip_flop
== 0) {
454 index
= s
->ar_index
& 0x1f;
456 case VGA_ATC_PALETTE0
... VGA_ATC_PALETTEF
:
457 s
->ar
[index
] = val
& 0x3f;
460 s
->ar
[index
] = val
& ~0x10;
462 case VGA_ATC_OVERSCAN
:
465 case VGA_ATC_PLANE_ENABLE
:
466 s
->ar
[index
] = val
& ~0xc0;
469 s
->ar
[index
] = val
& ~0xf0;
471 case VGA_ATC_COLOR_PAGE
:
472 s
->ar
[index
] = val
& ~0xf0;
478 s
->ar_flip_flop
^= 1;
481 s
->msr
= val
& ~0x10;
482 s
->update_retrace_info(s
);
485 s
->sr_index
= val
& 7;
489 printf("vga: write SR%x = 0x%02x\n", s
->sr_index
, val
);
491 s
->sr
[s
->sr_index
] = val
& sr_mask
[s
->sr_index
];
492 if (s
->sr_index
== VGA_SEQ_CLOCK_MODE
) {
493 s
->update_retrace_info(s
);
495 vga_update_memory_access(s
);
498 s
->dac_read_index
= val
;
499 s
->dac_sub_index
= 0;
503 s
->dac_write_index
= val
;
504 s
->dac_sub_index
= 0;
508 s
->dac_cache
[s
->dac_sub_index
] = val
;
509 if (++s
->dac_sub_index
== 3) {
510 memcpy(&s
->palette
[s
->dac_write_index
* 3], s
->dac_cache
, 3);
511 s
->dac_sub_index
= 0;
512 s
->dac_write_index
++;
516 s
->gr_index
= val
& 0x0f;
520 printf("vga: write GR%x = 0x%02x\n", s
->gr_index
, val
);
522 s
->gr
[s
->gr_index
] = val
& gr_mask
[s
->gr_index
];
523 vbe_update_vgaregs(s
);
524 vga_update_memory_access(s
);
533 printf("vga: write CR%x = 0x%02x\n", s
->cr_index
, val
);
535 /* handle CR0-7 protection */
536 if ((s
->cr
[VGA_CRTC_V_SYNC_END
] & VGA_CR11_LOCK_CR0_CR7
) &&
537 s
->cr_index
<= VGA_CRTC_OVERFLOW
) {
538 /* can always write bit 4 of CR7 */
539 if (s
->cr_index
== VGA_CRTC_OVERFLOW
) {
540 s
->cr
[VGA_CRTC_OVERFLOW
] = (s
->cr
[VGA_CRTC_OVERFLOW
] & ~0x10) |
542 vbe_update_vgaregs(s
);
546 s
->cr
[s
->cr_index
] = val
;
547 vbe_update_vgaregs(s
);
549 switch(s
->cr_index
) {
550 case VGA_CRTC_H_TOTAL
:
551 case VGA_CRTC_H_SYNC_START
:
552 case VGA_CRTC_H_SYNC_END
:
553 case VGA_CRTC_V_TOTAL
:
554 case VGA_CRTC_OVERFLOW
:
555 case VGA_CRTC_V_SYNC_END
:
557 s
->update_retrace_info(s
);
569 * Sanity check vbe register writes.
571 * As we don't have a way to signal errors to the guest in the bochs
572 * dispi interface we'll go adjust the registers to the closest valid
575 static void vbe_fixup_regs(VGACommonState
*s
)
577 uint16_t *r
= s
->vbe_regs
;
578 uint32_t bits
, linelength
, maxy
, offset
;
580 if (!vbe_enabled(s
)) {
581 /* vbe is turned off -- nothing to do */
586 switch (r
[VBE_DISPI_INDEX_BPP
]) {
592 bits
= r
[VBE_DISPI_INDEX_BPP
];
598 bits
= r
[VBE_DISPI_INDEX_BPP
] = 8;
603 r
[VBE_DISPI_INDEX_XRES
] &= ~7u;
604 if (r
[VBE_DISPI_INDEX_XRES
] == 0) {
605 r
[VBE_DISPI_INDEX_XRES
] = 8;
607 if (r
[VBE_DISPI_INDEX_XRES
] > VBE_DISPI_MAX_XRES
) {
608 r
[VBE_DISPI_INDEX_XRES
] = VBE_DISPI_MAX_XRES
;
610 r
[VBE_DISPI_INDEX_VIRT_WIDTH
] &= ~7u;
611 if (r
[VBE_DISPI_INDEX_VIRT_WIDTH
] > VBE_DISPI_MAX_XRES
) {
612 r
[VBE_DISPI_INDEX_VIRT_WIDTH
] = VBE_DISPI_MAX_XRES
;
614 if (r
[VBE_DISPI_INDEX_VIRT_WIDTH
] < r
[VBE_DISPI_INDEX_XRES
]) {
615 r
[VBE_DISPI_INDEX_VIRT_WIDTH
] = r
[VBE_DISPI_INDEX_XRES
];
619 linelength
= r
[VBE_DISPI_INDEX_VIRT_WIDTH
] * bits
/ 8;
620 maxy
= s
->vbe_size
/ linelength
;
621 if (r
[VBE_DISPI_INDEX_YRES
] == 0) {
622 r
[VBE_DISPI_INDEX_YRES
] = 1;
624 if (r
[VBE_DISPI_INDEX_YRES
] > VBE_DISPI_MAX_YRES
) {
625 r
[VBE_DISPI_INDEX_YRES
] = VBE_DISPI_MAX_YRES
;
627 if (r
[VBE_DISPI_INDEX_YRES
] > maxy
) {
628 r
[VBE_DISPI_INDEX_YRES
] = maxy
;
632 if (r
[VBE_DISPI_INDEX_X_OFFSET
] > VBE_DISPI_MAX_XRES
) {
633 r
[VBE_DISPI_INDEX_X_OFFSET
] = VBE_DISPI_MAX_XRES
;
635 if (r
[VBE_DISPI_INDEX_Y_OFFSET
] > VBE_DISPI_MAX_YRES
) {
636 r
[VBE_DISPI_INDEX_Y_OFFSET
] = VBE_DISPI_MAX_YRES
;
638 offset
= r
[VBE_DISPI_INDEX_X_OFFSET
] * bits
/ 8;
639 offset
+= r
[VBE_DISPI_INDEX_Y_OFFSET
] * linelength
;
640 if (offset
+ r
[VBE_DISPI_INDEX_YRES
] * linelength
> s
->vbe_size
) {
641 r
[VBE_DISPI_INDEX_Y_OFFSET
] = 0;
642 offset
= r
[VBE_DISPI_INDEX_X_OFFSET
] * bits
/ 8;
643 if (offset
+ r
[VBE_DISPI_INDEX_YRES
] * linelength
> s
->vbe_size
) {
644 r
[VBE_DISPI_INDEX_X_OFFSET
] = 0;
649 /* update vga state */
650 r
[VBE_DISPI_INDEX_VIRT_HEIGHT
] = maxy
;
651 s
->vbe_line_offset
= linelength
;
652 s
->vbe_start_addr
= offset
/ 4;
655 /* we initialize the VGA graphic mode */
656 static void vbe_update_vgaregs(VGACommonState
*s
)
658 int h
, shift_control
;
660 if (!vbe_enabled(s
)) {
661 /* vbe is turned off -- nothing to do */
665 /* graphic mode + memory map 1 */
666 s
->gr
[VGA_GFX_MISC
] = (s
->gr
[VGA_GFX_MISC
] & ~0x0c) | 0x04 |
667 VGA_GR06_GRAPHICS_MODE
;
668 s
->cr
[VGA_CRTC_MODE
] |= 3; /* no CGA modes */
669 s
->cr
[VGA_CRTC_OFFSET
] = s
->vbe_line_offset
>> 3;
671 s
->cr
[VGA_CRTC_H_DISP
] =
672 (s
->vbe_regs
[VBE_DISPI_INDEX_XRES
] >> 3) - 1;
673 /* height (only meaningful if < 1024) */
674 h
= s
->vbe_regs
[VBE_DISPI_INDEX_YRES
] - 1;
675 s
->cr
[VGA_CRTC_V_DISP_END
] = h
;
676 s
->cr
[VGA_CRTC_OVERFLOW
] = (s
->cr
[VGA_CRTC_OVERFLOW
] & ~0x42) |
677 ((h
>> 7) & 0x02) | ((h
>> 3) & 0x40);
678 /* line compare to 1023 */
679 s
->cr
[VGA_CRTC_LINE_COMPARE
] = 0xff;
680 s
->cr
[VGA_CRTC_OVERFLOW
] |= 0x10;
681 s
->cr
[VGA_CRTC_MAX_SCAN
] |= 0x40;
683 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4) {
685 s
->sr_vbe
[VGA_SEQ_CLOCK_MODE
] &= ~8; /* no double line */
688 /* set chain 4 mode */
689 s
->sr_vbe
[VGA_SEQ_MEMORY_MODE
] |= VGA_SR04_CHN_4M
;
690 /* activate all planes */
691 s
->sr_vbe
[VGA_SEQ_PLANE_WRITE
] |= VGA_SR02_ALL_PLANES
;
693 s
->gr
[VGA_GFX_MODE
] = (s
->gr
[VGA_GFX_MODE
] & ~0x60) |
694 (shift_control
<< 5);
695 s
->cr
[VGA_CRTC_MAX_SCAN
] &= ~0x9f; /* no double scan */
698 static uint32_t vbe_ioport_read_index(void *opaque
, uint32_t addr
)
700 VGACommonState
*s
= opaque
;
704 uint32_t vbe_ioport_read_data(void *opaque
, uint32_t addr
)
706 VGACommonState
*s
= opaque
;
709 if (s
->vbe_index
< VBE_DISPI_INDEX_NB
) {
710 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_GETCAPS
) {
711 switch(s
->vbe_index
) {
712 /* XXX: do not hardcode ? */
713 case VBE_DISPI_INDEX_XRES
:
714 val
= VBE_DISPI_MAX_XRES
;
716 case VBE_DISPI_INDEX_YRES
:
717 val
= VBE_DISPI_MAX_YRES
;
719 case VBE_DISPI_INDEX_BPP
:
720 val
= VBE_DISPI_MAX_BPP
;
723 val
= s
->vbe_regs
[s
->vbe_index
];
727 val
= s
->vbe_regs
[s
->vbe_index
];
729 } else if (s
->vbe_index
== VBE_DISPI_INDEX_VIDEO_MEMORY_64K
) {
730 val
= s
->vbe_size
/ (64 * KiB
);
734 trace_vga_vbe_read(s
->vbe_index
, val
);
738 void vbe_ioport_write_index(void *opaque
, uint32_t addr
, uint32_t val
)
740 VGACommonState
*s
= opaque
;
744 void vbe_ioport_write_data(void *opaque
, uint32_t addr
, uint32_t val
)
746 VGACommonState
*s
= opaque
;
748 if (s
->vbe_index
<= VBE_DISPI_INDEX_NB
) {
749 trace_vga_vbe_write(s
->vbe_index
, val
);
750 switch(s
->vbe_index
) {
751 case VBE_DISPI_INDEX_ID
:
752 if (val
== VBE_DISPI_ID0
||
753 val
== VBE_DISPI_ID1
||
754 val
== VBE_DISPI_ID2
||
755 val
== VBE_DISPI_ID3
||
756 val
== VBE_DISPI_ID4
||
757 val
== VBE_DISPI_ID5
) {
758 s
->vbe_regs
[s
->vbe_index
] = val
;
761 case VBE_DISPI_INDEX_XRES
:
762 case VBE_DISPI_INDEX_YRES
:
763 case VBE_DISPI_INDEX_BPP
:
764 case VBE_DISPI_INDEX_VIRT_WIDTH
:
765 case VBE_DISPI_INDEX_X_OFFSET
:
766 case VBE_DISPI_INDEX_Y_OFFSET
:
767 s
->vbe_regs
[s
->vbe_index
] = val
;
769 vbe_update_vgaregs(s
);
771 case VBE_DISPI_INDEX_BANK
:
772 val
&= s
->vbe_bank_mask
;
773 s
->vbe_regs
[s
->vbe_index
] = val
;
774 s
->bank_offset
= (val
<< 16);
775 vga_update_memory_access(s
);
777 case VBE_DISPI_INDEX_ENABLE
:
778 if ((val
& VBE_DISPI_ENABLED
) &&
779 !(s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
)) {
781 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_WIDTH
] = 0;
782 s
->vbe_regs
[VBE_DISPI_INDEX_X_OFFSET
] = 0;
783 s
->vbe_regs
[VBE_DISPI_INDEX_Y_OFFSET
] = 0;
784 s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] |= VBE_DISPI_ENABLED
;
786 vbe_update_vgaregs(s
);
788 /* clear the screen */
789 if (!(val
& VBE_DISPI_NOCLEARMEM
)) {
790 memset(s
->vram_ptr
, 0,
791 s
->vbe_regs
[VBE_DISPI_INDEX_YRES
] * s
->vbe_line_offset
);
796 s
->dac_8bit
= (val
& VBE_DISPI_8BIT_DAC
) > 0;
797 s
->vbe_regs
[s
->vbe_index
] = val
;
798 vga_update_memory_access(s
);
806 /* called for accesses between 0xa0000 and 0xc0000 */
807 uint32_t vga_mem_readb(VGACommonState
*s
, hwaddr addr
)
809 int memory_map_mode
, plane
;
812 /* convert to VGA memory offset */
813 memory_map_mode
= (s
->gr
[VGA_GFX_MISC
] >> 2) & 3;
815 switch(memory_map_mode
) {
821 addr
+= s
->bank_offset
;
836 if (sr(s
, VGA_SEQ_MEMORY_MODE
) & VGA_SR04_CHN_4M
) {
837 /* chain 4 mode : simplest access */
838 assert(addr
< s
->vram_size
);
839 ret
= s
->vram_ptr
[addr
];
840 } else if (s
->gr
[VGA_GFX_MODE
] & 0x10) {
841 /* odd/even mode (aka text mode mapping) */
842 plane
= (s
->gr
[VGA_GFX_PLANE_READ
] & 2) | (addr
& 1);
843 addr
= ((addr
& ~1) << 1) | plane
;
844 if (addr
>= s
->vram_size
) {
847 ret
= s
->vram_ptr
[addr
];
849 /* standard VGA latched access */
850 if (addr
* sizeof(uint32_t) >= s
->vram_size
) {
853 s
->latch
= ((uint32_t *)s
->vram_ptr
)[addr
];
855 if (!(s
->gr
[VGA_GFX_MODE
] & 0x08)) {
857 plane
= s
->gr
[VGA_GFX_PLANE_READ
];
858 ret
= GET_PLANE(s
->latch
, plane
);
861 ret
= (s
->latch
^ mask16
[s
->gr
[VGA_GFX_COMPARE_VALUE
]]) &
862 mask16
[s
->gr
[VGA_GFX_COMPARE_MASK
]];
871 /* called for accesses between 0xa0000 and 0xc0000 */
872 void vga_mem_writeb(VGACommonState
*s
, hwaddr addr
, uint32_t val
)
874 int memory_map_mode
, plane
, write_mode
, b
, func_select
, mask
;
875 uint32_t write_mask
, bit_mask
, set_mask
;
878 printf("vga: [0x" HWADDR_FMT_plx
"] = 0x%02x\n", addr
, val
);
880 /* convert to VGA memory offset */
881 memory_map_mode
= (s
->gr
[VGA_GFX_MISC
] >> 2) & 3;
883 switch(memory_map_mode
) {
889 addr
+= s
->bank_offset
;
904 if (sr(s
, VGA_SEQ_MEMORY_MODE
) & VGA_SR04_CHN_4M
) {
905 /* chain 4 mode : simplest access */
908 if (sr(s
, VGA_SEQ_PLANE_WRITE
) & mask
) {
909 assert(addr
< s
->vram_size
);
910 s
->vram_ptr
[addr
] = val
;
912 printf("vga: chain4: [0x" HWADDR_FMT_plx
"]\n", addr
);
914 s
->plane_updated
|= mask
; /* only used to detect font change */
915 memory_region_set_dirty(&s
->vram
, addr
, 1);
917 } else if (s
->gr
[VGA_GFX_MODE
] & 0x10) {
918 /* odd/even mode (aka text mode mapping) */
919 plane
= (s
->gr
[VGA_GFX_PLANE_READ
] & 2) | (addr
& 1);
921 if (sr(s
, VGA_SEQ_PLANE_WRITE
) & mask
) {
922 addr
= ((addr
& ~1) << 1) | plane
;
923 if (addr
>= s
->vram_size
) {
926 s
->vram_ptr
[addr
] = val
;
928 printf("vga: odd/even: [0x" HWADDR_FMT_plx
"]\n", addr
);
930 s
->plane_updated
|= mask
; /* only used to detect font change */
931 memory_region_set_dirty(&s
->vram
, addr
, 1);
934 /* standard VGA latched access */
935 write_mode
= s
->gr
[VGA_GFX_MODE
] & 3;
940 b
= s
->gr
[VGA_GFX_DATA_ROTATE
] & 7;
941 val
= ((val
>> b
) | (val
<< (8 - b
))) & 0xff;
945 /* apply set/reset mask */
946 set_mask
= mask16
[s
->gr
[VGA_GFX_SR_ENABLE
]];
947 val
= (val
& ~set_mask
) |
948 (mask16
[s
->gr
[VGA_GFX_SR_VALUE
]] & set_mask
);
949 bit_mask
= s
->gr
[VGA_GFX_BIT_MASK
];
955 val
= mask16
[val
& 0x0f];
956 bit_mask
= s
->gr
[VGA_GFX_BIT_MASK
];
960 b
= s
->gr
[VGA_GFX_DATA_ROTATE
] & 7;
961 val
= (val
>> b
) | (val
<< (8 - b
));
963 bit_mask
= s
->gr
[VGA_GFX_BIT_MASK
] & val
;
964 val
= mask16
[s
->gr
[VGA_GFX_SR_VALUE
]];
968 /* apply logical operation */
969 func_select
= s
->gr
[VGA_GFX_DATA_ROTATE
] >> 3;
970 switch(func_select
) {
990 bit_mask
|= bit_mask
<< 8;
991 bit_mask
|= bit_mask
<< 16;
992 val
= (val
& bit_mask
) | (s
->latch
& ~bit_mask
);
995 /* mask data according to sr[2] */
996 mask
= sr(s
, VGA_SEQ_PLANE_WRITE
);
997 s
->plane_updated
|= mask
; /* only used to detect font change */
998 write_mask
= mask16
[mask
];
999 if (addr
* sizeof(uint32_t) >= s
->vram_size
) {
1002 ((uint32_t *)s
->vram_ptr
)[addr
] =
1003 (((uint32_t *)s
->vram_ptr
)[addr
] & ~write_mask
) |
1005 #ifdef DEBUG_VGA_MEM
1006 printf("vga: latch: [0x" HWADDR_FMT_plx
"] mask=0x%08x val=0x%08x\n",
1007 addr
* 4, write_mask
, val
);
1009 memory_region_set_dirty(&s
->vram
, addr
<< 2, sizeof(uint32_t));
1013 typedef void vga_draw_line_func(VGACommonState
*s1
, uint8_t *d
,
1014 uint32_t srcaddr
, int width
);
1016 #include "vga-access.h"
1017 #include "vga-helpers.h"
1019 /* return true if the palette was modified */
1020 static int update_palette16(VGACommonState
*s
)
1023 uint32_t v
, col
, *palette
;
1026 palette
= s
->last_palette
;
1027 for(i
= 0; i
< 16; i
++) {
1029 if (s
->ar
[VGA_ATC_MODE
] & 0x80) {
1030 v
= ((s
->ar
[VGA_ATC_COLOR_PAGE
] & 0xf) << 4) | (v
& 0xf);
1032 v
= ((s
->ar
[VGA_ATC_COLOR_PAGE
] & 0xc) << 4) | (v
& 0x3f);
1035 col
= rgb_to_pixel32(c6_to_8(s
->palette
[v
]),
1036 c6_to_8(s
->palette
[v
+ 1]),
1037 c6_to_8(s
->palette
[v
+ 2]));
1038 if (col
!= palette
[i
]) {
1046 /* return true if the palette was modified */
1047 static int update_palette256(VGACommonState
*s
)
1050 uint32_t v
, col
, *palette
;
1053 palette
= s
->last_palette
;
1055 for(i
= 0; i
< 256; i
++) {
1057 col
= rgb_to_pixel32(s
->palette
[v
],
1061 col
= rgb_to_pixel32(c6_to_8(s
->palette
[v
]),
1062 c6_to_8(s
->palette
[v
+ 1]),
1063 c6_to_8(s
->palette
[v
+ 2]));
1065 if (col
!= palette
[i
]) {
1074 static void vga_get_offsets(VGACommonState
*s
,
1075 uint32_t *pline_offset
,
1076 uint32_t *pstart_addr
,
1077 uint32_t *pline_compare
)
1079 uint32_t start_addr
, line_offset
, line_compare
;
1081 if (vbe_enabled(s
)) {
1082 line_offset
= s
->vbe_line_offset
;
1083 start_addr
= s
->vbe_start_addr
;
1084 line_compare
= 65535;
1086 /* compute line_offset in bytes */
1087 line_offset
= s
->cr
[VGA_CRTC_OFFSET
];
1090 /* starting address */
1091 start_addr
= s
->cr
[VGA_CRTC_START_LO
] |
1092 (s
->cr
[VGA_CRTC_START_HI
] << 8);
1095 line_compare
= s
->cr
[VGA_CRTC_LINE_COMPARE
] |
1096 ((s
->cr
[VGA_CRTC_OVERFLOW
] & 0x10) << 4) |
1097 ((s
->cr
[VGA_CRTC_MAX_SCAN
] & 0x40) << 3);
1099 *pline_offset
= line_offset
;
1100 *pstart_addr
= start_addr
;
1101 *pline_compare
= line_compare
;
1104 /* update start_addr and line_offset. Return TRUE if modified */
1105 static int update_basic_params(VGACommonState
*s
)
1108 uint32_t start_addr
, line_offset
, line_compare
;
1112 s
->get_offsets(s
, &line_offset
, &start_addr
, &line_compare
);
1114 if (line_offset
!= s
->line_offset
||
1115 start_addr
!= s
->start_addr
||
1116 line_compare
!= s
->line_compare
) {
1117 s
->line_offset
= line_offset
;
1118 s
->start_addr
= start_addr
;
1119 s
->line_compare
= line_compare
;
1126 static const uint8_t cursor_glyph
[32 * 4] = {
1127 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1128 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1129 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1130 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1131 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1132 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1133 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1134 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1135 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1136 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1137 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1138 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1139 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1140 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1141 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1142 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1145 static void vga_get_text_resolution(VGACommonState
*s
, int *pwidth
, int *pheight
,
1146 int *pcwidth
, int *pcheight
)
1148 int width
, cwidth
, height
, cheight
;
1150 /* total width & height */
1151 cheight
= (s
->cr
[VGA_CRTC_MAX_SCAN
] & 0x1f) + 1;
1153 if (!(sr(s
, VGA_SEQ_CLOCK_MODE
) & VGA_SR01_CHAR_CLK_8DOTS
)) {
1156 if (sr(s
, VGA_SEQ_CLOCK_MODE
) & 0x08) {
1157 cwidth
= 16; /* NOTE: no 18 pixel wide */
1159 width
= (s
->cr
[VGA_CRTC_H_DISP
] + 1);
1160 if (s
->cr
[VGA_CRTC_V_TOTAL
] == 100) {
1161 /* ugly hack for CGA 160x100x16 - explain me the logic */
1164 height
= s
->cr
[VGA_CRTC_V_DISP_END
] |
1165 ((s
->cr
[VGA_CRTC_OVERFLOW
] & 0x02) << 7) |
1166 ((s
->cr
[VGA_CRTC_OVERFLOW
] & 0x40) << 3);
1167 height
= (height
+ 1) / cheight
;
1173 *pcheight
= cheight
;
1184 static void vga_draw_text(VGACommonState
*s
, int full_update
)
1186 DisplaySurface
*surface
= qemu_console_surface(s
->con
);
1187 int cx
, cy
, cheight
, cw
, ch
, cattr
, height
, width
, ch_attr
;
1188 int cx_min
, cx_max
, linesize
, x_incr
, line
, line1
;
1189 uint32_t offset
, fgcol
, bgcol
, v
, cursor_offset
;
1190 uint8_t *d1
, *d
, *src
, *dest
, *cursor_ptr
;
1191 const uint8_t *font_ptr
, *font_base
[2];
1192 int dup9
, line_offset
;
1194 uint32_t *ch_attr_ptr
;
1195 int64_t now
= qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL
);
1197 /* compute font data address (in plane 2) */
1198 v
= sr(s
, VGA_SEQ_CHARACTER_MAP
);
1199 offset
= (((v
>> 4) & 1) | ((v
<< 1) & 6)) * 8192 * 4 + 2;
1200 if (offset
!= s
->font_offsets
[0]) {
1201 s
->font_offsets
[0] = offset
;
1204 font_base
[0] = s
->vram_ptr
+ offset
;
1206 offset
= (((v
>> 5) & 1) | ((v
>> 1) & 6)) * 8192 * 4 + 2;
1207 font_base
[1] = s
->vram_ptr
+ offset
;
1208 if (offset
!= s
->font_offsets
[1]) {
1209 s
->font_offsets
[1] = offset
;
1212 if (s
->plane_updated
& (1 << 2) || s
->has_chain4_alias
) {
1213 /* if the plane 2 was modified since the last display, it
1214 indicates the font may have been modified */
1215 s
->plane_updated
= 0;
1218 full_update
|= update_basic_params(s
);
1220 line_offset
= s
->line_offset
;
1222 vga_get_text_resolution(s
, &width
, &height
, &cw
, &cheight
);
1223 if ((height
* width
) <= 1) {
1224 /* better than nothing: exit if transient size is too small */
1227 if ((height
* width
) > CH_ATTR_SIZE
) {
1228 /* better than nothing: exit if transient size is too big */
1232 if (width
!= s
->last_width
|| height
!= s
->last_height
||
1233 cw
!= s
->last_cw
|| cheight
!= s
->last_ch
|| s
->last_depth
) {
1234 s
->last_scr_width
= width
* cw
;
1235 s
->last_scr_height
= height
* cheight
;
1236 qemu_console_resize(s
->con
, s
->last_scr_width
, s
->last_scr_height
);
1237 surface
= qemu_console_surface(s
->con
);
1238 dpy_text_resize(s
->con
, width
, height
);
1240 s
->last_width
= width
;
1241 s
->last_height
= height
;
1242 s
->last_ch
= cheight
;
1246 full_update
|= update_palette16(s
);
1247 palette
= s
->last_palette
;
1248 x_incr
= cw
* surface_bytes_per_pixel(surface
);
1251 s
->full_update_text
= 1;
1253 if (s
->full_update_gfx
) {
1254 s
->full_update_gfx
= 0;
1258 cursor_offset
= ((s
->cr
[VGA_CRTC_CURSOR_HI
] << 8) |
1259 s
->cr
[VGA_CRTC_CURSOR_LO
]) - s
->start_addr
;
1260 if (cursor_offset
!= s
->cursor_offset
||
1261 s
->cr
[VGA_CRTC_CURSOR_START
] != s
->cursor_start
||
1262 s
->cr
[VGA_CRTC_CURSOR_END
] != s
->cursor_end
) {
1263 /* if the cursor position changed, we update the old and new
1265 if (s
->cursor_offset
< CH_ATTR_SIZE
)
1266 s
->last_ch_attr
[s
->cursor_offset
] = -1;
1267 if (cursor_offset
< CH_ATTR_SIZE
)
1268 s
->last_ch_attr
[cursor_offset
] = -1;
1269 s
->cursor_offset
= cursor_offset
;
1270 s
->cursor_start
= s
->cr
[VGA_CRTC_CURSOR_START
];
1271 s
->cursor_end
= s
->cr
[VGA_CRTC_CURSOR_END
];
1273 cursor_ptr
= s
->vram_ptr
+ (s
->start_addr
+ cursor_offset
) * 4;
1274 if (now
>= s
->cursor_blink_time
) {
1275 s
->cursor_blink_time
= now
+ VGA_TEXT_CURSOR_PERIOD_MS
/ 2;
1276 s
->cursor_visible_phase
= !s
->cursor_visible_phase
;
1279 dest
= surface_data(surface
);
1280 linesize
= surface_stride(surface
);
1281 ch_attr_ptr
= s
->last_ch_attr
;
1283 offset
= s
->start_addr
* 4;
1284 for(cy
= 0; cy
< height
; cy
++) {
1286 src
= s
->vram_ptr
+ offset
;
1289 for(cx
= 0; cx
< width
; cx
++) {
1290 if (src
+ sizeof(uint16_t) > s
->vram_ptr
+ s
->vram_size
) {
1293 ch_attr
= *(uint16_t *)src
;
1294 if (full_update
|| ch_attr
!= *ch_attr_ptr
|| src
== cursor_ptr
) {
1299 *ch_attr_ptr
= ch_attr
;
1302 cattr
= ch_attr
& 0xff;
1304 ch
= ch_attr
& 0xff;
1305 cattr
= ch_attr
>> 8;
1307 font_ptr
= font_base
[(cattr
>> 3) & 1];
1308 font_ptr
+= 32 * 4 * ch
;
1309 bgcol
= palette
[cattr
>> 4];
1310 fgcol
= palette
[cattr
& 0x0f];
1312 vga_draw_glyph16(d1
, linesize
,
1313 font_ptr
, cheight
, fgcol
, bgcol
);
1314 } else if (cw
!= 9) {
1315 vga_draw_glyph8(d1
, linesize
,
1316 font_ptr
, cheight
, fgcol
, bgcol
);
1319 if (ch
>= 0xb0 && ch
<= 0xdf &&
1320 (s
->ar
[VGA_ATC_MODE
] & 0x04)) {
1323 vga_draw_glyph9(d1
, linesize
,
1324 font_ptr
, cheight
, fgcol
, bgcol
, dup9
);
1326 if (src
== cursor_ptr
&&
1327 !(s
->cr
[VGA_CRTC_CURSOR_START
] & 0x20) &&
1328 s
->cursor_visible_phase
) {
1329 int line_start
, line_last
, h
;
1330 /* draw the cursor */
1331 line_start
= s
->cr
[VGA_CRTC_CURSOR_START
] & 0x1f;
1332 line_last
= s
->cr
[VGA_CRTC_CURSOR_END
] & 0x1f;
1333 /* XXX: check that */
1334 if (line_last
> cheight
- 1)
1335 line_last
= cheight
- 1;
1336 if (line_last
>= line_start
&& line_start
< cheight
) {
1337 h
= line_last
- line_start
+ 1;
1338 d
= d1
+ linesize
* line_start
;
1340 vga_draw_glyph16(d
, linesize
,
1341 cursor_glyph
, h
, fgcol
, bgcol
);
1342 } else if (cw
!= 9) {
1343 vga_draw_glyph8(d
, linesize
,
1344 cursor_glyph
, h
, fgcol
, bgcol
);
1346 vga_draw_glyph9(d
, linesize
,
1347 cursor_glyph
, h
, fgcol
, bgcol
, 1);
1357 dpy_gfx_update(s
->con
, cx_min
* cw
, cy
* cheight
,
1358 (cx_max
- cx_min
+ 1) * cw
, cheight
);
1360 dest
+= linesize
* cheight
;
1361 line1
= line
+ cheight
;
1362 offset
+= line_offset
;
1363 if (line
< s
->line_compare
&& line1
>= s
->line_compare
) {
1388 static vga_draw_line_func
* const vga_draw_line_table
[VGA_DRAW_LINE_NB
] = {
1405 static int vga_get_bpp(VGACommonState
*s
)
1409 if (vbe_enabled(s
)) {
1410 ret
= s
->vbe_regs
[VBE_DISPI_INDEX_BPP
];
1417 static void vga_get_resolution(VGACommonState
*s
, int *pwidth
, int *pheight
)
1421 if (vbe_enabled(s
)) {
1422 width
= s
->vbe_regs
[VBE_DISPI_INDEX_XRES
];
1423 height
= s
->vbe_regs
[VBE_DISPI_INDEX_YRES
];
1425 width
= (s
->cr
[VGA_CRTC_H_DISP
] + 1) * 8;
1426 height
= s
->cr
[VGA_CRTC_V_DISP_END
] |
1427 ((s
->cr
[VGA_CRTC_OVERFLOW
] & 0x02) << 7) |
1428 ((s
->cr
[VGA_CRTC_OVERFLOW
] & 0x40) << 3);
1429 height
= (height
+ 1);
1435 void vga_invalidate_scanlines(VGACommonState
*s
, int y1
, int y2
)
1438 if (y1
>= VGA_MAX_HEIGHT
)
1440 if (y2
>= VGA_MAX_HEIGHT
)
1441 y2
= VGA_MAX_HEIGHT
;
1442 for(y
= y1
; y
< y2
; y
++) {
1443 s
->invalidated_y_table
[y
>> 5] |= 1 << (y
& 0x1f);
1447 static bool vga_scanline_invalidated(VGACommonState
*s
, int y
)
1449 if (y
>= VGA_MAX_HEIGHT
) {
1452 return s
->invalidated_y_table
[y
>> 5] & (1 << (y
& 0x1f));
1455 void vga_dirty_log_start(VGACommonState
*s
)
1457 memory_region_set_log(&s
->vram
, true, DIRTY_MEMORY_VGA
);
1460 void vga_dirty_log_stop(VGACommonState
*s
)
1462 memory_region_set_log(&s
->vram
, false, DIRTY_MEMORY_VGA
);
1468 static void vga_draw_graphic(VGACommonState
*s
, int full_update
)
1470 DisplaySurface
*surface
= qemu_console_surface(s
->con
);
1471 int y1
, y
, update
, linesize
, y_start
, double_scan
, mask
, depth
;
1472 int width
, height
, shift_control
, bwidth
, bits
;
1473 ram_addr_t page0
, page1
, region_start
, region_end
;
1474 DirtyBitmapSnapshot
*snap
= NULL
;
1475 int disp_width
, multi_scan
, multi_run
;
1477 uint32_t v
, addr1
, addr
;
1478 vga_draw_line_func
*vga_draw_line
= NULL
;
1479 bool share_surface
, force_shadow
= false;
1480 pixman_format_code_t format
;
1482 bool byteswap
= !s
->big_endian_fb
;
1484 bool byteswap
= s
->big_endian_fb
;
1487 full_update
|= update_basic_params(s
);
1489 s
->get_resolution(s
, &width
, &height
);
1491 depth
= s
->get_bpp(s
);
1493 region_start
= (s
->start_addr
* 4);
1494 region_end
= region_start
+ (ram_addr_t
)s
->line_offset
* height
;
1495 region_end
+= width
* depth
/ 8; /* scanline length */
1496 region_end
-= s
->line_offset
;
1497 if (region_end
> s
->vbe_size
|| depth
== 0 || depth
== 15) {
1500 * - wraps around (can happen with cirrus vbe modes)
1501 * - depth == 0 (256 color palette video mode)
1504 * Take the safe and slow route:
1505 * - create a dirty bitmap snapshot for all vga memory.
1506 * - force shadowing (so all vga memory access goes
1507 * through vga_read_*() helpers).
1509 * Given this affects only vga features which are pretty much
1510 * unused by modern guests there should be no performance
1514 region_end
= s
->vbe_size
;
1515 force_shadow
= true;
1518 /* bits 5-6: 0 = 16-color mode, 1 = 4-color mode, 2 = 256-color mode. */
1519 shift_control
= (s
->gr
[VGA_GFX_MODE
] >> 5) & 3;
1520 double_scan
= (s
->cr
[VGA_CRTC_MAX_SCAN
] >> 7);
1521 if (s
->cr
[VGA_CRTC_MODE
] & 1) {
1522 multi_scan
= (((s
->cr
[VGA_CRTC_MAX_SCAN
] & 0x1f) + 1) << double_scan
)
1525 /* in CGA modes, multi_scan is ignored */
1526 /* XXX: is it correct ? */
1527 multi_scan
= double_scan
;
1529 multi_run
= multi_scan
;
1530 if (shift_control
!= s
->shift_control
||
1531 double_scan
!= s
->double_scan
) {
1533 s
->shift_control
= shift_control
;
1534 s
->double_scan
= double_scan
;
1537 if (shift_control
== 0) {
1538 if (sr(s
, VGA_SEQ_CLOCK_MODE
) & 8) {
1541 } else if (shift_control
== 1) {
1542 if (sr(s
, VGA_SEQ_CLOCK_MODE
) & 8) {
1548 * Check whether we can share the surface with the backend
1549 * or whether we need a shadow surface. We share native
1550 * endian surfaces for 15bpp and above and byteswapped
1551 * surfaces for 24bpp and above.
1553 format
= qemu_default_pixman_format(depth
, !byteswap
);
1555 share_surface
= dpy_gfx_check_format(s
->con
, format
)
1556 && !s
->force_shadow
&& !force_shadow
;
1558 share_surface
= false;
1561 if (s
->line_offset
!= s
->last_line_offset
||
1562 disp_width
!= s
->last_width
||
1563 height
!= s
->last_height
||
1564 s
->last_depth
!= depth
||
1565 s
->last_byteswap
!= byteswap
||
1566 share_surface
!= is_buffer_shared(surface
)) {
1567 /* display parameters changed -> need new display surface */
1568 s
->last_scr_width
= disp_width
;
1569 s
->last_scr_height
= height
;
1570 s
->last_width
= disp_width
;
1571 s
->last_height
= height
;
1572 s
->last_line_offset
= s
->line_offset
;
1573 s
->last_depth
= depth
;
1574 s
->last_byteswap
= byteswap
;
1577 if (surface_data(surface
) != s
->vram_ptr
+ (s
->start_addr
* 4)
1578 && is_buffer_shared(surface
)) {
1579 /* base address changed (page flip) -> shared display surfaces
1580 * must be updated with the new base address */
1585 if (share_surface
) {
1586 surface
= qemu_create_displaysurface_from(disp_width
,
1587 height
, format
, s
->line_offset
,
1588 s
->vram_ptr
+ (s
->start_addr
* 4));
1589 dpy_gfx_replace_surface(s
->con
, surface
);
1591 qemu_console_resize(s
->con
, disp_width
, height
);
1592 surface
= qemu_console_surface(s
->con
);
1596 if (shift_control
== 0) {
1597 full_update
|= update_palette16(s
);
1598 if (sr(s
, VGA_SEQ_CLOCK_MODE
) & 8) {
1599 v
= VGA_DRAW_LINE4D2
;
1604 } else if (shift_control
== 1) {
1605 full_update
|= update_palette16(s
);
1606 if (sr(s
, VGA_SEQ_CLOCK_MODE
) & 8) {
1607 v
= VGA_DRAW_LINE2D2
;
1613 switch(s
->get_bpp(s
)) {
1616 full_update
|= update_palette256(s
);
1617 v
= VGA_DRAW_LINE8D2
;
1621 full_update
|= update_palette256(s
);
1626 v
= s
->big_endian_fb
? VGA_DRAW_LINE15_BE
: VGA_DRAW_LINE15_LE
;
1630 v
= s
->big_endian_fb
? VGA_DRAW_LINE16_BE
: VGA_DRAW_LINE16_LE
;
1634 v
= s
->big_endian_fb
? VGA_DRAW_LINE24_BE
: VGA_DRAW_LINE24_LE
;
1638 v
= s
->big_endian_fb
? VGA_DRAW_LINE32_BE
: VGA_DRAW_LINE32_LE
;
1643 vga_draw_line
= vga_draw_line_table
[v
];
1645 if (!is_buffer_shared(surface
) && s
->cursor_invalidate
) {
1646 s
->cursor_invalidate(s
);
1650 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",
1651 width
, height
, v
, line_offset
, s
->cr
[9], s
->cr
[VGA_CRTC_MODE
],
1652 s
->line_compare
, sr(s
, VGA_SEQ_CLOCK_MODE
));
1654 addr1
= (s
->start_addr
* 4);
1655 bwidth
= DIV_ROUND_UP(width
* bits
, 8);
1657 d
= surface_data(surface
);
1658 linesize
= surface_stride(surface
);
1662 if (s
->line_compare
< height
) {
1663 /* split screen mode */
1666 snap
= memory_region_snapshot_and_clear_dirty(&s
->vram
, region_start
,
1667 region_end
- region_start
,
1671 for(y
= 0; y
< height
; y
++) {
1673 if (!(s
->cr
[VGA_CRTC_MODE
] & 1)) {
1675 /* CGA compatibility handling */
1676 shift
= 14 + ((s
->cr
[VGA_CRTC_MODE
] >> 6) & 1);
1677 addr
= (addr
& ~(1 << shift
)) | ((y1
& 1) << shift
);
1679 if (!(s
->cr
[VGA_CRTC_MODE
] & 2)) {
1680 addr
= (addr
& ~0x8000) | ((y1
& 2) << 14);
1682 page0
= addr
& s
->vbe_size_mask
;
1683 page1
= (addr
+ bwidth
- 1) & s
->vbe_size_mask
;
1686 } else if (page1
< page0
) {
1687 /* scanline wraps from end of video memory to the start */
1688 assert(force_shadow
);
1689 update
= memory_region_snapshot_get_dirty(&s
->vram
, snap
,
1690 page0
, s
->vbe_size
- page0
);
1691 update
|= memory_region_snapshot_get_dirty(&s
->vram
, snap
,
1694 update
= memory_region_snapshot_get_dirty(&s
->vram
, snap
,
1695 page0
, page1
- page0
);
1697 /* explicit invalidation for the hardware cursor (cirrus only) */
1698 update
|= vga_scanline_invalidated(s
, y
);
1702 if (!(is_buffer_shared(surface
))) {
1703 vga_draw_line(s
, d
, addr
, width
);
1704 if (s
->cursor_draw_line
)
1705 s
->cursor_draw_line(s
, d
, y
);
1709 /* flush to display */
1710 dpy_gfx_update(s
->con
, 0, y_start
,
1711 disp_width
, y
- y_start
);
1716 mask
= (s
->cr
[VGA_CRTC_MODE
] & 3) ^ 3;
1717 if ((y1
& mask
) == mask
)
1718 addr1
+= s
->line_offset
;
1720 multi_run
= multi_scan
;
1724 /* line compare acts on the displayed lines */
1725 if (y
== s
->line_compare
)
1730 /* flush to display */
1731 dpy_gfx_update(s
->con
, 0, y_start
,
1732 disp_width
, y
- y_start
);
1735 memset(s
->invalidated_y_table
, 0, sizeof(s
->invalidated_y_table
));
1738 static void vga_draw_blank(VGACommonState
*s
, int full_update
)
1740 DisplaySurface
*surface
= qemu_console_surface(s
->con
);
1746 if (s
->last_scr_width
<= 0 || s
->last_scr_height
<= 0)
1749 w
= s
->last_scr_width
* surface_bytes_per_pixel(surface
);
1750 d
= surface_data(surface
);
1751 for(i
= 0; i
< s
->last_scr_height
; i
++) {
1753 d
+= surface_stride(surface
);
1755 dpy_gfx_update_full(s
->con
);
1758 #define GMODE_TEXT 0
1759 #define GMODE_GRAPH 1
1760 #define GMODE_BLANK 2
1762 static void vga_update_display(void *opaque
)
1764 VGACommonState
*s
= opaque
;
1765 DisplaySurface
*surface
= qemu_console_surface(s
->con
);
1766 int full_update
, graphic_mode
;
1768 qemu_flush_coalesced_mmio_buffer();
1770 if (surface_bits_per_pixel(surface
) == 0) {
1774 if (!(s
->ar_index
& 0x20)) {
1775 graphic_mode
= GMODE_BLANK
;
1777 graphic_mode
= s
->gr
[VGA_GFX_MISC
] & VGA_GR06_GRAPHICS_MODE
;
1779 if (graphic_mode
!= s
->graphic_mode
) {
1780 s
->graphic_mode
= graphic_mode
;
1781 s
->cursor_blink_time
= qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL
);
1784 switch(graphic_mode
) {
1786 vga_draw_text(s
, full_update
);
1789 vga_draw_graphic(s
, full_update
);
1793 vga_draw_blank(s
, full_update
);
1799 /* force a full display refresh */
1800 static void vga_invalidate_display(void *opaque
)
1802 VGACommonState
*s
= opaque
;
1805 s
->last_height
= -1;
1808 void vga_common_reset(VGACommonState
*s
)
1811 memset(s
->sr
, '\0', sizeof(s
->sr
));
1812 memset(s
->sr_vbe
, '\0', sizeof(s
->sr_vbe
));
1814 memset(s
->gr
, '\0', sizeof(s
->gr
));
1816 memset(s
->ar
, '\0', sizeof(s
->ar
));
1817 s
->ar_flip_flop
= 0;
1819 memset(s
->cr
, '\0', sizeof(s
->cr
));
1825 s
->dac_sub_index
= 0;
1826 s
->dac_read_index
= 0;
1827 s
->dac_write_index
= 0;
1828 memset(s
->dac_cache
, '\0', sizeof(s
->dac_cache
));
1830 memset(s
->palette
, '\0', sizeof(s
->palette
));
1833 memset(s
->vbe_regs
, '\0', sizeof(s
->vbe_regs
));
1834 s
->vbe_regs
[VBE_DISPI_INDEX_ID
] = VBE_DISPI_ID5
;
1835 s
->vbe_start_addr
= 0;
1836 s
->vbe_line_offset
= 0;
1837 s
->vbe_bank_mask
= (s
->vram_size
>> 16) - 1;
1838 memset(s
->font_offsets
, '\0', sizeof(s
->font_offsets
));
1839 s
->graphic_mode
= -1; /* force full update */
1840 s
->shift_control
= 0;
1843 s
->line_compare
= 0;
1845 s
->plane_updated
= 0;
1850 s
->last_scr_width
= 0;
1851 s
->last_scr_height
= 0;
1852 s
->cursor_start
= 0;
1854 s
->cursor_offset
= 0;
1855 s
->big_endian_fb
= s
->default_endian_fb
;
1856 memset(s
->invalidated_y_table
, '\0', sizeof(s
->invalidated_y_table
));
1857 memset(s
->last_palette
, '\0', sizeof(s
->last_palette
));
1858 memset(s
->last_ch_attr
, '\0', sizeof(s
->last_ch_attr
));
1859 switch (vga_retrace_method
) {
1860 case VGA_RETRACE_DUMB
:
1862 case VGA_RETRACE_PRECISE
:
1863 memset(&s
->retrace_info
, 0, sizeof (s
->retrace_info
));
1866 vga_update_memory_access(s
);
1869 static void vga_reset(void *opaque
)
1871 VGACommonState
*s
= opaque
;
1872 vga_common_reset(s
);
1875 #define TEXTMODE_X(x) ((x) % width)
1876 #define TEXTMODE_Y(x) ((x) / width)
1877 #define VMEM2CHTYPE(v) ((v & 0xff0007ff) | \
1878 ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1))
1879 /* relay text rendering to the display driver
1880 * instead of doing a full vga_update_display() */
1881 static void vga_update_text(void *opaque
, console_ch_t
*chardata
)
1883 VGACommonState
*s
= opaque
;
1884 int graphic_mode
, i
, cursor_offset
, cursor_visible
;
1885 int cw
, cheight
, width
, height
, size
, c_min
, c_max
;
1887 console_ch_t
*dst
, val
;
1888 char msg_buffer
[80];
1889 int full_update
= 0;
1891 qemu_flush_coalesced_mmio_buffer();
1893 if (!(s
->ar_index
& 0x20)) {
1894 graphic_mode
= GMODE_BLANK
;
1896 graphic_mode
= s
->gr
[VGA_GFX_MISC
] & VGA_GR06_GRAPHICS_MODE
;
1898 if (graphic_mode
!= s
->graphic_mode
) {
1899 s
->graphic_mode
= graphic_mode
;
1902 if (s
->last_width
== -1) {
1907 switch (graphic_mode
) {
1909 /* TODO: update palette */
1910 full_update
|= update_basic_params(s
);
1912 /* total width & height */
1913 cheight
= (s
->cr
[VGA_CRTC_MAX_SCAN
] & 0x1f) + 1;
1915 if (!(sr(s
, VGA_SEQ_CLOCK_MODE
) & VGA_SR01_CHAR_CLK_8DOTS
)) {
1918 if (sr(s
, VGA_SEQ_CLOCK_MODE
) & 0x08) {
1919 cw
= 16; /* NOTE: no 18 pixel wide */
1921 width
= (s
->cr
[VGA_CRTC_H_DISP
] + 1);
1922 if (s
->cr
[VGA_CRTC_V_TOTAL
] == 100) {
1923 /* ugly hack for CGA 160x100x16 - explain me the logic */
1926 height
= s
->cr
[VGA_CRTC_V_DISP_END
] |
1927 ((s
->cr
[VGA_CRTC_OVERFLOW
] & 0x02) << 7) |
1928 ((s
->cr
[VGA_CRTC_OVERFLOW
] & 0x40) << 3);
1929 height
= (height
+ 1) / cheight
;
1932 size
= (height
* width
);
1933 if (size
> CH_ATTR_SIZE
) {
1937 snprintf(msg_buffer
, sizeof(msg_buffer
), "%i x %i Text mode",
1942 if (width
!= s
->last_width
|| height
!= s
->last_height
||
1943 cw
!= s
->last_cw
|| cheight
!= s
->last_ch
) {
1944 s
->last_scr_width
= width
* cw
;
1945 s
->last_scr_height
= height
* cheight
;
1946 qemu_console_resize(s
->con
, s
->last_scr_width
, s
->last_scr_height
);
1947 dpy_text_resize(s
->con
, width
, height
);
1949 s
->last_width
= width
;
1950 s
->last_height
= height
;
1951 s
->last_ch
= cheight
;
1957 s
->full_update_gfx
= 1;
1959 if (s
->full_update_text
) {
1960 s
->full_update_text
= 0;
1964 /* Update "hardware" cursor */
1965 cursor_offset
= ((s
->cr
[VGA_CRTC_CURSOR_HI
] << 8) |
1966 s
->cr
[VGA_CRTC_CURSOR_LO
]) - s
->start_addr
;
1967 if (cursor_offset
!= s
->cursor_offset
||
1968 s
->cr
[VGA_CRTC_CURSOR_START
] != s
->cursor_start
||
1969 s
->cr
[VGA_CRTC_CURSOR_END
] != s
->cursor_end
|| full_update
) {
1970 cursor_visible
= !(s
->cr
[VGA_CRTC_CURSOR_START
] & 0x20);
1971 if (cursor_visible
&& cursor_offset
< size
&& cursor_offset
>= 0)
1972 dpy_text_cursor(s
->con
,
1973 TEXTMODE_X(cursor_offset
),
1974 TEXTMODE_Y(cursor_offset
));
1976 dpy_text_cursor(s
->con
, -1, -1);
1977 s
->cursor_offset
= cursor_offset
;
1978 s
->cursor_start
= s
->cr
[VGA_CRTC_CURSOR_START
];
1979 s
->cursor_end
= s
->cr
[VGA_CRTC_CURSOR_END
];
1982 src
= (uint32_t *) s
->vram_ptr
+ s
->start_addr
;
1986 for (i
= 0; i
< size
; src
++, dst
++, i
++)
1987 console_write_ch(dst
, VMEM2CHTYPE(le32_to_cpu(*src
)));
1989 dpy_text_update(s
->con
, 0, 0, width
, height
);
1993 for (i
= 0; i
< size
; src
++, dst
++, i
++) {
1994 console_write_ch(&val
, VMEM2CHTYPE(le32_to_cpu(*src
)));
2002 for (; i
< size
; src
++, dst
++, i
++) {
2003 console_write_ch(&val
, VMEM2CHTYPE(le32_to_cpu(*src
)));
2010 if (c_min
<= c_max
) {
2011 i
= TEXTMODE_Y(c_min
);
2012 dpy_text_update(s
->con
, 0, i
, width
, TEXTMODE_Y(c_max
) - i
+ 1);
2021 s
->get_resolution(s
, &width
, &height
);
2022 snprintf(msg_buffer
, sizeof(msg_buffer
), "%i x %i Graphic mode",
2030 snprintf(msg_buffer
, sizeof(msg_buffer
), "VGA Blank mode");
2034 /* Display a message */
2036 s
->last_height
= height
= 3;
2037 dpy_text_cursor(s
->con
, -1, -1);
2038 dpy_text_resize(s
->con
, s
->last_width
, height
);
2040 for (dst
= chardata
, i
= 0; i
< s
->last_width
* height
; i
++)
2041 console_write_ch(dst
++, ' ');
2043 size
= strlen(msg_buffer
);
2044 width
= (s
->last_width
- size
) / 2;
2045 dst
= chardata
+ s
->last_width
+ width
;
2046 for (i
= 0; i
< size
; i
++)
2047 console_write_ch(dst
++, ATTR2CHTYPE(msg_buffer
[i
], QEMU_COLOR_BLUE
,
2048 QEMU_COLOR_BLACK
, 1));
2050 dpy_text_update(s
->con
, 0, 0, s
->last_width
, height
);
2053 static uint64_t vga_mem_read(void *opaque
, hwaddr addr
,
2056 VGACommonState
*s
= opaque
;
2058 return vga_mem_readb(s
, addr
);
2061 static void vga_mem_write(void *opaque
, hwaddr addr
,
2062 uint64_t data
, unsigned size
)
2064 VGACommonState
*s
= opaque
;
2066 vga_mem_writeb(s
, addr
, data
);
2069 const MemoryRegionOps vga_mem_ops
= {
2070 .read
= vga_mem_read
,
2071 .write
= vga_mem_write
,
2072 .endianness
= DEVICE_LITTLE_ENDIAN
,
2074 .min_access_size
= 1,
2075 .max_access_size
= 1,
2079 static int vga_common_post_load(void *opaque
, int version_id
)
2081 VGACommonState
*s
= opaque
;
2084 s
->graphic_mode
= -1;
2085 vbe_update_vgaregs(s
);
2086 vga_update_memory_access(s
);
2090 static bool vga_endian_state_needed(void *opaque
)
2092 VGACommonState
*s
= opaque
;
2095 * Only send the endian state if it's different from the
2096 * default one, thus ensuring backward compatibility for
2097 * migration of the common case
2099 return s
->default_endian_fb
!= s
->big_endian_fb
;
2102 static const VMStateDescription vmstate_vga_endian
= {
2103 .name
= "vga.endian",
2105 .minimum_version_id
= 1,
2106 .needed
= vga_endian_state_needed
,
2107 .fields
= (VMStateField
[]) {
2108 VMSTATE_BOOL(big_endian_fb
, VGACommonState
),
2109 VMSTATE_END_OF_LIST()
2113 const VMStateDescription vmstate_vga_common
= {
2116 .minimum_version_id
= 2,
2117 .post_load
= vga_common_post_load
,
2118 .fields
= (VMStateField
[]) {
2119 VMSTATE_UINT32(latch
, VGACommonState
),
2120 VMSTATE_UINT8(sr_index
, VGACommonState
),
2121 VMSTATE_PARTIAL_BUFFER(sr
, VGACommonState
, 8),
2122 VMSTATE_UINT8(gr_index
, VGACommonState
),
2123 VMSTATE_PARTIAL_BUFFER(gr
, VGACommonState
, 16),
2124 VMSTATE_UINT8(ar_index
, VGACommonState
),
2125 VMSTATE_BUFFER(ar
, VGACommonState
),
2126 VMSTATE_INT32(ar_flip_flop
, VGACommonState
),
2127 VMSTATE_UINT8(cr_index
, VGACommonState
),
2128 VMSTATE_BUFFER(cr
, VGACommonState
),
2129 VMSTATE_UINT8(msr
, VGACommonState
),
2130 VMSTATE_UINT8(fcr
, VGACommonState
),
2131 VMSTATE_UINT8(st00
, VGACommonState
),
2132 VMSTATE_UINT8(st01
, VGACommonState
),
2134 VMSTATE_UINT8(dac_state
, VGACommonState
),
2135 VMSTATE_UINT8(dac_sub_index
, VGACommonState
),
2136 VMSTATE_UINT8(dac_read_index
, VGACommonState
),
2137 VMSTATE_UINT8(dac_write_index
, VGACommonState
),
2138 VMSTATE_BUFFER(dac_cache
, VGACommonState
),
2139 VMSTATE_BUFFER(palette
, VGACommonState
),
2141 VMSTATE_INT32(bank_offset
, VGACommonState
),
2142 VMSTATE_UINT8_EQUAL(is_vbe_vmstate
, VGACommonState
, NULL
),
2143 VMSTATE_UINT16(vbe_index
, VGACommonState
),
2144 VMSTATE_UINT16_ARRAY(vbe_regs
, VGACommonState
, VBE_DISPI_INDEX_NB
),
2145 VMSTATE_UINT32(vbe_start_addr
, VGACommonState
),
2146 VMSTATE_UINT32(vbe_line_offset
, VGACommonState
),
2147 VMSTATE_UINT32(vbe_bank_mask
, VGACommonState
),
2148 VMSTATE_END_OF_LIST()
2150 .subsections
= (const VMStateDescription
*[]) {
2151 &vmstate_vga_endian
,
2156 static const GraphicHwOps vga_ops
= {
2157 .invalidate
= vga_invalidate_display
,
2158 .gfx_update
= vga_update_display
,
2159 .text_update
= vga_update_text
,
2162 static inline uint32_t uint_clamp(uint32_t val
, uint32_t vmin
, uint32_t vmax
)
2173 bool vga_common_init(VGACommonState
*s
, Object
*obj
, Error
**errp
)
2176 Error
*local_err
= NULL
;
2178 for(i
= 0;i
< 256; i
++) {
2180 for(j
= 0; j
< 8; j
++) {
2181 v
|= ((i
>> j
) & 1) << (j
* 4);
2186 for(j
= 0; j
< 4; j
++) {
2187 v
|= ((i
>> (2 * j
)) & 3) << (j
* 4);
2191 for(i
= 0; i
< 16; i
++) {
2193 for(j
= 0; j
< 4; j
++) {
2196 v
|= b
<< (2 * j
+ 1);
2201 s
->vram_size_mb
= uint_clamp(s
->vram_size_mb
, 1, 512);
2202 s
->vram_size_mb
= pow2ceil(s
->vram_size_mb
);
2203 s
->vram_size
= s
->vram_size_mb
* MiB
;
2206 s
->vbe_size
= s
->vram_size
;
2208 s
->vbe_size_mask
= s
->vbe_size
- 1;
2210 s
->is_vbe_vmstate
= 1;
2212 if (s
->global_vmstate
&& qemu_ram_block_by_name("vga.vram")) {
2213 error_setg(errp
, "Only one global VGA device can be used at a time");
2217 memory_region_init_ram_nomigrate(&s
->vram
, obj
, "vga.vram", s
->vram_size
,
2220 error_propagate(errp
, local_err
);
2223 vmstate_register_ram(&s
->vram
, s
->global_vmstate
? NULL
: DEVICE(obj
));
2224 xen_register_framebuffer(&s
->vram
);
2225 s
->vram_ptr
= memory_region_get_ram_ptr(&s
->vram
);
2226 s
->get_bpp
= vga_get_bpp
;
2227 s
->get_offsets
= vga_get_offsets
;
2228 s
->get_resolution
= vga_get_resolution
;
2229 s
->hw_ops
= &vga_ops
;
2230 switch (vga_retrace_method
) {
2231 case VGA_RETRACE_DUMB
:
2232 s
->retrace
= vga_dumb_retrace
;
2233 s
->update_retrace_info
= vga_dumb_update_retrace_info
;
2236 case VGA_RETRACE_PRECISE
:
2237 s
->retrace
= vga_precise_retrace
;
2238 s
->update_retrace_info
= vga_precise_update_retrace_info
;
2243 * Set default fb endian based on target, could probably be turned
2244 * into a device attribute set by the machine/platform to remove
2245 * all target endian dependencies from this file.
2247 #if TARGET_BIG_ENDIAN
2248 s
->default_endian_fb
= true;
2250 s
->default_endian_fb
= false;
2252 vga_dirty_log_start(s
);
2257 static const MemoryRegionPortio vga_portio_list
[] = {
2258 { 0x04, 2, 1, .read
= vga_ioport_read
, .write
= vga_ioport_write
}, /* 3b4 */
2259 { 0x0a, 1, 1, .read
= vga_ioport_read
, .write
= vga_ioport_write
}, /* 3ba */
2260 { 0x10, 16, 1, .read
= vga_ioport_read
, .write
= vga_ioport_write
}, /* 3c0 */
2261 { 0x24, 2, 1, .read
= vga_ioport_read
, .write
= vga_ioport_write
}, /* 3d4 */
2262 { 0x2a, 1, 1, .read
= vga_ioport_read
, .write
= vga_ioport_write
}, /* 3da */
2263 PORTIO_END_OF_LIST(),
2266 static const MemoryRegionPortio vbe_portio_list
[] = {
2267 { 0, 1, 2, .read
= vbe_ioport_read_index
, .write
= vbe_ioport_write_index
},
2269 { 1, 1, 2, .read
= vbe_ioport_read_data
, .write
= vbe_ioport_write_data
},
2271 { 2, 1, 2, .read
= vbe_ioport_read_data
, .write
= vbe_ioport_write_data
},
2272 PORTIO_END_OF_LIST(),
2275 /* Used by both ISA and PCI */
2276 MemoryRegion
*vga_init_io(VGACommonState
*s
, Object
*obj
,
2277 const MemoryRegionPortio
**vga_ports
,
2278 const MemoryRegionPortio
**vbe_ports
)
2280 MemoryRegion
*vga_mem
;
2282 *vga_ports
= vga_portio_list
;
2283 *vbe_ports
= vbe_portio_list
;
2285 vga_mem
= g_malloc(sizeof(*vga_mem
));
2286 memory_region_init_io(vga_mem
, obj
, &vga_mem_ops
, s
,
2287 "vga-lowmem", 0x20000);
2288 memory_region_set_flush_coalesced(vga_mem
);
2293 void vga_init(VGACommonState
*s
, Object
*obj
, MemoryRegion
*address_space
,
2294 MemoryRegion
*address_space_io
, bool init_vga_ports
)
2296 MemoryRegion
*vga_io_memory
;
2297 const MemoryRegionPortio
*vga_ports
, *vbe_ports
;
2299 qemu_register_reset(vga_reset
, s
);
2303 s
->legacy_address_space
= address_space
;
2305 vga_io_memory
= vga_init_io(s
, obj
, &vga_ports
, &vbe_ports
);
2306 memory_region_add_subregion_overlap(address_space
,
2310 memory_region_set_coalescing(vga_io_memory
);
2311 if (init_vga_ports
) {
2312 portio_list_init(&s
->vga_port_list
, obj
, vga_ports
, s
, "vga");
2313 portio_list_set_flush_coalesced(&s
->vga_port_list
);
2314 portio_list_add(&s
->vga_port_list
, address_space_io
, 0x3b0);
2317 portio_list_init(&s
->vbe_port_list
, obj
, vbe_ports
, s
, "vbe");
2318 portio_list_add(&s
->vbe_port_list
, address_space_io
, 0x1ce);