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/core/cpu.h"
30 #include "hw/display/vga.h"
31 #include "hw/i386/x86.h"
32 #include "hw/pci/pci.h"
35 #include "ui/pixel_ops.h"
36 #include "ui/console.h"
37 #include "qemu/timer.h"
38 #include "hw/xen/xen.h"
39 #include "migration/vmstate.h"
42 //#define DEBUG_VGA_MEM
43 //#define DEBUG_VGA_REG
47 /* 16 state changes per vertical frame @60 Hz */
48 #define VGA_TEXT_CURSOR_PERIOD_MS (1000 * 2 * 16 / 60)
51 * Video Graphics Array (VGA)
53 * Chipset docs for original IBM VGA:
54 * http://www.mcamafia.de/pdf/ibm_vgaxga_trm2.pdf
57 * http://www.osdever.net/FreeVGA/home.htm
59 * Standard VGA features and Bochs VBE extensions are implemented.
62 /* force some bits to zero */
63 const uint8_t sr_mask
[8] = {
74 const uint8_t gr_mask
[16] = {
93 #define cbswap_32(__x) \
95 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
96 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
97 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
98 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
101 #define PAT(x) cbswap_32(x)
113 #define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
115 #define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
118 static const uint32_t mask16
[16] = {
142 #define PAT(x) cbswap_32(x)
145 static uint32_t expand4
[256];
146 static uint16_t expand2
[256];
147 static uint8_t expand4to8
[16];
149 static void vbe_update_vgaregs(VGACommonState
*s
);
151 static inline bool vbe_enabled(VGACommonState
*s
)
153 return s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
;
156 static inline uint8_t sr(VGACommonState
*s
, int idx
)
158 return vbe_enabled(s
) ? s
->sr_vbe
[idx
] : s
->sr
[idx
];
161 static void vga_update_memory_access(VGACommonState
*s
)
163 hwaddr base
, offset
, size
;
165 if (s
->legacy_address_space
== NULL
) {
169 if (s
->has_chain4_alias
) {
170 memory_region_del_subregion(s
->legacy_address_space
, &s
->chain4_alias
);
171 object_unparent(OBJECT(&s
->chain4_alias
));
172 s
->has_chain4_alias
= false;
173 s
->plane_updated
= 0xf;
175 if ((sr(s
, VGA_SEQ_PLANE_WRITE
) & VGA_SR02_ALL_PLANES
) ==
176 VGA_SR02_ALL_PLANES
&& sr(s
, VGA_SEQ_MEMORY_MODE
) & VGA_SR04_CHN_4M
) {
178 switch ((s
->gr
[VGA_GFX_MISC
] >> 2) & 3) {
186 offset
= s
->bank_offset
;
198 assert(offset
+ size
<= s
->vram_size
);
199 memory_region_init_alias(&s
->chain4_alias
, memory_region_owner(&s
->vram
),
200 "vga.chain4", &s
->vram
, offset
, size
);
201 memory_region_add_subregion_overlap(s
->legacy_address_space
, base
,
202 &s
->chain4_alias
, 2);
203 s
->has_chain4_alias
= true;
207 static void vga_dumb_update_retrace_info(VGACommonState
*s
)
212 static void vga_precise_update_retrace_info(VGACommonState
*s
)
215 int hretr_start_char
;
216 int hretr_skew_chars
;
220 int vretr_start_line
;
229 const int clk_hz
[] = {25175000, 28322000, 25175000, 25175000};
230 int64_t chars_per_sec
;
231 struct vga_precise_retrace
*r
= &s
->retrace_info
.precise
;
233 htotal_chars
= s
->cr
[VGA_CRTC_H_TOTAL
] + 5;
234 hretr_start_char
= s
->cr
[VGA_CRTC_H_SYNC_START
];
235 hretr_skew_chars
= (s
->cr
[VGA_CRTC_H_SYNC_END
] >> 5) & 3;
236 hretr_end_char
= s
->cr
[VGA_CRTC_H_SYNC_END
] & 0x1f;
238 vtotal_lines
= (s
->cr
[VGA_CRTC_V_TOTAL
] |
239 (((s
->cr
[VGA_CRTC_OVERFLOW
] & 1) |
240 ((s
->cr
[VGA_CRTC_OVERFLOW
] >> 4) & 2)) << 8)) + 2;
241 vretr_start_line
= s
->cr
[VGA_CRTC_V_SYNC_START
] |
242 ((((s
->cr
[VGA_CRTC_OVERFLOW
] >> 2) & 1) |
243 ((s
->cr
[VGA_CRTC_OVERFLOW
] >> 6) & 2)) << 8);
244 vretr_end_line
= s
->cr
[VGA_CRTC_V_SYNC_END
] & 0xf;
246 clocking_mode
= (sr(s
, VGA_SEQ_CLOCK_MODE
) >> 3) & 1;
247 clock_sel
= (s
->msr
>> 2) & 3;
248 dots
= (s
->msr
& 1) ? 8 : 9;
250 chars_per_sec
= clk_hz
[clock_sel
] / dots
;
252 htotal_chars
<<= clocking_mode
;
254 r
->total_chars
= vtotal_lines
* htotal_chars
;
256 r
->ticks_per_char
= NANOSECONDS_PER_SECOND
/ (r
->total_chars
* r
->freq
);
258 r
->ticks_per_char
= NANOSECONDS_PER_SECOND
/ chars_per_sec
;
261 r
->vstart
= vretr_start_line
;
262 r
->vend
= r
->vstart
+ vretr_end_line
+ 1;
264 r
->hstart
= hretr_start_char
+ hretr_skew_chars
;
265 r
->hend
= r
->hstart
+ hretr_end_char
+ 1;
266 r
->htotal
= htotal_chars
;
269 div2
= (s
->cr
[VGA_CRTC_MODE
] >> 2) & 1;
270 sldiv2
= (s
->cr
[VGA_CRTC_MODE
] >> 3) & 1;
280 "div2 = %d sldiv2 = %d\n"
281 "clocking_mode = %d\n"
282 "clock_sel = %d %d\n"
284 "ticks/char = %" PRId64
"\n"
286 (double) NANOSECONDS_PER_SECOND
/ (r
->ticks_per_char
* r
->total_chars
),
304 static uint8_t vga_precise_retrace(VGACommonState
*s
)
306 struct vga_precise_retrace
*r
= &s
->retrace_info
.precise
;
307 uint8_t val
= s
->st01
& ~(ST01_V_RETRACE
| ST01_DISP_ENABLE
);
309 if (r
->total_chars
) {
310 int cur_line
, cur_line_char
, cur_char
;
313 cur_tick
= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
);
315 cur_char
= (cur_tick
/ r
->ticks_per_char
) % r
->total_chars
;
316 cur_line
= cur_char
/ r
->htotal
;
318 if (cur_line
>= r
->vstart
&& cur_line
<= r
->vend
) {
319 val
|= ST01_V_RETRACE
| ST01_DISP_ENABLE
;
321 cur_line_char
= cur_char
% r
->htotal
;
322 if (cur_line_char
>= r
->hstart
&& cur_line_char
<= r
->hend
) {
323 val
|= ST01_DISP_ENABLE
;
329 return s
->st01
^ (ST01_V_RETRACE
| ST01_DISP_ENABLE
);
333 static uint8_t vga_dumb_retrace(VGACommonState
*s
)
335 return s
->st01
^ (ST01_V_RETRACE
| ST01_DISP_ENABLE
);
338 int vga_ioport_invalid(VGACommonState
*s
, uint32_t addr
)
340 if (s
->msr
& VGA_MIS_COLOR
) {
342 return (addr
>= 0x3b0 && addr
<= 0x3bf);
345 return (addr
>= 0x3d0 && addr
<= 0x3df);
349 uint32_t vga_ioport_read(void *opaque
, uint32_t addr
)
351 VGACommonState
*s
= opaque
;
354 if (vga_ioport_invalid(s
, addr
)) {
359 if (s
->ar_flip_flop
== 0) {
366 index
= s
->ar_index
& 0x1f;
367 if (index
< VGA_ATT_C
) {
380 val
= s
->sr
[s
->sr_index
];
382 printf("vga: read SR%x = 0x%02x\n", s
->sr_index
, val
);
389 val
= s
->dac_write_index
;
392 val
= s
->palette
[s
->dac_read_index
* 3 + s
->dac_sub_index
];
393 if (++s
->dac_sub_index
== 3) {
394 s
->dac_sub_index
= 0;
408 val
= s
->gr
[s
->gr_index
];
410 printf("vga: read GR%x = 0x%02x\n", s
->gr_index
, val
);
419 val
= s
->cr
[s
->cr_index
];
421 printf("vga: read CR%x = 0x%02x\n", s
->cr_index
, val
);
426 /* just toggle to fool polling */
427 val
= s
->st01
= s
->retrace(s
);
435 trace_vga_std_read_io(addr
, val
);
439 void vga_ioport_write(void *opaque
, uint32_t addr
, uint32_t val
)
441 VGACommonState
*s
= opaque
;
444 /* check port range access depending on color/monochrome mode */
445 if (vga_ioport_invalid(s
, addr
)) {
448 trace_vga_std_write_io(addr
, val
);
452 if (s
->ar_flip_flop
== 0) {
456 index
= s
->ar_index
& 0x1f;
458 case VGA_ATC_PALETTE0
... VGA_ATC_PALETTEF
:
459 s
->ar
[index
] = val
& 0x3f;
462 s
->ar
[index
] = val
& ~0x10;
464 case VGA_ATC_OVERSCAN
:
467 case VGA_ATC_PLANE_ENABLE
:
468 s
->ar
[index
] = val
& ~0xc0;
471 s
->ar
[index
] = val
& ~0xf0;
473 case VGA_ATC_COLOR_PAGE
:
474 s
->ar
[index
] = val
& ~0xf0;
480 s
->ar_flip_flop
^= 1;
483 s
->msr
= val
& ~0x10;
484 s
->update_retrace_info(s
);
487 s
->sr_index
= val
& 7;
491 printf("vga: write SR%x = 0x%02x\n", s
->sr_index
, val
);
493 s
->sr
[s
->sr_index
] = val
& sr_mask
[s
->sr_index
];
494 if (s
->sr_index
== VGA_SEQ_CLOCK_MODE
) {
495 s
->update_retrace_info(s
);
497 vga_update_memory_access(s
);
500 s
->dac_read_index
= val
;
501 s
->dac_sub_index
= 0;
505 s
->dac_write_index
= val
;
506 s
->dac_sub_index
= 0;
510 s
->dac_cache
[s
->dac_sub_index
] = val
;
511 if (++s
->dac_sub_index
== 3) {
512 memcpy(&s
->palette
[s
->dac_write_index
* 3], s
->dac_cache
, 3);
513 s
->dac_sub_index
= 0;
514 s
->dac_write_index
++;
518 s
->gr_index
= val
& 0x0f;
522 printf("vga: write GR%x = 0x%02x\n", s
->gr_index
, val
);
524 s
->gr
[s
->gr_index
] = val
& gr_mask
[s
->gr_index
];
525 vbe_update_vgaregs(s
);
526 vga_update_memory_access(s
);
535 printf("vga: write CR%x = 0x%02x\n", s
->cr_index
, val
);
537 /* handle CR0-7 protection */
538 if ((s
->cr
[VGA_CRTC_V_SYNC_END
] & VGA_CR11_LOCK_CR0_CR7
) &&
539 s
->cr_index
<= VGA_CRTC_OVERFLOW
) {
540 /* can always write bit 4 of CR7 */
541 if (s
->cr_index
== VGA_CRTC_OVERFLOW
) {
542 s
->cr
[VGA_CRTC_OVERFLOW
] = (s
->cr
[VGA_CRTC_OVERFLOW
] & ~0x10) |
544 vbe_update_vgaregs(s
);
548 s
->cr
[s
->cr_index
] = val
;
549 vbe_update_vgaregs(s
);
551 switch(s
->cr_index
) {
552 case VGA_CRTC_H_TOTAL
:
553 case VGA_CRTC_H_SYNC_START
:
554 case VGA_CRTC_H_SYNC_END
:
555 case VGA_CRTC_V_TOTAL
:
556 case VGA_CRTC_OVERFLOW
:
557 case VGA_CRTC_V_SYNC_END
:
559 s
->update_retrace_info(s
);
571 * Sanity check vbe register writes.
573 * As we don't have a way to signal errors to the guest in the bochs
574 * dispi interface we'll go adjust the registers to the closest valid
577 static void vbe_fixup_regs(VGACommonState
*s
)
579 uint16_t *r
= s
->vbe_regs
;
580 uint32_t bits
, linelength
, maxy
, offset
;
582 if (!vbe_enabled(s
)) {
583 /* vbe is turned off -- nothing to do */
588 switch (r
[VBE_DISPI_INDEX_BPP
]) {
594 bits
= r
[VBE_DISPI_INDEX_BPP
];
600 bits
= r
[VBE_DISPI_INDEX_BPP
] = 8;
605 r
[VBE_DISPI_INDEX_XRES
] &= ~7u;
606 if (r
[VBE_DISPI_INDEX_XRES
] == 0) {
607 r
[VBE_DISPI_INDEX_XRES
] = 8;
609 if (r
[VBE_DISPI_INDEX_XRES
] > VBE_DISPI_MAX_XRES
) {
610 r
[VBE_DISPI_INDEX_XRES
] = VBE_DISPI_MAX_XRES
;
612 r
[VBE_DISPI_INDEX_VIRT_WIDTH
] &= ~7u;
613 if (r
[VBE_DISPI_INDEX_VIRT_WIDTH
] > VBE_DISPI_MAX_XRES
) {
614 r
[VBE_DISPI_INDEX_VIRT_WIDTH
] = VBE_DISPI_MAX_XRES
;
616 if (r
[VBE_DISPI_INDEX_VIRT_WIDTH
] < r
[VBE_DISPI_INDEX_XRES
]) {
617 r
[VBE_DISPI_INDEX_VIRT_WIDTH
] = r
[VBE_DISPI_INDEX_XRES
];
621 linelength
= r
[VBE_DISPI_INDEX_VIRT_WIDTH
] * bits
/ 8;
622 maxy
= s
->vbe_size
/ linelength
;
623 if (r
[VBE_DISPI_INDEX_YRES
] == 0) {
624 r
[VBE_DISPI_INDEX_YRES
] = 1;
626 if (r
[VBE_DISPI_INDEX_YRES
] > VBE_DISPI_MAX_YRES
) {
627 r
[VBE_DISPI_INDEX_YRES
] = VBE_DISPI_MAX_YRES
;
629 if (r
[VBE_DISPI_INDEX_YRES
] > maxy
) {
630 r
[VBE_DISPI_INDEX_YRES
] = maxy
;
634 if (r
[VBE_DISPI_INDEX_X_OFFSET
] > VBE_DISPI_MAX_XRES
) {
635 r
[VBE_DISPI_INDEX_X_OFFSET
] = VBE_DISPI_MAX_XRES
;
637 if (r
[VBE_DISPI_INDEX_Y_OFFSET
] > VBE_DISPI_MAX_YRES
) {
638 r
[VBE_DISPI_INDEX_Y_OFFSET
] = VBE_DISPI_MAX_YRES
;
640 offset
= r
[VBE_DISPI_INDEX_X_OFFSET
] * bits
/ 8;
641 offset
+= r
[VBE_DISPI_INDEX_Y_OFFSET
] * linelength
;
642 if (offset
+ r
[VBE_DISPI_INDEX_YRES
] * linelength
> s
->vbe_size
) {
643 r
[VBE_DISPI_INDEX_Y_OFFSET
] = 0;
644 offset
= r
[VBE_DISPI_INDEX_X_OFFSET
] * bits
/ 8;
645 if (offset
+ r
[VBE_DISPI_INDEX_YRES
] * linelength
> s
->vbe_size
) {
646 r
[VBE_DISPI_INDEX_X_OFFSET
] = 0;
651 /* update vga state */
652 r
[VBE_DISPI_INDEX_VIRT_HEIGHT
] = maxy
;
653 s
->vbe_line_offset
= linelength
;
654 s
->vbe_start_addr
= offset
/ 4;
657 /* we initialize the VGA graphic mode */
658 static void vbe_update_vgaregs(VGACommonState
*s
)
660 int h
, shift_control
;
662 if (!vbe_enabled(s
)) {
663 /* vbe is turned off -- nothing to do */
667 /* graphic mode + memory map 1 */
668 s
->gr
[VGA_GFX_MISC
] = (s
->gr
[VGA_GFX_MISC
] & ~0x0c) | 0x04 |
669 VGA_GR06_GRAPHICS_MODE
;
670 s
->cr
[VGA_CRTC_MODE
] |= 3; /* no CGA modes */
671 s
->cr
[VGA_CRTC_OFFSET
] = s
->vbe_line_offset
>> 3;
673 s
->cr
[VGA_CRTC_H_DISP
] =
674 (s
->vbe_regs
[VBE_DISPI_INDEX_XRES
] >> 3) - 1;
675 /* height (only meaningful if < 1024) */
676 h
= s
->vbe_regs
[VBE_DISPI_INDEX_YRES
] - 1;
677 s
->cr
[VGA_CRTC_V_DISP_END
] = h
;
678 s
->cr
[VGA_CRTC_OVERFLOW
] = (s
->cr
[VGA_CRTC_OVERFLOW
] & ~0x42) |
679 ((h
>> 7) & 0x02) | ((h
>> 3) & 0x40);
680 /* line compare to 1023 */
681 s
->cr
[VGA_CRTC_LINE_COMPARE
] = 0xff;
682 s
->cr
[VGA_CRTC_OVERFLOW
] |= 0x10;
683 s
->cr
[VGA_CRTC_MAX_SCAN
] |= 0x40;
685 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4) {
687 s
->sr_vbe
[VGA_SEQ_CLOCK_MODE
] &= ~8; /* no double line */
690 /* set chain 4 mode */
691 s
->sr_vbe
[VGA_SEQ_MEMORY_MODE
] |= VGA_SR04_CHN_4M
;
692 /* activate all planes */
693 s
->sr_vbe
[VGA_SEQ_PLANE_WRITE
] |= VGA_SR02_ALL_PLANES
;
695 s
->gr
[VGA_GFX_MODE
] = (s
->gr
[VGA_GFX_MODE
] & ~0x60) |
696 (shift_control
<< 5);
697 s
->cr
[VGA_CRTC_MAX_SCAN
] &= ~0x9f; /* no double scan */
700 static uint32_t vbe_ioport_read_index(void *opaque
, uint32_t addr
)
702 VGACommonState
*s
= opaque
;
706 uint32_t vbe_ioport_read_data(void *opaque
, uint32_t addr
)
708 VGACommonState
*s
= opaque
;
711 if (s
->vbe_index
< VBE_DISPI_INDEX_NB
) {
712 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_GETCAPS
) {
713 switch(s
->vbe_index
) {
714 /* XXX: do not hardcode ? */
715 case VBE_DISPI_INDEX_XRES
:
716 val
= VBE_DISPI_MAX_XRES
;
718 case VBE_DISPI_INDEX_YRES
:
719 val
= VBE_DISPI_MAX_YRES
;
721 case VBE_DISPI_INDEX_BPP
:
722 val
= VBE_DISPI_MAX_BPP
;
725 val
= s
->vbe_regs
[s
->vbe_index
];
729 val
= s
->vbe_regs
[s
->vbe_index
];
731 } else if (s
->vbe_index
== VBE_DISPI_INDEX_VIDEO_MEMORY_64K
) {
732 val
= s
->vbe_size
/ (64 * KiB
);
736 trace_vga_vbe_read(s
->vbe_index
, val
);
740 void vbe_ioport_write_index(void *opaque
, uint32_t addr
, uint32_t val
)
742 VGACommonState
*s
= opaque
;
746 void vbe_ioport_write_data(void *opaque
, uint32_t addr
, uint32_t val
)
748 VGACommonState
*s
= opaque
;
750 if (s
->vbe_index
<= VBE_DISPI_INDEX_NB
) {
751 trace_vga_vbe_write(s
->vbe_index
, val
);
752 switch(s
->vbe_index
) {
753 case VBE_DISPI_INDEX_ID
:
754 if (val
== VBE_DISPI_ID0
||
755 val
== VBE_DISPI_ID1
||
756 val
== VBE_DISPI_ID2
||
757 val
== VBE_DISPI_ID3
||
758 val
== VBE_DISPI_ID4
||
759 val
== VBE_DISPI_ID5
) {
760 s
->vbe_regs
[s
->vbe_index
] = val
;
763 case VBE_DISPI_INDEX_XRES
:
764 case VBE_DISPI_INDEX_YRES
:
765 case VBE_DISPI_INDEX_BPP
:
766 case VBE_DISPI_INDEX_VIRT_WIDTH
:
767 case VBE_DISPI_INDEX_X_OFFSET
:
768 case VBE_DISPI_INDEX_Y_OFFSET
:
769 s
->vbe_regs
[s
->vbe_index
] = val
;
771 vbe_update_vgaregs(s
);
773 case VBE_DISPI_INDEX_BANK
:
774 val
&= s
->vbe_bank_mask
;
775 s
->vbe_regs
[s
->vbe_index
] = val
;
776 s
->bank_offset
= (val
<< 16);
777 vga_update_memory_access(s
);
779 case VBE_DISPI_INDEX_ENABLE
:
780 if ((val
& VBE_DISPI_ENABLED
) &&
781 !(s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
)) {
783 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_WIDTH
] = 0;
784 s
->vbe_regs
[VBE_DISPI_INDEX_X_OFFSET
] = 0;
785 s
->vbe_regs
[VBE_DISPI_INDEX_Y_OFFSET
] = 0;
786 s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] |= VBE_DISPI_ENABLED
;
788 vbe_update_vgaregs(s
);
790 /* clear the screen */
791 if (!(val
& VBE_DISPI_NOCLEARMEM
)) {
792 memset(s
->vram_ptr
, 0,
793 s
->vbe_regs
[VBE_DISPI_INDEX_YRES
] * s
->vbe_line_offset
);
798 s
->dac_8bit
= (val
& VBE_DISPI_8BIT_DAC
) > 0;
799 s
->vbe_regs
[s
->vbe_index
] = val
;
800 vga_update_memory_access(s
);
808 /* called for accesses between 0xa0000 and 0xc0000 */
809 uint32_t vga_mem_readb(VGACommonState
*s
, hwaddr addr
)
811 int memory_map_mode
, plane
;
814 /* convert to VGA memory offset */
815 memory_map_mode
= (s
->gr
[VGA_GFX_MISC
] >> 2) & 3;
817 switch(memory_map_mode
) {
823 addr
+= s
->bank_offset
;
838 if (sr(s
, VGA_SEQ_MEMORY_MODE
) & VGA_SR04_CHN_4M
) {
839 /* chain 4 mode : simplest access */
840 assert(addr
< s
->vram_size
);
841 ret
= s
->vram_ptr
[addr
];
842 } else if (s
->gr
[VGA_GFX_MODE
] & 0x10) {
843 /* odd/even mode (aka text mode mapping) */
844 plane
= (s
->gr
[VGA_GFX_PLANE_READ
] & 2) | (addr
& 1);
845 addr
= ((addr
& ~1) << 1) | plane
;
846 if (addr
>= s
->vram_size
) {
849 ret
= s
->vram_ptr
[addr
];
851 /* standard VGA latched access */
852 if (addr
* sizeof(uint32_t) >= s
->vram_size
) {
855 s
->latch
= ((uint32_t *)s
->vram_ptr
)[addr
];
857 if (!(s
->gr
[VGA_GFX_MODE
] & 0x08)) {
859 plane
= s
->gr
[VGA_GFX_PLANE_READ
];
860 ret
= GET_PLANE(s
->latch
, plane
);
863 ret
= (s
->latch
^ mask16
[s
->gr
[VGA_GFX_COMPARE_VALUE
]]) &
864 mask16
[s
->gr
[VGA_GFX_COMPARE_MASK
]];
873 /* called for accesses between 0xa0000 and 0xc0000 */
874 void vga_mem_writeb(VGACommonState
*s
, hwaddr addr
, uint32_t val
)
876 int memory_map_mode
, plane
, write_mode
, b
, func_select
, mask
;
877 uint32_t write_mask
, bit_mask
, set_mask
;
880 printf("vga: [0x" HWADDR_FMT_plx
"] = 0x%02x\n", addr
, val
);
882 /* convert to VGA memory offset */
883 memory_map_mode
= (s
->gr
[VGA_GFX_MISC
] >> 2) & 3;
885 switch(memory_map_mode
) {
891 addr
+= s
->bank_offset
;
906 if (sr(s
, VGA_SEQ_MEMORY_MODE
) & VGA_SR04_CHN_4M
) {
907 /* chain 4 mode : simplest access */
910 if (sr(s
, VGA_SEQ_PLANE_WRITE
) & mask
) {
911 assert(addr
< s
->vram_size
);
912 s
->vram_ptr
[addr
] = val
;
914 printf("vga: chain4: [0x" HWADDR_FMT_plx
"]\n", addr
);
916 s
->plane_updated
|= mask
; /* only used to detect font change */
917 memory_region_set_dirty(&s
->vram
, addr
, 1);
919 } else if (s
->gr
[VGA_GFX_MODE
] & 0x10) {
920 /* odd/even mode (aka text mode mapping) */
921 plane
= (s
->gr
[VGA_GFX_PLANE_READ
] & 2) | (addr
& 1);
923 if (sr(s
, VGA_SEQ_PLANE_WRITE
) & mask
) {
924 addr
= ((addr
& ~1) << 1) | plane
;
925 if (addr
>= s
->vram_size
) {
928 s
->vram_ptr
[addr
] = val
;
930 printf("vga: odd/even: [0x" HWADDR_FMT_plx
"]\n", addr
);
932 s
->plane_updated
|= mask
; /* only used to detect font change */
933 memory_region_set_dirty(&s
->vram
, addr
, 1);
936 /* standard VGA latched access */
937 write_mode
= s
->gr
[VGA_GFX_MODE
] & 3;
942 b
= s
->gr
[VGA_GFX_DATA_ROTATE
] & 7;
943 val
= ((val
>> b
) | (val
<< (8 - b
))) & 0xff;
947 /* apply set/reset mask */
948 set_mask
= mask16
[s
->gr
[VGA_GFX_SR_ENABLE
]];
949 val
= (val
& ~set_mask
) |
950 (mask16
[s
->gr
[VGA_GFX_SR_VALUE
]] & set_mask
);
951 bit_mask
= s
->gr
[VGA_GFX_BIT_MASK
];
957 val
= mask16
[val
& 0x0f];
958 bit_mask
= s
->gr
[VGA_GFX_BIT_MASK
];
962 b
= s
->gr
[VGA_GFX_DATA_ROTATE
] & 7;
963 val
= (val
>> b
) | (val
<< (8 - b
));
965 bit_mask
= s
->gr
[VGA_GFX_BIT_MASK
] & val
;
966 val
= mask16
[s
->gr
[VGA_GFX_SR_VALUE
]];
970 /* apply logical operation */
971 func_select
= s
->gr
[VGA_GFX_DATA_ROTATE
] >> 3;
972 switch(func_select
) {
992 bit_mask
|= bit_mask
<< 8;
993 bit_mask
|= bit_mask
<< 16;
994 val
= (val
& bit_mask
) | (s
->latch
& ~bit_mask
);
997 /* mask data according to sr[2] */
998 mask
= sr(s
, VGA_SEQ_PLANE_WRITE
);
999 s
->plane_updated
|= mask
; /* only used to detect font change */
1000 write_mask
= mask16
[mask
];
1001 if (addr
* sizeof(uint32_t) >= s
->vram_size
) {
1004 ((uint32_t *)s
->vram_ptr
)[addr
] =
1005 (((uint32_t *)s
->vram_ptr
)[addr
] & ~write_mask
) |
1007 #ifdef DEBUG_VGA_MEM
1008 printf("vga: latch: [0x" HWADDR_FMT_plx
"] mask=0x%08x val=0x%08x\n",
1009 addr
* 4, write_mask
, val
);
1011 memory_region_set_dirty(&s
->vram
, addr
<< 2, sizeof(uint32_t));
1015 typedef void vga_draw_line_func(VGACommonState
*s1
, uint8_t *d
,
1016 uint32_t srcaddr
, int width
);
1018 #include "vga-access.h"
1019 #include "vga-helpers.h"
1021 /* return true if the palette was modified */
1022 static int update_palette16(VGACommonState
*s
)
1025 uint32_t v
, col
, *palette
;
1028 palette
= s
->last_palette
;
1029 for(i
= 0; i
< 16; i
++) {
1031 if (s
->ar
[VGA_ATC_MODE
] & 0x80) {
1032 v
= ((s
->ar
[VGA_ATC_COLOR_PAGE
] & 0xf) << 4) | (v
& 0xf);
1034 v
= ((s
->ar
[VGA_ATC_COLOR_PAGE
] & 0xc) << 4) | (v
& 0x3f);
1037 col
= rgb_to_pixel32(c6_to_8(s
->palette
[v
]),
1038 c6_to_8(s
->palette
[v
+ 1]),
1039 c6_to_8(s
->palette
[v
+ 2]));
1040 if (col
!= palette
[i
]) {
1048 /* return true if the palette was modified */
1049 static int update_palette256(VGACommonState
*s
)
1052 uint32_t v
, col
, *palette
;
1055 palette
= s
->last_palette
;
1057 for(i
= 0; i
< 256; i
++) {
1059 col
= rgb_to_pixel32(s
->palette
[v
],
1063 col
= rgb_to_pixel32(c6_to_8(s
->palette
[v
]),
1064 c6_to_8(s
->palette
[v
+ 1]),
1065 c6_to_8(s
->palette
[v
+ 2]));
1067 if (col
!= palette
[i
]) {
1076 static void vga_get_offsets(VGACommonState
*s
,
1077 uint32_t *pline_offset
,
1078 uint32_t *pstart_addr
,
1079 uint32_t *pline_compare
)
1081 uint32_t start_addr
, line_offset
, line_compare
;
1083 if (vbe_enabled(s
)) {
1084 line_offset
= s
->vbe_line_offset
;
1085 start_addr
= s
->vbe_start_addr
;
1086 line_compare
= 65535;
1088 /* compute line_offset in bytes */
1089 line_offset
= s
->cr
[VGA_CRTC_OFFSET
];
1092 /* starting address */
1093 start_addr
= s
->cr
[VGA_CRTC_START_LO
] |
1094 (s
->cr
[VGA_CRTC_START_HI
] << 8);
1097 line_compare
= s
->cr
[VGA_CRTC_LINE_COMPARE
] |
1098 ((s
->cr
[VGA_CRTC_OVERFLOW
] & 0x10) << 4) |
1099 ((s
->cr
[VGA_CRTC_MAX_SCAN
] & 0x40) << 3);
1101 *pline_offset
= line_offset
;
1102 *pstart_addr
= start_addr
;
1103 *pline_compare
= line_compare
;
1106 /* update start_addr and line_offset. Return TRUE if modified */
1107 static int update_basic_params(VGACommonState
*s
)
1110 uint32_t start_addr
, line_offset
, line_compare
;
1114 s
->get_offsets(s
, &line_offset
, &start_addr
, &line_compare
);
1116 if (line_offset
!= s
->line_offset
||
1117 start_addr
!= s
->start_addr
||
1118 line_compare
!= s
->line_compare
) {
1119 s
->line_offset
= line_offset
;
1120 s
->start_addr
= start_addr
;
1121 s
->line_compare
= line_compare
;
1128 static const uint8_t cursor_glyph
[32 * 4] = {
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,
1143 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1144 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1147 static void vga_get_text_resolution(VGACommonState
*s
, int *pwidth
, int *pheight
,
1148 int *pcwidth
, int *pcheight
)
1150 int width
, cwidth
, height
, cheight
;
1152 /* total width & height */
1153 cheight
= (s
->cr
[VGA_CRTC_MAX_SCAN
] & 0x1f) + 1;
1155 if (!(sr(s
, VGA_SEQ_CLOCK_MODE
) & VGA_SR01_CHAR_CLK_8DOTS
)) {
1158 if (sr(s
, VGA_SEQ_CLOCK_MODE
) & 0x08) {
1159 cwidth
= 16; /* NOTE: no 18 pixel wide */
1161 width
= (s
->cr
[VGA_CRTC_H_DISP
] + 1);
1162 if (s
->cr
[VGA_CRTC_V_TOTAL
] == 100) {
1163 /* ugly hack for CGA 160x100x16 - explain me the logic */
1166 height
= s
->cr
[VGA_CRTC_V_DISP_END
] |
1167 ((s
->cr
[VGA_CRTC_OVERFLOW
] & 0x02) << 7) |
1168 ((s
->cr
[VGA_CRTC_OVERFLOW
] & 0x40) << 3);
1169 height
= (height
+ 1) / cheight
;
1175 *pcheight
= cheight
;
1186 static void vga_draw_text(VGACommonState
*s
, int full_update
)
1188 DisplaySurface
*surface
= qemu_console_surface(s
->con
);
1189 int cx
, cy
, cheight
, cw
, ch
, cattr
, height
, width
, ch_attr
;
1190 int cx_min
, cx_max
, linesize
, x_incr
, line
, line1
;
1191 uint32_t offset
, fgcol
, bgcol
, v
, cursor_offset
;
1192 uint8_t *d1
, *d
, *src
, *dest
, *cursor_ptr
;
1193 const uint8_t *font_ptr
, *font_base
[2];
1194 int dup9
, line_offset
;
1196 uint32_t *ch_attr_ptr
;
1197 int64_t now
= qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL
);
1199 /* compute font data address (in plane 2) */
1200 v
= sr(s
, VGA_SEQ_CHARACTER_MAP
);
1201 offset
= (((v
>> 4) & 1) | ((v
<< 1) & 6)) * 8192 * 4 + 2;
1202 if (offset
!= s
->font_offsets
[0]) {
1203 s
->font_offsets
[0] = offset
;
1206 font_base
[0] = s
->vram_ptr
+ offset
;
1208 offset
= (((v
>> 5) & 1) | ((v
>> 1) & 6)) * 8192 * 4 + 2;
1209 font_base
[1] = s
->vram_ptr
+ offset
;
1210 if (offset
!= s
->font_offsets
[1]) {
1211 s
->font_offsets
[1] = offset
;
1214 if (s
->plane_updated
& (1 << 2) || s
->has_chain4_alias
) {
1215 /* if the plane 2 was modified since the last display, it
1216 indicates the font may have been modified */
1217 s
->plane_updated
= 0;
1220 full_update
|= update_basic_params(s
);
1222 line_offset
= s
->line_offset
;
1224 vga_get_text_resolution(s
, &width
, &height
, &cw
, &cheight
);
1225 if ((height
* width
) <= 1) {
1226 /* better than nothing: exit if transient size is too small */
1229 if ((height
* width
) > CH_ATTR_SIZE
) {
1230 /* better than nothing: exit if transient size is too big */
1234 if (width
!= s
->last_width
|| height
!= s
->last_height
||
1235 cw
!= s
->last_cw
|| cheight
!= s
->last_ch
|| s
->last_depth
) {
1236 s
->last_scr_width
= width
* cw
;
1237 s
->last_scr_height
= height
* cheight
;
1238 qemu_console_resize(s
->con
, s
->last_scr_width
, s
->last_scr_height
);
1239 surface
= qemu_console_surface(s
->con
);
1240 dpy_text_resize(s
->con
, width
, height
);
1242 s
->last_width
= width
;
1243 s
->last_height
= height
;
1244 s
->last_ch
= cheight
;
1248 full_update
|= update_palette16(s
);
1249 palette
= s
->last_palette
;
1250 x_incr
= cw
* surface_bytes_per_pixel(surface
);
1253 s
->full_update_text
= 1;
1255 if (s
->full_update_gfx
) {
1256 s
->full_update_gfx
= 0;
1260 cursor_offset
= ((s
->cr
[VGA_CRTC_CURSOR_HI
] << 8) |
1261 s
->cr
[VGA_CRTC_CURSOR_LO
]) - s
->start_addr
;
1262 if (cursor_offset
!= s
->cursor_offset
||
1263 s
->cr
[VGA_CRTC_CURSOR_START
] != s
->cursor_start
||
1264 s
->cr
[VGA_CRTC_CURSOR_END
] != s
->cursor_end
) {
1265 /* if the cursor position changed, we update the old and new
1267 if (s
->cursor_offset
< CH_ATTR_SIZE
)
1268 s
->last_ch_attr
[s
->cursor_offset
] = -1;
1269 if (cursor_offset
< CH_ATTR_SIZE
)
1270 s
->last_ch_attr
[cursor_offset
] = -1;
1271 s
->cursor_offset
= cursor_offset
;
1272 s
->cursor_start
= s
->cr
[VGA_CRTC_CURSOR_START
];
1273 s
->cursor_end
= s
->cr
[VGA_CRTC_CURSOR_END
];
1275 cursor_ptr
= s
->vram_ptr
+ (s
->start_addr
+ cursor_offset
) * 4;
1276 if (now
>= s
->cursor_blink_time
) {
1277 s
->cursor_blink_time
= now
+ VGA_TEXT_CURSOR_PERIOD_MS
/ 2;
1278 s
->cursor_visible_phase
= !s
->cursor_visible_phase
;
1281 dest
= surface_data(surface
);
1282 linesize
= surface_stride(surface
);
1283 ch_attr_ptr
= s
->last_ch_attr
;
1285 offset
= s
->start_addr
* 4;
1286 for(cy
= 0; cy
< height
; cy
++) {
1288 src
= s
->vram_ptr
+ offset
;
1291 for(cx
= 0; cx
< width
; cx
++) {
1292 if (src
+ sizeof(uint16_t) > s
->vram_ptr
+ s
->vram_size
) {
1295 ch_attr
= *(uint16_t *)src
;
1296 if (full_update
|| ch_attr
!= *ch_attr_ptr
|| src
== cursor_ptr
) {
1301 *ch_attr_ptr
= ch_attr
;
1304 cattr
= ch_attr
& 0xff;
1306 ch
= ch_attr
& 0xff;
1307 cattr
= ch_attr
>> 8;
1309 font_ptr
= font_base
[(cattr
>> 3) & 1];
1310 font_ptr
+= 32 * 4 * ch
;
1311 bgcol
= palette
[cattr
>> 4];
1312 fgcol
= palette
[cattr
& 0x0f];
1314 vga_draw_glyph16(d1
, linesize
,
1315 font_ptr
, cheight
, fgcol
, bgcol
);
1316 } else if (cw
!= 9) {
1317 vga_draw_glyph8(d1
, linesize
,
1318 font_ptr
, cheight
, fgcol
, bgcol
);
1321 if (ch
>= 0xb0 && ch
<= 0xdf &&
1322 (s
->ar
[VGA_ATC_MODE
] & 0x04)) {
1325 vga_draw_glyph9(d1
, linesize
,
1326 font_ptr
, cheight
, fgcol
, bgcol
, dup9
);
1328 if (src
== cursor_ptr
&&
1329 !(s
->cr
[VGA_CRTC_CURSOR_START
] & 0x20) &&
1330 s
->cursor_visible_phase
) {
1331 int line_start
, line_last
, h
;
1332 /* draw the cursor */
1333 line_start
= s
->cr
[VGA_CRTC_CURSOR_START
] & 0x1f;
1334 line_last
= s
->cr
[VGA_CRTC_CURSOR_END
] & 0x1f;
1335 /* XXX: check that */
1336 if (line_last
> cheight
- 1)
1337 line_last
= cheight
- 1;
1338 if (line_last
>= line_start
&& line_start
< cheight
) {
1339 h
= line_last
- line_start
+ 1;
1340 d
= d1
+ linesize
* line_start
;
1342 vga_draw_glyph16(d
, linesize
,
1343 cursor_glyph
, h
, fgcol
, bgcol
);
1344 } else if (cw
!= 9) {
1345 vga_draw_glyph8(d
, linesize
,
1346 cursor_glyph
, h
, fgcol
, bgcol
);
1348 vga_draw_glyph9(d
, linesize
,
1349 cursor_glyph
, h
, fgcol
, bgcol
, 1);
1359 dpy_gfx_update(s
->con
, cx_min
* cw
, cy
* cheight
,
1360 (cx_max
- cx_min
+ 1) * cw
, cheight
);
1362 dest
+= linesize
* cheight
;
1363 line1
= line
+ cheight
;
1364 offset
+= line_offset
;
1365 if (line
< s
->line_compare
&& line1
>= s
->line_compare
) {
1390 static vga_draw_line_func
* const vga_draw_line_table
[VGA_DRAW_LINE_NB
] = {
1407 static int vga_get_bpp(VGACommonState
*s
)
1411 if (vbe_enabled(s
)) {
1412 ret
= s
->vbe_regs
[VBE_DISPI_INDEX_BPP
];
1419 static void vga_get_resolution(VGACommonState
*s
, int *pwidth
, int *pheight
)
1423 if (vbe_enabled(s
)) {
1424 width
= s
->vbe_regs
[VBE_DISPI_INDEX_XRES
];
1425 height
= s
->vbe_regs
[VBE_DISPI_INDEX_YRES
];
1427 width
= (s
->cr
[VGA_CRTC_H_DISP
] + 1) * 8;
1428 height
= s
->cr
[VGA_CRTC_V_DISP_END
] |
1429 ((s
->cr
[VGA_CRTC_OVERFLOW
] & 0x02) << 7) |
1430 ((s
->cr
[VGA_CRTC_OVERFLOW
] & 0x40) << 3);
1431 height
= (height
+ 1);
1437 void vga_invalidate_scanlines(VGACommonState
*s
, int y1
, int y2
)
1440 if (y1
>= VGA_MAX_HEIGHT
)
1442 if (y2
>= VGA_MAX_HEIGHT
)
1443 y2
= VGA_MAX_HEIGHT
;
1444 for(y
= y1
; y
< y2
; y
++) {
1445 s
->invalidated_y_table
[y
>> 5] |= 1 << (y
& 0x1f);
1449 static bool vga_scanline_invalidated(VGACommonState
*s
, int y
)
1451 if (y
>= VGA_MAX_HEIGHT
) {
1454 return s
->invalidated_y_table
[y
>> 5] & (1 << (y
& 0x1f));
1457 void vga_dirty_log_start(VGACommonState
*s
)
1459 memory_region_set_log(&s
->vram
, true, DIRTY_MEMORY_VGA
);
1462 void vga_dirty_log_stop(VGACommonState
*s
)
1464 memory_region_set_log(&s
->vram
, false, DIRTY_MEMORY_VGA
);
1470 static void vga_draw_graphic(VGACommonState
*s
, int full_update
)
1472 DisplaySurface
*surface
= qemu_console_surface(s
->con
);
1473 int y1
, y
, update
, linesize
, y_start
, double_scan
, mask
, depth
;
1474 int width
, height
, shift_control
, bwidth
, bits
;
1475 ram_addr_t page0
, page1
, region_start
, region_end
;
1476 DirtyBitmapSnapshot
*snap
= NULL
;
1477 int disp_width
, multi_scan
, multi_run
;
1479 uint32_t v
, addr1
, addr
;
1480 vga_draw_line_func
*vga_draw_line
= NULL
;
1481 bool share_surface
, force_shadow
= false;
1482 pixman_format_code_t format
;
1484 bool byteswap
= !s
->big_endian_fb
;
1486 bool byteswap
= s
->big_endian_fb
;
1489 full_update
|= update_basic_params(s
);
1491 s
->get_resolution(s
, &width
, &height
);
1493 depth
= s
->get_bpp(s
);
1495 region_start
= (s
->start_addr
* 4);
1496 region_end
= region_start
+ (ram_addr_t
)s
->line_offset
* height
;
1497 region_end
+= width
* depth
/ 8; /* scanline length */
1498 region_end
-= s
->line_offset
;
1499 if (region_end
> s
->vbe_size
|| depth
== 0 || depth
== 15) {
1502 * - wraps around (can happen with cirrus vbe modes)
1503 * - depth == 0 (256 color palette video mode)
1506 * Take the safe and slow route:
1507 * - create a dirty bitmap snapshot for all vga memory.
1508 * - force shadowing (so all vga memory access goes
1509 * through vga_read_*() helpers).
1511 * Given this affects only vga features which are pretty much
1512 * unused by modern guests there should be no performance
1516 region_end
= s
->vbe_size
;
1517 force_shadow
= true;
1520 /* bits 5-6: 0 = 16-color mode, 1 = 4-color mode, 2 = 256-color mode. */
1521 shift_control
= (s
->gr
[VGA_GFX_MODE
] >> 5) & 3;
1522 double_scan
= (s
->cr
[VGA_CRTC_MAX_SCAN
] >> 7);
1523 if (s
->cr
[VGA_CRTC_MODE
] & 1) {
1524 multi_scan
= (((s
->cr
[VGA_CRTC_MAX_SCAN
] & 0x1f) + 1) << double_scan
)
1527 /* in CGA modes, multi_scan is ignored */
1528 /* XXX: is it correct ? */
1529 multi_scan
= double_scan
;
1531 multi_run
= multi_scan
;
1532 if (shift_control
!= s
->shift_control
||
1533 double_scan
!= s
->double_scan
) {
1535 s
->shift_control
= shift_control
;
1536 s
->double_scan
= double_scan
;
1539 if (shift_control
== 0) {
1540 if (sr(s
, VGA_SEQ_CLOCK_MODE
) & 8) {
1543 } else if (shift_control
== 1) {
1544 if (sr(s
, VGA_SEQ_CLOCK_MODE
) & 8) {
1550 * Check whether we can share the surface with the backend
1551 * or whether we need a shadow surface. We share native
1552 * endian surfaces for 15bpp and above and byteswapped
1553 * surfaces for 24bpp and above.
1555 format
= qemu_default_pixman_format(depth
, !byteswap
);
1557 share_surface
= dpy_gfx_check_format(s
->con
, format
)
1558 && !s
->force_shadow
&& !force_shadow
;
1560 share_surface
= false;
1563 if (s
->line_offset
!= s
->last_line_offset
||
1564 disp_width
!= s
->last_width
||
1565 height
!= s
->last_height
||
1566 s
->last_depth
!= depth
||
1567 s
->last_byteswap
!= byteswap
||
1568 share_surface
!= is_buffer_shared(surface
)) {
1569 /* display parameters changed -> need new display surface */
1570 s
->last_scr_width
= disp_width
;
1571 s
->last_scr_height
= height
;
1572 s
->last_width
= disp_width
;
1573 s
->last_height
= height
;
1574 s
->last_line_offset
= s
->line_offset
;
1575 s
->last_depth
= depth
;
1576 s
->last_byteswap
= byteswap
;
1579 if (surface_data(surface
) != s
->vram_ptr
+ (s
->start_addr
* 4)
1580 && is_buffer_shared(surface
)) {
1581 /* base address changed (page flip) -> shared display surfaces
1582 * must be updated with the new base address */
1587 if (share_surface
) {
1588 surface
= qemu_create_displaysurface_from(disp_width
,
1589 height
, format
, s
->line_offset
,
1590 s
->vram_ptr
+ (s
->start_addr
* 4));
1591 dpy_gfx_replace_surface(s
->con
, surface
);
1593 qemu_console_resize(s
->con
, disp_width
, height
);
1594 surface
= qemu_console_surface(s
->con
);
1598 if (shift_control
== 0) {
1599 full_update
|= update_palette16(s
);
1600 if (sr(s
, VGA_SEQ_CLOCK_MODE
) & 8) {
1601 v
= VGA_DRAW_LINE4D2
;
1606 } else if (shift_control
== 1) {
1607 full_update
|= update_palette16(s
);
1608 if (sr(s
, VGA_SEQ_CLOCK_MODE
) & 8) {
1609 v
= VGA_DRAW_LINE2D2
;
1615 switch(s
->get_bpp(s
)) {
1618 full_update
|= update_palette256(s
);
1619 v
= VGA_DRAW_LINE8D2
;
1623 full_update
|= update_palette256(s
);
1628 v
= s
->big_endian_fb
? VGA_DRAW_LINE15_BE
: VGA_DRAW_LINE15_LE
;
1632 v
= s
->big_endian_fb
? VGA_DRAW_LINE16_BE
: VGA_DRAW_LINE16_LE
;
1636 v
= s
->big_endian_fb
? VGA_DRAW_LINE24_BE
: VGA_DRAW_LINE24_LE
;
1640 v
= s
->big_endian_fb
? VGA_DRAW_LINE32_BE
: VGA_DRAW_LINE32_LE
;
1645 vga_draw_line
= vga_draw_line_table
[v
];
1647 if (!is_buffer_shared(surface
) && s
->cursor_invalidate
) {
1648 s
->cursor_invalidate(s
);
1652 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",
1653 width
, height
, v
, line_offset
, s
->cr
[9], s
->cr
[VGA_CRTC_MODE
],
1654 s
->line_compare
, sr(s
, VGA_SEQ_CLOCK_MODE
));
1656 addr1
= (s
->start_addr
* 4);
1657 bwidth
= DIV_ROUND_UP(width
* bits
, 8);
1659 d
= surface_data(surface
);
1660 linesize
= surface_stride(surface
);
1664 if (s
->line_compare
< height
) {
1665 /* split screen mode */
1668 snap
= memory_region_snapshot_and_clear_dirty(&s
->vram
, region_start
,
1669 region_end
- region_start
,
1673 for(y
= 0; y
< height
; y
++) {
1675 if (!(s
->cr
[VGA_CRTC_MODE
] & 1)) {
1677 /* CGA compatibility handling */
1678 shift
= 14 + ((s
->cr
[VGA_CRTC_MODE
] >> 6) & 1);
1679 addr
= (addr
& ~(1 << shift
)) | ((y1
& 1) << shift
);
1681 if (!(s
->cr
[VGA_CRTC_MODE
] & 2)) {
1682 addr
= (addr
& ~0x8000) | ((y1
& 2) << 14);
1684 page0
= addr
& s
->vbe_size_mask
;
1685 page1
= (addr
+ bwidth
- 1) & s
->vbe_size_mask
;
1688 } else if (page1
< page0
) {
1689 /* scanline wraps from end of video memory to the start */
1690 assert(force_shadow
);
1691 update
= memory_region_snapshot_get_dirty(&s
->vram
, snap
,
1692 page0
, s
->vbe_size
- page0
);
1693 update
|= memory_region_snapshot_get_dirty(&s
->vram
, snap
,
1696 update
= memory_region_snapshot_get_dirty(&s
->vram
, snap
,
1697 page0
, page1
- page0
);
1699 /* explicit invalidation for the hardware cursor (cirrus only) */
1700 update
|= vga_scanline_invalidated(s
, y
);
1704 if (!(is_buffer_shared(surface
))) {
1705 vga_draw_line(s
, d
, addr
, width
);
1706 if (s
->cursor_draw_line
)
1707 s
->cursor_draw_line(s
, d
, y
);
1711 /* flush to display */
1712 dpy_gfx_update(s
->con
, 0, y_start
,
1713 disp_width
, y
- y_start
);
1718 mask
= (s
->cr
[VGA_CRTC_MODE
] & 3) ^ 3;
1719 if ((y1
& mask
) == mask
)
1720 addr1
+= s
->line_offset
;
1722 multi_run
= multi_scan
;
1726 /* line compare acts on the displayed lines */
1727 if (y
== s
->line_compare
)
1732 /* flush to display */
1733 dpy_gfx_update(s
->con
, 0, y_start
,
1734 disp_width
, y
- y_start
);
1737 memset(s
->invalidated_y_table
, 0, sizeof(s
->invalidated_y_table
));
1740 static void vga_draw_blank(VGACommonState
*s
, int full_update
)
1742 DisplaySurface
*surface
= qemu_console_surface(s
->con
);
1748 if (s
->last_scr_width
<= 0 || s
->last_scr_height
<= 0)
1751 w
= s
->last_scr_width
* surface_bytes_per_pixel(surface
);
1752 d
= surface_data(surface
);
1753 for(i
= 0; i
< s
->last_scr_height
; i
++) {
1755 d
+= surface_stride(surface
);
1757 dpy_gfx_update_full(s
->con
);
1760 #define GMODE_TEXT 0
1761 #define GMODE_GRAPH 1
1762 #define GMODE_BLANK 2
1764 static void vga_update_display(void *opaque
)
1766 VGACommonState
*s
= opaque
;
1767 DisplaySurface
*surface
= qemu_console_surface(s
->con
);
1768 int full_update
, graphic_mode
;
1770 qemu_flush_coalesced_mmio_buffer();
1772 if (surface_bits_per_pixel(surface
) == 0) {
1776 if (!(s
->ar_index
& 0x20)) {
1777 graphic_mode
= GMODE_BLANK
;
1779 graphic_mode
= s
->gr
[VGA_GFX_MISC
] & VGA_GR06_GRAPHICS_MODE
;
1781 if (graphic_mode
!= s
->graphic_mode
) {
1782 s
->graphic_mode
= graphic_mode
;
1783 s
->cursor_blink_time
= qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL
);
1786 switch(graphic_mode
) {
1788 vga_draw_text(s
, full_update
);
1791 vga_draw_graphic(s
, full_update
);
1795 vga_draw_blank(s
, full_update
);
1801 /* force a full display refresh */
1802 static void vga_invalidate_display(void *opaque
)
1804 VGACommonState
*s
= opaque
;
1807 s
->last_height
= -1;
1810 void vga_common_reset(VGACommonState
*s
)
1813 memset(s
->sr
, '\0', sizeof(s
->sr
));
1814 memset(s
->sr_vbe
, '\0', sizeof(s
->sr_vbe
));
1816 memset(s
->gr
, '\0', sizeof(s
->gr
));
1818 memset(s
->ar
, '\0', sizeof(s
->ar
));
1819 s
->ar_flip_flop
= 0;
1821 memset(s
->cr
, '\0', sizeof(s
->cr
));
1827 s
->dac_sub_index
= 0;
1828 s
->dac_read_index
= 0;
1829 s
->dac_write_index
= 0;
1830 memset(s
->dac_cache
, '\0', sizeof(s
->dac_cache
));
1832 memset(s
->palette
, '\0', sizeof(s
->palette
));
1835 memset(s
->vbe_regs
, '\0', sizeof(s
->vbe_regs
));
1836 s
->vbe_regs
[VBE_DISPI_INDEX_ID
] = VBE_DISPI_ID5
;
1837 s
->vbe_start_addr
= 0;
1838 s
->vbe_line_offset
= 0;
1839 s
->vbe_bank_mask
= (s
->vram_size
>> 16) - 1;
1840 memset(s
->font_offsets
, '\0', sizeof(s
->font_offsets
));
1841 s
->graphic_mode
= -1; /* force full update */
1842 s
->shift_control
= 0;
1845 s
->line_compare
= 0;
1847 s
->plane_updated
= 0;
1852 s
->last_scr_width
= 0;
1853 s
->last_scr_height
= 0;
1854 s
->cursor_start
= 0;
1856 s
->cursor_offset
= 0;
1857 s
->big_endian_fb
= s
->default_endian_fb
;
1858 memset(s
->invalidated_y_table
, '\0', sizeof(s
->invalidated_y_table
));
1859 memset(s
->last_palette
, '\0', sizeof(s
->last_palette
));
1860 memset(s
->last_ch_attr
, '\0', sizeof(s
->last_ch_attr
));
1861 switch (vga_retrace_method
) {
1862 case VGA_RETRACE_DUMB
:
1864 case VGA_RETRACE_PRECISE
:
1865 memset(&s
->retrace_info
, 0, sizeof (s
->retrace_info
));
1868 vga_update_memory_access(s
);
1871 static void vga_reset(void *opaque
)
1873 VGACommonState
*s
= opaque
;
1874 vga_common_reset(s
);
1877 #define TEXTMODE_X(x) ((x) % width)
1878 #define TEXTMODE_Y(x) ((x) / width)
1879 #define VMEM2CHTYPE(v) ((v & 0xff0007ff) | \
1880 ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1))
1881 /* relay text rendering to the display driver
1882 * instead of doing a full vga_update_display() */
1883 static void vga_update_text(void *opaque
, console_ch_t
*chardata
)
1885 VGACommonState
*s
= opaque
;
1886 int graphic_mode
, i
, cursor_offset
, cursor_visible
;
1887 int cw
, cheight
, width
, height
, size
, c_min
, c_max
;
1889 console_ch_t
*dst
, val
;
1890 char msg_buffer
[80];
1891 int full_update
= 0;
1893 qemu_flush_coalesced_mmio_buffer();
1895 if (!(s
->ar_index
& 0x20)) {
1896 graphic_mode
= GMODE_BLANK
;
1898 graphic_mode
= s
->gr
[VGA_GFX_MISC
] & VGA_GR06_GRAPHICS_MODE
;
1900 if (graphic_mode
!= s
->graphic_mode
) {
1901 s
->graphic_mode
= graphic_mode
;
1904 if (s
->last_width
== -1) {
1909 switch (graphic_mode
) {
1911 /* TODO: update palette */
1912 full_update
|= update_basic_params(s
);
1914 /* total width & height */
1915 cheight
= (s
->cr
[VGA_CRTC_MAX_SCAN
] & 0x1f) + 1;
1917 if (!(sr(s
, VGA_SEQ_CLOCK_MODE
) & VGA_SR01_CHAR_CLK_8DOTS
)) {
1920 if (sr(s
, VGA_SEQ_CLOCK_MODE
) & 0x08) {
1921 cw
= 16; /* NOTE: no 18 pixel wide */
1923 width
= (s
->cr
[VGA_CRTC_H_DISP
] + 1);
1924 if (s
->cr
[VGA_CRTC_V_TOTAL
] == 100) {
1925 /* ugly hack for CGA 160x100x16 - explain me the logic */
1928 height
= s
->cr
[VGA_CRTC_V_DISP_END
] |
1929 ((s
->cr
[VGA_CRTC_OVERFLOW
] & 0x02) << 7) |
1930 ((s
->cr
[VGA_CRTC_OVERFLOW
] & 0x40) << 3);
1931 height
= (height
+ 1) / cheight
;
1934 size
= (height
* width
);
1935 if (size
> CH_ATTR_SIZE
) {
1939 snprintf(msg_buffer
, sizeof(msg_buffer
), "%i x %i Text mode",
1944 if (width
!= s
->last_width
|| height
!= s
->last_height
||
1945 cw
!= s
->last_cw
|| cheight
!= s
->last_ch
) {
1946 s
->last_scr_width
= width
* cw
;
1947 s
->last_scr_height
= height
* cheight
;
1948 qemu_console_resize(s
->con
, s
->last_scr_width
, s
->last_scr_height
);
1949 dpy_text_resize(s
->con
, width
, height
);
1951 s
->last_width
= width
;
1952 s
->last_height
= height
;
1953 s
->last_ch
= cheight
;
1959 s
->full_update_gfx
= 1;
1961 if (s
->full_update_text
) {
1962 s
->full_update_text
= 0;
1966 /* Update "hardware" cursor */
1967 cursor_offset
= ((s
->cr
[VGA_CRTC_CURSOR_HI
] << 8) |
1968 s
->cr
[VGA_CRTC_CURSOR_LO
]) - s
->start_addr
;
1969 if (cursor_offset
!= s
->cursor_offset
||
1970 s
->cr
[VGA_CRTC_CURSOR_START
] != s
->cursor_start
||
1971 s
->cr
[VGA_CRTC_CURSOR_END
] != s
->cursor_end
|| full_update
) {
1972 cursor_visible
= !(s
->cr
[VGA_CRTC_CURSOR_START
] & 0x20);
1973 if (cursor_visible
&& cursor_offset
< size
&& cursor_offset
>= 0)
1974 dpy_text_cursor(s
->con
,
1975 TEXTMODE_X(cursor_offset
),
1976 TEXTMODE_Y(cursor_offset
));
1978 dpy_text_cursor(s
->con
, -1, -1);
1979 s
->cursor_offset
= cursor_offset
;
1980 s
->cursor_start
= s
->cr
[VGA_CRTC_CURSOR_START
];
1981 s
->cursor_end
= s
->cr
[VGA_CRTC_CURSOR_END
];
1984 src
= (uint32_t *) s
->vram_ptr
+ s
->start_addr
;
1988 for (i
= 0; i
< size
; src
++, dst
++, i
++)
1989 console_write_ch(dst
, VMEM2CHTYPE(le32_to_cpu(*src
)));
1991 dpy_text_update(s
->con
, 0, 0, width
, height
);
1995 for (i
= 0; i
< size
; src
++, dst
++, i
++) {
1996 console_write_ch(&val
, VMEM2CHTYPE(le32_to_cpu(*src
)));
2004 for (; i
< size
; src
++, dst
++, i
++) {
2005 console_write_ch(&val
, VMEM2CHTYPE(le32_to_cpu(*src
)));
2012 if (c_min
<= c_max
) {
2013 i
= TEXTMODE_Y(c_min
);
2014 dpy_text_update(s
->con
, 0, i
, width
, TEXTMODE_Y(c_max
) - i
+ 1);
2023 s
->get_resolution(s
, &width
, &height
);
2024 snprintf(msg_buffer
, sizeof(msg_buffer
), "%i x %i Graphic mode",
2032 snprintf(msg_buffer
, sizeof(msg_buffer
), "VGA Blank mode");
2036 /* Display a message */
2038 s
->last_height
= height
= 3;
2039 dpy_text_cursor(s
->con
, -1, -1);
2040 dpy_text_resize(s
->con
, s
->last_width
, height
);
2042 for (dst
= chardata
, i
= 0; i
< s
->last_width
* height
; i
++)
2043 console_write_ch(dst
++, ' ');
2045 size
= strlen(msg_buffer
);
2046 width
= (s
->last_width
- size
) / 2;
2047 dst
= chardata
+ s
->last_width
+ width
;
2048 for (i
= 0; i
< size
; i
++)
2049 console_write_ch(dst
++, ATTR2CHTYPE(msg_buffer
[i
], QEMU_COLOR_BLUE
,
2050 QEMU_COLOR_BLACK
, 1));
2052 dpy_text_update(s
->con
, 0, 0, s
->last_width
, height
);
2055 static uint64_t vga_mem_read(void *opaque
, hwaddr addr
,
2058 VGACommonState
*s
= opaque
;
2060 return vga_mem_readb(s
, addr
);
2063 static void vga_mem_write(void *opaque
, hwaddr addr
,
2064 uint64_t data
, unsigned size
)
2066 VGACommonState
*s
= opaque
;
2068 vga_mem_writeb(s
, addr
, data
);
2071 const MemoryRegionOps vga_mem_ops
= {
2072 .read
= vga_mem_read
,
2073 .write
= vga_mem_write
,
2074 .endianness
= DEVICE_LITTLE_ENDIAN
,
2076 .min_access_size
= 1,
2077 .max_access_size
= 1,
2081 static int vga_common_post_load(void *opaque
, int version_id
)
2083 VGACommonState
*s
= opaque
;
2086 s
->graphic_mode
= -1;
2087 vbe_update_vgaregs(s
);
2088 vga_update_memory_access(s
);
2092 static bool vga_endian_state_needed(void *opaque
)
2094 VGACommonState
*s
= opaque
;
2097 * Only send the endian state if it's different from the
2098 * default one, thus ensuring backward compatibility for
2099 * migration of the common case
2101 return s
->default_endian_fb
!= s
->big_endian_fb
;
2104 static const VMStateDescription vmstate_vga_endian
= {
2105 .name
= "vga.endian",
2107 .minimum_version_id
= 1,
2108 .needed
= vga_endian_state_needed
,
2109 .fields
= (VMStateField
[]) {
2110 VMSTATE_BOOL(big_endian_fb
, VGACommonState
),
2111 VMSTATE_END_OF_LIST()
2115 const VMStateDescription vmstate_vga_common
= {
2118 .minimum_version_id
= 2,
2119 .post_load
= vga_common_post_load
,
2120 .fields
= (VMStateField
[]) {
2121 VMSTATE_UINT32(latch
, VGACommonState
),
2122 VMSTATE_UINT8(sr_index
, VGACommonState
),
2123 VMSTATE_PARTIAL_BUFFER(sr
, VGACommonState
, 8),
2124 VMSTATE_UINT8(gr_index
, VGACommonState
),
2125 VMSTATE_PARTIAL_BUFFER(gr
, VGACommonState
, 16),
2126 VMSTATE_UINT8(ar_index
, VGACommonState
),
2127 VMSTATE_BUFFER(ar
, VGACommonState
),
2128 VMSTATE_INT32(ar_flip_flop
, VGACommonState
),
2129 VMSTATE_UINT8(cr_index
, VGACommonState
),
2130 VMSTATE_BUFFER(cr
, VGACommonState
),
2131 VMSTATE_UINT8(msr
, VGACommonState
),
2132 VMSTATE_UINT8(fcr
, VGACommonState
),
2133 VMSTATE_UINT8(st00
, VGACommonState
),
2134 VMSTATE_UINT8(st01
, VGACommonState
),
2136 VMSTATE_UINT8(dac_state
, VGACommonState
),
2137 VMSTATE_UINT8(dac_sub_index
, VGACommonState
),
2138 VMSTATE_UINT8(dac_read_index
, VGACommonState
),
2139 VMSTATE_UINT8(dac_write_index
, VGACommonState
),
2140 VMSTATE_BUFFER(dac_cache
, VGACommonState
),
2141 VMSTATE_BUFFER(palette
, VGACommonState
),
2143 VMSTATE_INT32(bank_offset
, VGACommonState
),
2144 VMSTATE_UINT8_EQUAL(is_vbe_vmstate
, VGACommonState
, NULL
),
2145 VMSTATE_UINT16(vbe_index
, VGACommonState
),
2146 VMSTATE_UINT16_ARRAY(vbe_regs
, VGACommonState
, VBE_DISPI_INDEX_NB
),
2147 VMSTATE_UINT32(vbe_start_addr
, VGACommonState
),
2148 VMSTATE_UINT32(vbe_line_offset
, VGACommonState
),
2149 VMSTATE_UINT32(vbe_bank_mask
, VGACommonState
),
2150 VMSTATE_END_OF_LIST()
2152 .subsections
= (const VMStateDescription
*[]) {
2153 &vmstate_vga_endian
,
2158 static const GraphicHwOps vga_ops
= {
2159 .invalidate
= vga_invalidate_display
,
2160 .gfx_update
= vga_update_display
,
2161 .text_update
= vga_update_text
,
2164 static inline uint32_t uint_clamp(uint32_t val
, uint32_t vmin
, uint32_t vmax
)
2175 bool vga_common_init(VGACommonState
*s
, Object
*obj
, Error
**errp
)
2178 Error
*local_err
= NULL
;
2180 for(i
= 0;i
< 256; i
++) {
2182 for(j
= 0; j
< 8; j
++) {
2183 v
|= ((i
>> j
) & 1) << (j
* 4);
2188 for(j
= 0; j
< 4; j
++) {
2189 v
|= ((i
>> (2 * j
)) & 3) << (j
* 4);
2193 for(i
= 0; i
< 16; i
++) {
2195 for(j
= 0; j
< 4; j
++) {
2198 v
|= b
<< (2 * j
+ 1);
2203 s
->vram_size_mb
= uint_clamp(s
->vram_size_mb
, 1, 512);
2204 s
->vram_size_mb
= pow2ceil(s
->vram_size_mb
);
2205 s
->vram_size
= s
->vram_size_mb
* MiB
;
2208 s
->vbe_size
= s
->vram_size
;
2210 s
->vbe_size_mask
= s
->vbe_size
- 1;
2212 s
->is_vbe_vmstate
= 1;
2214 if (s
->global_vmstate
&& qemu_ram_block_by_name("vga.vram")) {
2215 error_setg(errp
, "Only one global VGA device can be used at a time");
2219 memory_region_init_ram_nomigrate(&s
->vram
, obj
, "vga.vram", s
->vram_size
,
2222 error_propagate(errp
, local_err
);
2225 vmstate_register_ram(&s
->vram
, s
->global_vmstate
? NULL
: DEVICE(obj
));
2226 xen_register_framebuffer(&s
->vram
);
2227 s
->vram_ptr
= memory_region_get_ram_ptr(&s
->vram
);
2228 s
->get_bpp
= vga_get_bpp
;
2229 s
->get_offsets
= vga_get_offsets
;
2230 s
->get_resolution
= vga_get_resolution
;
2231 s
->hw_ops
= &vga_ops
;
2232 switch (vga_retrace_method
) {
2233 case VGA_RETRACE_DUMB
:
2234 s
->retrace
= vga_dumb_retrace
;
2235 s
->update_retrace_info
= vga_dumb_update_retrace_info
;
2238 case VGA_RETRACE_PRECISE
:
2239 s
->retrace
= vga_precise_retrace
;
2240 s
->update_retrace_info
= vga_precise_update_retrace_info
;
2245 * Set default fb endian based on target, could probably be turned
2246 * into a device attribute set by the machine/platform to remove
2247 * all target endian dependencies from this file.
2249 s
->default_endian_fb
= target_words_bigendian();
2251 vga_dirty_log_start(s
);
2256 static const MemoryRegionPortio vga_portio_list
[] = {
2257 { 0x04, 2, 1, .read
= vga_ioport_read
, .write
= vga_ioport_write
}, /* 3b4 */
2258 { 0x0a, 1, 1, .read
= vga_ioport_read
, .write
= vga_ioport_write
}, /* 3ba */
2259 { 0x10, 16, 1, .read
= vga_ioport_read
, .write
= vga_ioport_write
}, /* 3c0 */
2260 { 0x24, 2, 1, .read
= vga_ioport_read
, .write
= vga_ioport_write
}, /* 3d4 */
2261 { 0x2a, 1, 1, .read
= vga_ioport_read
, .write
= vga_ioport_write
}, /* 3da */
2262 PORTIO_END_OF_LIST(),
2265 static const MemoryRegionPortio vbe_portio_list_x86
[] = {
2266 { 0, 1, 2, .read
= vbe_ioport_read_index
, .write
= vbe_ioport_write_index
},
2267 { 1, 1, 2, .read
= vbe_ioport_read_data
, .write
= vbe_ioport_write_data
},
2268 { 2, 1, 2, .read
= vbe_ioport_read_data
, .write
= vbe_ioport_write_data
},
2269 PORTIO_END_OF_LIST(),
2272 static const MemoryRegionPortio vbe_portio_list_no_x86
[] = {
2273 { 0, 1, 2, .read
= vbe_ioport_read_index
, .write
= vbe_ioport_write_index
},
2274 { 2, 1, 2, .read
= vbe_ioport_read_data
, .write
= vbe_ioport_write_data
},
2275 PORTIO_END_OF_LIST(),
2278 /* Used by both ISA and PCI */
2279 MemoryRegion
*vga_init_io(VGACommonState
*s
, Object
*obj
,
2280 const MemoryRegionPortio
**vga_ports
,
2281 const MemoryRegionPortio
**vbe_ports
)
2283 MemoryRegion
*vga_mem
;
2284 MachineState
*ms
= MACHINE(qdev_get_machine());
2287 * We unfortunately need two VBE lists since non-x86 machines might
2288 * not be able to do 16-bit accesses at unaligned addresses (0x1cf)
2290 if (object_dynamic_cast(OBJECT(ms
), TYPE_X86_MACHINE
)) {
2291 *vbe_ports
= vbe_portio_list_x86
;
2293 *vbe_ports
= vbe_portio_list_no_x86
;
2296 *vga_ports
= vga_portio_list
;
2298 vga_mem
= g_malloc(sizeof(*vga_mem
));
2299 memory_region_init_io(vga_mem
, obj
, &vga_mem_ops
, s
,
2300 "vga-lowmem", 0x20000);
2301 memory_region_set_flush_coalesced(vga_mem
);
2306 void vga_init(VGACommonState
*s
, Object
*obj
, MemoryRegion
*address_space
,
2307 MemoryRegion
*address_space_io
, bool init_vga_ports
)
2309 MemoryRegion
*vga_io_memory
;
2310 const MemoryRegionPortio
*vga_ports
, *vbe_ports
;
2312 qemu_register_reset(vga_reset
, s
);
2316 s
->legacy_address_space
= address_space
;
2318 vga_io_memory
= vga_init_io(s
, obj
, &vga_ports
, &vbe_ports
);
2319 memory_region_add_subregion_overlap(address_space
,
2323 memory_region_set_coalescing(vga_io_memory
);
2324 if (init_vga_ports
) {
2325 portio_list_init(&s
->vga_port_list
, obj
, vga_ports
, s
, "vga");
2326 portio_list_set_flush_coalesced(&s
->vga_port_list
);
2327 portio_list_add(&s
->vga_port_list
, address_space_io
, 0x3b0);
2330 portio_list_init(&s
->vbe_port_list
, obj
, vbe_ports
, s
, "vbe");
2331 portio_list_add(&s
->vbe_port_list
, address_space_io
, 0x1ce);