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
26 #include "ui/console.h"
27 #include "hw/i386/pc.h"
28 #include "hw/pci/pci.h"
30 #include "ui/pixel_ops.h"
31 #include "qemu/timer.h"
32 #include "hw/xen/xen.h"
36 //#define DEBUG_VGA_MEM
37 //#define DEBUG_VGA_REG
39 //#define DEBUG_BOCHS_VBE
41 /* 16 state changes per vertical frame @60 Hz */
42 #define VGA_TEXT_CURSOR_PERIOD_MS (1000 * 2 * 16 / 60)
45 * Video Graphics Array (VGA)
47 * Chipset docs for original IBM VGA:
48 * http://www.mcamafia.de/pdf/ibm_vgaxga_trm2.pdf
51 * http://www.osdever.net/FreeVGA/home.htm
53 * Standard VGA features and Bochs VBE extensions are implemented.
56 /* force some bits to zero */
57 const uint8_t sr_mask
[8] = {
68 const uint8_t gr_mask
[16] = {
87 #define cbswap_32(__x) \
89 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
90 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
91 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
92 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
94 #ifdef HOST_WORDS_BIGENDIAN
95 #define PAT(x) cbswap_32(x)
100 #ifdef HOST_WORDS_BIGENDIAN
106 #ifdef HOST_WORDS_BIGENDIAN
107 #define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
109 #define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
112 static const uint32_t mask16
[16] = {
133 #ifdef HOST_WORDS_BIGENDIAN
136 #define PAT(x) cbswap_32(x)
139 static uint32_t expand4
[256];
140 static uint16_t expand2
[256];
141 static uint8_t expand4to8
[16];
143 static void vga_update_memory_access(VGACommonState
*s
)
145 hwaddr base
, offset
, size
;
147 if (s
->legacy_address_space
== NULL
) {
151 if (s
->has_chain4_alias
) {
152 memory_region_del_subregion(s
->legacy_address_space
, &s
->chain4_alias
);
153 object_unparent(OBJECT(&s
->chain4_alias
));
154 s
->has_chain4_alias
= false;
155 s
->plane_updated
= 0xf;
157 if ((s
->sr
[VGA_SEQ_PLANE_WRITE
] & VGA_SR02_ALL_PLANES
) ==
158 VGA_SR02_ALL_PLANES
&& s
->sr
[VGA_SEQ_MEMORY_MODE
] & VGA_SR04_CHN_4M
) {
160 switch ((s
->gr
[VGA_GFX_MISC
] >> 2) & 3) {
168 offset
= s
->bank_offset
;
180 memory_region_init_alias(&s
->chain4_alias
, memory_region_owner(&s
->vram
),
181 "vga.chain4", &s
->vram
, offset
, size
);
182 memory_region_add_subregion_overlap(s
->legacy_address_space
, base
,
183 &s
->chain4_alias
, 2);
184 s
->has_chain4_alias
= true;
188 static void vga_dumb_update_retrace_info(VGACommonState
*s
)
193 static void vga_precise_update_retrace_info(VGACommonState
*s
)
196 int hretr_start_char
;
197 int hretr_skew_chars
;
201 int vretr_start_line
;
210 const int clk_hz
[] = {25175000, 28322000, 25175000, 25175000};
211 int64_t chars_per_sec
;
212 struct vga_precise_retrace
*r
= &s
->retrace_info
.precise
;
214 htotal_chars
= s
->cr
[VGA_CRTC_H_TOTAL
] + 5;
215 hretr_start_char
= s
->cr
[VGA_CRTC_H_SYNC_START
];
216 hretr_skew_chars
= (s
->cr
[VGA_CRTC_H_SYNC_END
] >> 5) & 3;
217 hretr_end_char
= s
->cr
[VGA_CRTC_H_SYNC_END
] & 0x1f;
219 vtotal_lines
= (s
->cr
[VGA_CRTC_V_TOTAL
] |
220 (((s
->cr
[VGA_CRTC_OVERFLOW
] & 1) |
221 ((s
->cr
[VGA_CRTC_OVERFLOW
] >> 4) & 2)) << 8)) + 2;
222 vretr_start_line
= s
->cr
[VGA_CRTC_V_SYNC_START
] |
223 ((((s
->cr
[VGA_CRTC_OVERFLOW
] >> 2) & 1) |
224 ((s
->cr
[VGA_CRTC_OVERFLOW
] >> 6) & 2)) << 8);
225 vretr_end_line
= s
->cr
[VGA_CRTC_V_SYNC_END
] & 0xf;
227 clocking_mode
= (s
->sr
[VGA_SEQ_CLOCK_MODE
] >> 3) & 1;
228 clock_sel
= (s
->msr
>> 2) & 3;
229 dots
= (s
->msr
& 1) ? 8 : 9;
231 chars_per_sec
= clk_hz
[clock_sel
] / dots
;
233 htotal_chars
<<= clocking_mode
;
235 r
->total_chars
= vtotal_lines
* htotal_chars
;
237 r
->ticks_per_char
= get_ticks_per_sec() / (r
->total_chars
* r
->freq
);
239 r
->ticks_per_char
= get_ticks_per_sec() / chars_per_sec
;
242 r
->vstart
= vretr_start_line
;
243 r
->vend
= r
->vstart
+ vretr_end_line
+ 1;
245 r
->hstart
= hretr_start_char
+ hretr_skew_chars
;
246 r
->hend
= r
->hstart
+ hretr_end_char
+ 1;
247 r
->htotal
= htotal_chars
;
250 div2
= (s
->cr
[VGA_CRTC_MODE
] >> 2) & 1;
251 sldiv2
= (s
->cr
[VGA_CRTC_MODE
] >> 3) & 1;
261 "div2 = %d sldiv2 = %d\n"
262 "clocking_mode = %d\n"
263 "clock_sel = %d %d\n"
265 "ticks/char = %" PRId64
"\n"
267 (double) get_ticks_per_sec() / (r
->ticks_per_char
* r
->total_chars
),
285 static uint8_t vga_precise_retrace(VGACommonState
*s
)
287 struct vga_precise_retrace
*r
= &s
->retrace_info
.precise
;
288 uint8_t val
= s
->st01
& ~(ST01_V_RETRACE
| ST01_DISP_ENABLE
);
290 if (r
->total_chars
) {
291 int cur_line
, cur_line_char
, cur_char
;
294 cur_tick
= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
);
296 cur_char
= (cur_tick
/ r
->ticks_per_char
) % r
->total_chars
;
297 cur_line
= cur_char
/ r
->htotal
;
299 if (cur_line
>= r
->vstart
&& cur_line
<= r
->vend
) {
300 val
|= ST01_V_RETRACE
| ST01_DISP_ENABLE
;
302 cur_line_char
= cur_char
% r
->htotal
;
303 if (cur_line_char
>= r
->hstart
&& cur_line_char
<= r
->hend
) {
304 val
|= ST01_DISP_ENABLE
;
310 return s
->st01
^ (ST01_V_RETRACE
| ST01_DISP_ENABLE
);
314 static uint8_t vga_dumb_retrace(VGACommonState
*s
)
316 return s
->st01
^ (ST01_V_RETRACE
| ST01_DISP_ENABLE
);
319 int vga_ioport_invalid(VGACommonState
*s
, uint32_t addr
)
321 if (s
->msr
& VGA_MIS_COLOR
) {
323 return (addr
>= 0x3b0 && addr
<= 0x3bf);
326 return (addr
>= 0x3d0 && addr
<= 0x3df);
330 uint32_t vga_ioport_read(void *opaque
, uint32_t addr
)
332 VGACommonState
*s
= opaque
;
335 if (vga_ioport_invalid(s
, addr
)) {
340 if (s
->ar_flip_flop
== 0) {
347 index
= s
->ar_index
& 0x1f;
348 if (index
< VGA_ATT_C
) {
361 val
= s
->sr
[s
->sr_index
];
363 printf("vga: read SR%x = 0x%02x\n", s
->sr_index
, val
);
370 val
= s
->dac_write_index
;
373 val
= s
->palette
[s
->dac_read_index
* 3 + s
->dac_sub_index
];
374 if (++s
->dac_sub_index
== 3) {
375 s
->dac_sub_index
= 0;
389 val
= s
->gr
[s
->gr_index
];
391 printf("vga: read GR%x = 0x%02x\n", s
->gr_index
, val
);
400 val
= s
->cr
[s
->cr_index
];
402 printf("vga: read CR%x = 0x%02x\n", s
->cr_index
, val
);
407 /* just toggle to fool polling */
408 val
= s
->st01
= s
->retrace(s
);
416 #if defined(DEBUG_VGA)
417 printf("VGA: read addr=0x%04x data=0x%02x\n", addr
, val
);
422 void vga_ioport_write(void *opaque
, uint32_t addr
, uint32_t val
)
424 VGACommonState
*s
= opaque
;
427 /* check port range access depending on color/monochrome mode */
428 if (vga_ioport_invalid(s
, addr
)) {
432 printf("VGA: write addr=0x%04x data=0x%02x\n", addr
, val
);
437 if (s
->ar_flip_flop
== 0) {
441 index
= s
->ar_index
& 0x1f;
443 case VGA_ATC_PALETTE0
... VGA_ATC_PALETTEF
:
444 s
->ar
[index
] = val
& 0x3f;
447 s
->ar
[index
] = val
& ~0x10;
449 case VGA_ATC_OVERSCAN
:
452 case VGA_ATC_PLANE_ENABLE
:
453 s
->ar
[index
] = val
& ~0xc0;
456 s
->ar
[index
] = val
& ~0xf0;
458 case VGA_ATC_COLOR_PAGE
:
459 s
->ar
[index
] = val
& ~0xf0;
465 s
->ar_flip_flop
^= 1;
468 s
->msr
= val
& ~0x10;
469 s
->update_retrace_info(s
);
472 s
->sr_index
= val
& 7;
476 printf("vga: write SR%x = 0x%02x\n", s
->sr_index
, val
);
478 s
->sr
[s
->sr_index
] = val
& sr_mask
[s
->sr_index
];
479 if (s
->sr_index
== VGA_SEQ_CLOCK_MODE
) {
480 s
->update_retrace_info(s
);
482 vga_update_memory_access(s
);
485 s
->dac_read_index
= val
;
486 s
->dac_sub_index
= 0;
490 s
->dac_write_index
= val
;
491 s
->dac_sub_index
= 0;
495 s
->dac_cache
[s
->dac_sub_index
] = val
;
496 if (++s
->dac_sub_index
== 3) {
497 memcpy(&s
->palette
[s
->dac_write_index
* 3], s
->dac_cache
, 3);
498 s
->dac_sub_index
= 0;
499 s
->dac_write_index
++;
503 s
->gr_index
= val
& 0x0f;
507 printf("vga: write GR%x = 0x%02x\n", s
->gr_index
, val
);
509 s
->gr
[s
->gr_index
] = val
& gr_mask
[s
->gr_index
];
510 vga_update_memory_access(s
);
519 printf("vga: write CR%x = 0x%02x\n", s
->cr_index
, val
);
521 /* handle CR0-7 protection */
522 if ((s
->cr
[VGA_CRTC_V_SYNC_END
] & VGA_CR11_LOCK_CR0_CR7
) &&
523 s
->cr_index
<= VGA_CRTC_OVERFLOW
) {
524 /* can always write bit 4 of CR7 */
525 if (s
->cr_index
== VGA_CRTC_OVERFLOW
) {
526 s
->cr
[VGA_CRTC_OVERFLOW
] = (s
->cr
[VGA_CRTC_OVERFLOW
] & ~0x10) |
531 s
->cr
[s
->cr_index
] = val
;
533 switch(s
->cr_index
) {
534 case VGA_CRTC_H_TOTAL
:
535 case VGA_CRTC_H_SYNC_START
:
536 case VGA_CRTC_H_SYNC_END
:
537 case VGA_CRTC_V_TOTAL
:
538 case VGA_CRTC_OVERFLOW
:
539 case VGA_CRTC_V_SYNC_END
:
541 s
->update_retrace_info(s
);
553 * Sanity check vbe register writes.
555 * As we don't have a way to signal errors to the guest in the bochs
556 * dispi interface we'll go adjust the registers to the closest valid
559 static void vbe_fixup_regs(VGACommonState
*s
)
561 uint16_t *r
= s
->vbe_regs
;
562 uint32_t bits
, linelength
, maxy
, offset
;
564 if (!(r
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
)) {
565 /* vbe is turned off -- nothing to do */
570 switch (r
[VBE_DISPI_INDEX_BPP
]) {
576 bits
= r
[VBE_DISPI_INDEX_BPP
];
582 bits
= r
[VBE_DISPI_INDEX_BPP
] = 8;
587 r
[VBE_DISPI_INDEX_XRES
] &= ~7u;
588 if (r
[VBE_DISPI_INDEX_XRES
] == 0) {
589 r
[VBE_DISPI_INDEX_XRES
] = 8;
591 if (r
[VBE_DISPI_INDEX_XRES
] > VBE_DISPI_MAX_XRES
) {
592 r
[VBE_DISPI_INDEX_XRES
] = VBE_DISPI_MAX_XRES
;
594 r
[VBE_DISPI_INDEX_VIRT_WIDTH
] &= ~7u;
595 if (r
[VBE_DISPI_INDEX_VIRT_WIDTH
] > VBE_DISPI_MAX_XRES
) {
596 r
[VBE_DISPI_INDEX_VIRT_WIDTH
] = VBE_DISPI_MAX_XRES
;
598 if (r
[VBE_DISPI_INDEX_VIRT_WIDTH
] < r
[VBE_DISPI_INDEX_XRES
]) {
599 r
[VBE_DISPI_INDEX_VIRT_WIDTH
] = r
[VBE_DISPI_INDEX_XRES
];
603 linelength
= r
[VBE_DISPI_INDEX_VIRT_WIDTH
] * bits
/ 8;
604 maxy
= s
->vbe_size
/ linelength
;
605 if (r
[VBE_DISPI_INDEX_YRES
] == 0) {
606 r
[VBE_DISPI_INDEX_YRES
] = 1;
608 if (r
[VBE_DISPI_INDEX_YRES
] > VBE_DISPI_MAX_YRES
) {
609 r
[VBE_DISPI_INDEX_YRES
] = VBE_DISPI_MAX_YRES
;
611 if (r
[VBE_DISPI_INDEX_YRES
] > maxy
) {
612 r
[VBE_DISPI_INDEX_YRES
] = maxy
;
616 if (r
[VBE_DISPI_INDEX_X_OFFSET
] > VBE_DISPI_MAX_XRES
) {
617 r
[VBE_DISPI_INDEX_X_OFFSET
] = VBE_DISPI_MAX_XRES
;
619 if (r
[VBE_DISPI_INDEX_Y_OFFSET
] > VBE_DISPI_MAX_YRES
) {
620 r
[VBE_DISPI_INDEX_Y_OFFSET
] = VBE_DISPI_MAX_YRES
;
622 offset
= r
[VBE_DISPI_INDEX_X_OFFSET
] * bits
/ 8;
623 offset
+= r
[VBE_DISPI_INDEX_Y_OFFSET
] * linelength
;
624 if (offset
+ r
[VBE_DISPI_INDEX_YRES
] * linelength
> s
->vbe_size
) {
625 r
[VBE_DISPI_INDEX_Y_OFFSET
] = 0;
626 offset
= r
[VBE_DISPI_INDEX_X_OFFSET
] * bits
/ 8;
627 if (offset
+ r
[VBE_DISPI_INDEX_YRES
] * linelength
> s
->vbe_size
) {
628 r
[VBE_DISPI_INDEX_X_OFFSET
] = 0;
633 /* update vga state */
634 r
[VBE_DISPI_INDEX_VIRT_HEIGHT
] = maxy
;
635 s
->vbe_line_offset
= linelength
;
636 s
->vbe_start_addr
= offset
/ 4;
639 static uint32_t vbe_ioport_read_index(void *opaque
, uint32_t addr
)
641 VGACommonState
*s
= opaque
;
647 uint32_t vbe_ioport_read_data(void *opaque
, uint32_t addr
)
649 VGACommonState
*s
= opaque
;
652 if (s
->vbe_index
< VBE_DISPI_INDEX_NB
) {
653 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_GETCAPS
) {
654 switch(s
->vbe_index
) {
655 /* XXX: do not hardcode ? */
656 case VBE_DISPI_INDEX_XRES
:
657 val
= VBE_DISPI_MAX_XRES
;
659 case VBE_DISPI_INDEX_YRES
:
660 val
= VBE_DISPI_MAX_YRES
;
662 case VBE_DISPI_INDEX_BPP
:
663 val
= VBE_DISPI_MAX_BPP
;
666 val
= s
->vbe_regs
[s
->vbe_index
];
670 val
= s
->vbe_regs
[s
->vbe_index
];
672 } else if (s
->vbe_index
== VBE_DISPI_INDEX_VIDEO_MEMORY_64K
) {
673 val
= s
->vbe_size
/ (64 * 1024);
677 #ifdef DEBUG_BOCHS_VBE
678 printf("VBE: read index=0x%x val=0x%x\n", s
->vbe_index
, val
);
683 void vbe_ioport_write_index(void *opaque
, uint32_t addr
, uint32_t val
)
685 VGACommonState
*s
= opaque
;
689 void vbe_ioport_write_data(void *opaque
, uint32_t addr
, uint32_t val
)
691 VGACommonState
*s
= opaque
;
693 if (s
->vbe_index
<= VBE_DISPI_INDEX_NB
) {
694 #ifdef DEBUG_BOCHS_VBE
695 printf("VBE: write index=0x%x val=0x%x\n", s
->vbe_index
, val
);
697 switch(s
->vbe_index
) {
698 case VBE_DISPI_INDEX_ID
:
699 if (val
== VBE_DISPI_ID0
||
700 val
== VBE_DISPI_ID1
||
701 val
== VBE_DISPI_ID2
||
702 val
== VBE_DISPI_ID3
||
703 val
== VBE_DISPI_ID4
) {
704 s
->vbe_regs
[s
->vbe_index
] = val
;
707 case VBE_DISPI_INDEX_XRES
:
708 case VBE_DISPI_INDEX_YRES
:
709 case VBE_DISPI_INDEX_BPP
:
710 case VBE_DISPI_INDEX_VIRT_WIDTH
:
711 case VBE_DISPI_INDEX_X_OFFSET
:
712 case VBE_DISPI_INDEX_Y_OFFSET
:
713 s
->vbe_regs
[s
->vbe_index
] = val
;
716 case VBE_DISPI_INDEX_BANK
:
717 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4) {
718 val
&= (s
->vbe_bank_mask
>> 2);
720 val
&= s
->vbe_bank_mask
;
722 s
->vbe_regs
[s
->vbe_index
] = val
;
723 s
->bank_offset
= (val
<< 16);
724 vga_update_memory_access(s
);
726 case VBE_DISPI_INDEX_ENABLE
:
727 if ((val
& VBE_DISPI_ENABLED
) &&
728 !(s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
)) {
729 int h
, shift_control
;
731 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_WIDTH
] = 0;
732 s
->vbe_regs
[VBE_DISPI_INDEX_X_OFFSET
] = 0;
733 s
->vbe_regs
[VBE_DISPI_INDEX_Y_OFFSET
] = 0;
734 s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] |= VBE_DISPI_ENABLED
;
737 /* clear the screen */
738 if (!(val
& VBE_DISPI_NOCLEARMEM
)) {
739 memset(s
->vram_ptr
, 0,
740 s
->vbe_regs
[VBE_DISPI_INDEX_YRES
] * s
->vbe_line_offset
);
743 /* we initialize the VGA graphic mode */
744 /* graphic mode + memory map 1 */
745 s
->gr
[VGA_GFX_MISC
] = (s
->gr
[VGA_GFX_MISC
] & ~0x0c) | 0x04 |
746 VGA_GR06_GRAPHICS_MODE
;
747 s
->cr
[VGA_CRTC_MODE
] |= 3; /* no CGA modes */
748 s
->cr
[VGA_CRTC_OFFSET
] = s
->vbe_line_offset
>> 3;
750 s
->cr
[VGA_CRTC_H_DISP
] =
751 (s
->vbe_regs
[VBE_DISPI_INDEX_XRES
] >> 3) - 1;
752 /* height (only meaningful if < 1024) */
753 h
= s
->vbe_regs
[VBE_DISPI_INDEX_YRES
] - 1;
754 s
->cr
[VGA_CRTC_V_DISP_END
] = h
;
755 s
->cr
[VGA_CRTC_OVERFLOW
] = (s
->cr
[VGA_CRTC_OVERFLOW
] & ~0x42) |
756 ((h
>> 7) & 0x02) | ((h
>> 3) & 0x40);
757 /* line compare to 1023 */
758 s
->cr
[VGA_CRTC_LINE_COMPARE
] = 0xff;
759 s
->cr
[VGA_CRTC_OVERFLOW
] |= 0x10;
760 s
->cr
[VGA_CRTC_MAX_SCAN
] |= 0x40;
762 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4) {
764 s
->sr
[VGA_SEQ_CLOCK_MODE
] &= ~8; /* no double line */
767 /* set chain 4 mode */
768 s
->sr
[VGA_SEQ_MEMORY_MODE
] |= VGA_SR04_CHN_4M
;
769 /* activate all planes */
770 s
->sr
[VGA_SEQ_PLANE_WRITE
] |= VGA_SR02_ALL_PLANES
;
772 s
->gr
[VGA_GFX_MODE
] = (s
->gr
[VGA_GFX_MODE
] & ~0x60) |
773 (shift_control
<< 5);
774 s
->cr
[VGA_CRTC_MAX_SCAN
] &= ~0x9f; /* no double scan */
778 s
->dac_8bit
= (val
& VBE_DISPI_8BIT_DAC
) > 0;
779 s
->vbe_regs
[s
->vbe_index
] = val
;
780 vga_update_memory_access(s
);
788 /* called for accesses between 0xa0000 and 0xc0000 */
789 uint32_t vga_mem_readb(VGACommonState
*s
, hwaddr addr
)
791 int memory_map_mode
, plane
;
794 /* convert to VGA memory offset */
795 memory_map_mode
= (s
->gr
[VGA_GFX_MISC
] >> 2) & 3;
797 switch(memory_map_mode
) {
803 addr
+= s
->bank_offset
;
818 if (s
->sr
[VGA_SEQ_MEMORY_MODE
] & VGA_SR04_CHN_4M
) {
819 /* chain 4 mode : simplest access */
820 ret
= s
->vram_ptr
[addr
];
821 } else if (s
->gr
[VGA_GFX_MODE
] & 0x10) {
822 /* odd/even mode (aka text mode mapping) */
823 plane
= (s
->gr
[VGA_GFX_PLANE_READ
] & 2) | (addr
& 1);
824 ret
= s
->vram_ptr
[((addr
& ~1) << 1) | plane
];
826 /* standard VGA latched access */
827 s
->latch
= ((uint32_t *)s
->vram_ptr
)[addr
];
829 if (!(s
->gr
[VGA_GFX_MODE
] & 0x08)) {
831 plane
= s
->gr
[VGA_GFX_PLANE_READ
];
832 ret
= GET_PLANE(s
->latch
, plane
);
835 ret
= (s
->latch
^ mask16
[s
->gr
[VGA_GFX_COMPARE_VALUE
]]) &
836 mask16
[s
->gr
[VGA_GFX_COMPARE_MASK
]];
845 /* called for accesses between 0xa0000 and 0xc0000 */
846 void vga_mem_writeb(VGACommonState
*s
, hwaddr addr
, uint32_t val
)
848 int memory_map_mode
, plane
, write_mode
, b
, func_select
, mask
;
849 uint32_t write_mask
, bit_mask
, set_mask
;
852 printf("vga: [0x" TARGET_FMT_plx
"] = 0x%02x\n", addr
, val
);
854 /* convert to VGA memory offset */
855 memory_map_mode
= (s
->gr
[VGA_GFX_MISC
] >> 2) & 3;
857 switch(memory_map_mode
) {
863 addr
+= s
->bank_offset
;
878 if (s
->sr
[VGA_SEQ_MEMORY_MODE
] & VGA_SR04_CHN_4M
) {
879 /* chain 4 mode : simplest access */
882 if (s
->sr
[VGA_SEQ_PLANE_WRITE
] & mask
) {
883 s
->vram_ptr
[addr
] = val
;
885 printf("vga: chain4: [0x" TARGET_FMT_plx
"]\n", addr
);
887 s
->plane_updated
|= mask
; /* only used to detect font change */
888 memory_region_set_dirty(&s
->vram
, addr
, 1);
890 } else if (s
->gr
[VGA_GFX_MODE
] & 0x10) {
891 /* odd/even mode (aka text mode mapping) */
892 plane
= (s
->gr
[VGA_GFX_PLANE_READ
] & 2) | (addr
& 1);
894 if (s
->sr
[VGA_SEQ_PLANE_WRITE
] & mask
) {
895 addr
= ((addr
& ~1) << 1) | plane
;
896 s
->vram_ptr
[addr
] = val
;
898 printf("vga: odd/even: [0x" TARGET_FMT_plx
"]\n", addr
);
900 s
->plane_updated
|= mask
; /* only used to detect font change */
901 memory_region_set_dirty(&s
->vram
, addr
, 1);
904 /* standard VGA latched access */
905 write_mode
= s
->gr
[VGA_GFX_MODE
] & 3;
910 b
= s
->gr
[VGA_GFX_DATA_ROTATE
] & 7;
911 val
= ((val
>> b
) | (val
<< (8 - b
))) & 0xff;
915 /* apply set/reset mask */
916 set_mask
= mask16
[s
->gr
[VGA_GFX_SR_ENABLE
]];
917 val
= (val
& ~set_mask
) |
918 (mask16
[s
->gr
[VGA_GFX_SR_VALUE
]] & set_mask
);
919 bit_mask
= s
->gr
[VGA_GFX_BIT_MASK
];
925 val
= mask16
[val
& 0x0f];
926 bit_mask
= s
->gr
[VGA_GFX_BIT_MASK
];
930 b
= s
->gr
[VGA_GFX_DATA_ROTATE
] & 7;
931 val
= (val
>> b
) | (val
<< (8 - b
));
933 bit_mask
= s
->gr
[VGA_GFX_BIT_MASK
] & val
;
934 val
= mask16
[s
->gr
[VGA_GFX_SR_VALUE
]];
938 /* apply logical operation */
939 func_select
= s
->gr
[VGA_GFX_DATA_ROTATE
] >> 3;
940 switch(func_select
) {
960 bit_mask
|= bit_mask
<< 8;
961 bit_mask
|= bit_mask
<< 16;
962 val
= (val
& bit_mask
) | (s
->latch
& ~bit_mask
);
965 /* mask data according to sr[2] */
966 mask
= s
->sr
[VGA_SEQ_PLANE_WRITE
];
967 s
->plane_updated
|= mask
; /* only used to detect font change */
968 write_mask
= mask16
[mask
];
969 ((uint32_t *)s
->vram_ptr
)[addr
] =
970 (((uint32_t *)s
->vram_ptr
)[addr
] & ~write_mask
) |
973 printf("vga: latch: [0x" TARGET_FMT_plx
"] mask=0x%08x val=0x%08x\n",
974 addr
* 4, write_mask
, val
);
976 memory_region_set_dirty(&s
->vram
, addr
<< 2, sizeof(uint32_t));
980 typedef void vga_draw_line_func(VGACommonState
*s1
, uint8_t *d
,
981 const uint8_t *s
, int width
);
983 #include "vga-helpers.h"
985 /* return true if the palette was modified */
986 static int update_palette16(VGACommonState
*s
)
989 uint32_t v
, col
, *palette
;
992 palette
= s
->last_palette
;
993 for(i
= 0; i
< 16; i
++) {
995 if (s
->ar
[VGA_ATC_MODE
] & 0x80) {
996 v
= ((s
->ar
[VGA_ATC_COLOR_PAGE
] & 0xf) << 4) | (v
& 0xf);
998 v
= ((s
->ar
[VGA_ATC_COLOR_PAGE
] & 0xc) << 4) | (v
& 0x3f);
1001 col
= rgb_to_pixel32(c6_to_8(s
->palette
[v
]),
1002 c6_to_8(s
->palette
[v
+ 1]),
1003 c6_to_8(s
->palette
[v
+ 2]));
1004 if (col
!= palette
[i
]) {
1012 /* return true if the palette was modified */
1013 static int update_palette256(VGACommonState
*s
)
1016 uint32_t v
, col
, *palette
;
1019 palette
= s
->last_palette
;
1021 for(i
= 0; i
< 256; i
++) {
1023 col
= rgb_to_pixel32(s
->palette
[v
],
1027 col
= rgb_to_pixel32(c6_to_8(s
->palette
[v
]),
1028 c6_to_8(s
->palette
[v
+ 1]),
1029 c6_to_8(s
->palette
[v
+ 2]));
1031 if (col
!= palette
[i
]) {
1040 static void vga_get_offsets(VGACommonState
*s
,
1041 uint32_t *pline_offset
,
1042 uint32_t *pstart_addr
,
1043 uint32_t *pline_compare
)
1045 uint32_t start_addr
, line_offset
, line_compare
;
1047 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
) {
1048 line_offset
= s
->vbe_line_offset
;
1049 start_addr
= s
->vbe_start_addr
;
1050 line_compare
= 65535;
1052 /* compute line_offset in bytes */
1053 line_offset
= s
->cr
[VGA_CRTC_OFFSET
];
1056 /* starting address */
1057 start_addr
= s
->cr
[VGA_CRTC_START_LO
] |
1058 (s
->cr
[VGA_CRTC_START_HI
] << 8);
1061 line_compare
= s
->cr
[VGA_CRTC_LINE_COMPARE
] |
1062 ((s
->cr
[VGA_CRTC_OVERFLOW
] & 0x10) << 4) |
1063 ((s
->cr
[VGA_CRTC_MAX_SCAN
] & 0x40) << 3);
1065 *pline_offset
= line_offset
;
1066 *pstart_addr
= start_addr
;
1067 *pline_compare
= line_compare
;
1070 /* update start_addr and line_offset. Return TRUE if modified */
1071 static int update_basic_params(VGACommonState
*s
)
1074 uint32_t start_addr
, line_offset
, line_compare
;
1078 s
->get_offsets(s
, &line_offset
, &start_addr
, &line_compare
);
1080 if (line_offset
!= s
->line_offset
||
1081 start_addr
!= s
->start_addr
||
1082 line_compare
!= s
->line_compare
) {
1083 s
->line_offset
= line_offset
;
1084 s
->start_addr
= start_addr
;
1085 s
->line_compare
= line_compare
;
1092 static const uint8_t cursor_glyph
[32 * 4] = {
1093 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1094 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1095 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1096 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1097 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1098 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1099 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1100 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1101 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1102 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1103 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1104 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1105 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1106 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1107 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1108 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1111 static void vga_get_text_resolution(VGACommonState
*s
, int *pwidth
, int *pheight
,
1112 int *pcwidth
, int *pcheight
)
1114 int width
, cwidth
, height
, cheight
;
1116 /* total width & height */
1117 cheight
= (s
->cr
[VGA_CRTC_MAX_SCAN
] & 0x1f) + 1;
1119 if (!(s
->sr
[VGA_SEQ_CLOCK_MODE
] & VGA_SR01_CHAR_CLK_8DOTS
)) {
1122 if (s
->sr
[VGA_SEQ_CLOCK_MODE
] & 0x08) {
1123 cwidth
= 16; /* NOTE: no 18 pixel wide */
1125 width
= (s
->cr
[VGA_CRTC_H_DISP
] + 1);
1126 if (s
->cr
[VGA_CRTC_V_TOTAL
] == 100) {
1127 /* ugly hack for CGA 160x100x16 - explain me the logic */
1130 height
= s
->cr
[VGA_CRTC_V_DISP_END
] |
1131 ((s
->cr
[VGA_CRTC_OVERFLOW
] & 0x02) << 7) |
1132 ((s
->cr
[VGA_CRTC_OVERFLOW
] & 0x40) << 3);
1133 height
= (height
+ 1) / cheight
;
1139 *pcheight
= cheight
;
1150 static void vga_draw_text(VGACommonState
*s
, int full_update
)
1152 DisplaySurface
*surface
= qemu_console_surface(s
->con
);
1153 int cx
, cy
, cheight
, cw
, ch
, cattr
, height
, width
, ch_attr
;
1154 int cx_min
, cx_max
, linesize
, x_incr
, line
, line1
;
1155 uint32_t offset
, fgcol
, bgcol
, v
, cursor_offset
;
1156 uint8_t *d1
, *d
, *src
, *dest
, *cursor_ptr
;
1157 const uint8_t *font_ptr
, *font_base
[2];
1158 int dup9
, line_offset
;
1160 uint32_t *ch_attr_ptr
;
1161 int64_t now
= qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL
);
1163 /* compute font data address (in plane 2) */
1164 v
= s
->sr
[VGA_SEQ_CHARACTER_MAP
];
1165 offset
= (((v
>> 4) & 1) | ((v
<< 1) & 6)) * 8192 * 4 + 2;
1166 if (offset
!= s
->font_offsets
[0]) {
1167 s
->font_offsets
[0] = offset
;
1170 font_base
[0] = s
->vram_ptr
+ offset
;
1172 offset
= (((v
>> 5) & 1) | ((v
>> 1) & 6)) * 8192 * 4 + 2;
1173 font_base
[1] = s
->vram_ptr
+ offset
;
1174 if (offset
!= s
->font_offsets
[1]) {
1175 s
->font_offsets
[1] = offset
;
1178 if (s
->plane_updated
& (1 << 2) || s
->has_chain4_alias
) {
1179 /* if the plane 2 was modified since the last display, it
1180 indicates the font may have been modified */
1181 s
->plane_updated
= 0;
1184 full_update
|= update_basic_params(s
);
1186 line_offset
= s
->line_offset
;
1188 vga_get_text_resolution(s
, &width
, &height
, &cw
, &cheight
);
1189 if ((height
* width
) <= 1) {
1190 /* better than nothing: exit if transient size is too small */
1193 if ((height
* width
) > CH_ATTR_SIZE
) {
1194 /* better than nothing: exit if transient size is too big */
1198 if (width
!= s
->last_width
|| height
!= s
->last_height
||
1199 cw
!= s
->last_cw
|| cheight
!= s
->last_ch
|| s
->last_depth
) {
1200 s
->last_scr_width
= width
* cw
;
1201 s
->last_scr_height
= height
* cheight
;
1202 qemu_console_resize(s
->con
, s
->last_scr_width
, s
->last_scr_height
);
1203 surface
= qemu_console_surface(s
->con
);
1204 dpy_text_resize(s
->con
, width
, height
);
1206 s
->last_width
= width
;
1207 s
->last_height
= height
;
1208 s
->last_ch
= cheight
;
1212 full_update
|= update_palette16(s
);
1213 palette
= s
->last_palette
;
1214 x_incr
= cw
* surface_bytes_per_pixel(surface
);
1217 s
->full_update_text
= 1;
1219 if (s
->full_update_gfx
) {
1220 s
->full_update_gfx
= 0;
1224 cursor_offset
= ((s
->cr
[VGA_CRTC_CURSOR_HI
] << 8) |
1225 s
->cr
[VGA_CRTC_CURSOR_LO
]) - s
->start_addr
;
1226 if (cursor_offset
!= s
->cursor_offset
||
1227 s
->cr
[VGA_CRTC_CURSOR_START
] != s
->cursor_start
||
1228 s
->cr
[VGA_CRTC_CURSOR_END
] != s
->cursor_end
) {
1229 /* if the cursor position changed, we update the old and new
1231 if (s
->cursor_offset
< CH_ATTR_SIZE
)
1232 s
->last_ch_attr
[s
->cursor_offset
] = -1;
1233 if (cursor_offset
< CH_ATTR_SIZE
)
1234 s
->last_ch_attr
[cursor_offset
] = -1;
1235 s
->cursor_offset
= cursor_offset
;
1236 s
->cursor_start
= s
->cr
[VGA_CRTC_CURSOR_START
];
1237 s
->cursor_end
= s
->cr
[VGA_CRTC_CURSOR_END
];
1239 cursor_ptr
= s
->vram_ptr
+ (s
->start_addr
+ cursor_offset
) * 4;
1240 if (now
>= s
->cursor_blink_time
) {
1241 s
->cursor_blink_time
= now
+ VGA_TEXT_CURSOR_PERIOD_MS
/ 2;
1242 s
->cursor_visible_phase
= !s
->cursor_visible_phase
;
1245 dest
= surface_data(surface
);
1246 linesize
= surface_stride(surface
);
1247 ch_attr_ptr
= s
->last_ch_attr
;
1249 offset
= s
->start_addr
* 4;
1250 for(cy
= 0; cy
< height
; cy
++) {
1252 src
= s
->vram_ptr
+ offset
;
1255 for(cx
= 0; cx
< width
; cx
++) {
1256 ch_attr
= *(uint16_t *)src
;
1257 if (full_update
|| ch_attr
!= *ch_attr_ptr
|| src
== cursor_ptr
) {
1262 *ch_attr_ptr
= ch_attr
;
1263 #ifdef HOST_WORDS_BIGENDIAN
1265 cattr
= ch_attr
& 0xff;
1267 ch
= ch_attr
& 0xff;
1268 cattr
= ch_attr
>> 8;
1270 font_ptr
= font_base
[(cattr
>> 3) & 1];
1271 font_ptr
+= 32 * 4 * ch
;
1272 bgcol
= palette
[cattr
>> 4];
1273 fgcol
= palette
[cattr
& 0x0f];
1275 vga_draw_glyph16(d1
, linesize
,
1276 font_ptr
, cheight
, fgcol
, bgcol
);
1277 } else if (cw
!= 9) {
1278 vga_draw_glyph8(d1
, linesize
,
1279 font_ptr
, cheight
, fgcol
, bgcol
);
1282 if (ch
>= 0xb0 && ch
<= 0xdf &&
1283 (s
->ar
[VGA_ATC_MODE
] & 0x04)) {
1286 vga_draw_glyph9(d1
, linesize
,
1287 font_ptr
, cheight
, fgcol
, bgcol
, dup9
);
1289 if (src
== cursor_ptr
&&
1290 !(s
->cr
[VGA_CRTC_CURSOR_START
] & 0x20) &&
1291 s
->cursor_visible_phase
) {
1292 int line_start
, line_last
, h
;
1293 /* draw the cursor */
1294 line_start
= s
->cr
[VGA_CRTC_CURSOR_START
] & 0x1f;
1295 line_last
= s
->cr
[VGA_CRTC_CURSOR_END
] & 0x1f;
1296 /* XXX: check that */
1297 if (line_last
> cheight
- 1)
1298 line_last
= cheight
- 1;
1299 if (line_last
>= line_start
&& line_start
< cheight
) {
1300 h
= line_last
- line_start
+ 1;
1301 d
= d1
+ linesize
* line_start
;
1303 vga_draw_glyph16(d
, linesize
,
1304 cursor_glyph
, h
, fgcol
, bgcol
);
1305 } else if (cw
!= 9) {
1306 vga_draw_glyph8(d
, linesize
,
1307 cursor_glyph
, h
, fgcol
, bgcol
);
1309 vga_draw_glyph9(d
, linesize
,
1310 cursor_glyph
, h
, fgcol
, bgcol
, 1);
1320 dpy_gfx_update(s
->con
, cx_min
* cw
, cy
* cheight
,
1321 (cx_max
- cx_min
+ 1) * cw
, cheight
);
1323 dest
+= linesize
* cheight
;
1324 line1
= line
+ cheight
;
1325 offset
+= line_offset
;
1326 if (line
< s
->line_compare
&& line1
>= s
->line_compare
) {
1351 static vga_draw_line_func
* const vga_draw_line_table
[VGA_DRAW_LINE_NB
] = {
1368 static int vga_get_bpp(VGACommonState
*s
)
1372 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
) {
1373 ret
= s
->vbe_regs
[VBE_DISPI_INDEX_BPP
];
1380 static void vga_get_resolution(VGACommonState
*s
, int *pwidth
, int *pheight
)
1384 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
) {
1385 width
= s
->vbe_regs
[VBE_DISPI_INDEX_XRES
];
1386 height
= s
->vbe_regs
[VBE_DISPI_INDEX_YRES
];
1388 width
= (s
->cr
[VGA_CRTC_H_DISP
] + 1) * 8;
1389 height
= s
->cr
[VGA_CRTC_V_DISP_END
] |
1390 ((s
->cr
[VGA_CRTC_OVERFLOW
] & 0x02) << 7) |
1391 ((s
->cr
[VGA_CRTC_OVERFLOW
] & 0x40) << 3);
1392 height
= (height
+ 1);
1398 void vga_invalidate_scanlines(VGACommonState
*s
, int y1
, int y2
)
1401 if (y1
>= VGA_MAX_HEIGHT
)
1403 if (y2
>= VGA_MAX_HEIGHT
)
1404 y2
= VGA_MAX_HEIGHT
;
1405 for(y
= y1
; y
< y2
; y
++) {
1406 s
->invalidated_y_table
[y
>> 5] |= 1 << (y
& 0x1f);
1410 void vga_sync_dirty_bitmap(VGACommonState
*s
)
1412 memory_region_sync_dirty_bitmap(&s
->vram
);
1415 void vga_dirty_log_start(VGACommonState
*s
)
1417 memory_region_set_log(&s
->vram
, true, DIRTY_MEMORY_VGA
);
1420 void vga_dirty_log_stop(VGACommonState
*s
)
1422 memory_region_set_log(&s
->vram
, false, DIRTY_MEMORY_VGA
);
1428 static void vga_draw_graphic(VGACommonState
*s
, int full_update
)
1430 DisplaySurface
*surface
= qemu_console_surface(s
->con
);
1431 int y1
, y
, update
, linesize
, y_start
, double_scan
, mask
, depth
;
1432 int width
, height
, shift_control
, line_offset
, bwidth
, bits
;
1433 ram_addr_t page0
, page1
, page_min
, page_max
;
1434 int disp_width
, multi_scan
, multi_run
;
1436 uint32_t v
, addr1
, addr
;
1437 vga_draw_line_func
*vga_draw_line
= NULL
;
1439 pixman_format_code_t format
;
1440 #ifdef HOST_WORDS_BIGENDIAN
1441 bool byteswap
= !s
->big_endian_fb
;
1443 bool byteswap
= s
->big_endian_fb
;
1446 full_update
|= update_basic_params(s
);
1449 vga_sync_dirty_bitmap(s
);
1451 s
->get_resolution(s
, &width
, &height
);
1454 shift_control
= (s
->gr
[VGA_GFX_MODE
] >> 5) & 3;
1455 double_scan
= (s
->cr
[VGA_CRTC_MAX_SCAN
] >> 7);
1456 if (shift_control
!= 1) {
1457 multi_scan
= (((s
->cr
[VGA_CRTC_MAX_SCAN
] & 0x1f) + 1) << double_scan
)
1460 /* in CGA modes, multi_scan is ignored */
1461 /* XXX: is it correct ? */
1462 multi_scan
= double_scan
;
1464 multi_run
= multi_scan
;
1465 if (shift_control
!= s
->shift_control
||
1466 double_scan
!= s
->double_scan
) {
1468 s
->shift_control
= shift_control
;
1469 s
->double_scan
= double_scan
;
1472 if (shift_control
== 0) {
1473 if (s
->sr
[VGA_SEQ_CLOCK_MODE
] & 8) {
1476 } else if (shift_control
== 1) {
1477 if (s
->sr
[VGA_SEQ_CLOCK_MODE
] & 8) {
1482 depth
= s
->get_bpp(s
);
1485 * Check whether we can share the surface with the backend
1486 * or whether we need a shadow surface. We share native
1487 * endian surfaces for 15bpp and above and byteswapped
1488 * surfaces for 24bpp and above.
1490 format
= qemu_default_pixman_format(depth
, !byteswap
);
1492 share_surface
= dpy_gfx_check_format(s
->con
, format
)
1493 && !s
->force_shadow
;
1495 share_surface
= false;
1497 if (s
->line_offset
!= s
->last_line_offset
||
1498 disp_width
!= s
->last_width
||
1499 height
!= s
->last_height
||
1500 s
->last_depth
!= depth
||
1501 s
->last_byteswap
!= byteswap
||
1502 share_surface
!= is_buffer_shared(surface
)) {
1503 if (share_surface
) {
1504 surface
= qemu_create_displaysurface_from(disp_width
,
1505 height
, format
, s
->line_offset
,
1506 s
->vram_ptr
+ (s
->start_addr
* 4));
1507 dpy_gfx_replace_surface(s
->con
, surface
);
1509 printf("VGA: Using shared surface for depth=%d swap=%d\n",
1513 qemu_console_resize(s
->con
, disp_width
, height
);
1514 surface
= qemu_console_surface(s
->con
);
1516 printf("VGA: Using shadow surface for depth=%d swap=%d\n",
1520 s
->last_scr_width
= disp_width
;
1521 s
->last_scr_height
= height
;
1522 s
->last_width
= disp_width
;
1523 s
->last_height
= height
;
1524 s
->last_line_offset
= s
->line_offset
;
1525 s
->last_depth
= depth
;
1526 s
->last_byteswap
= byteswap
;
1528 } else if (is_buffer_shared(surface
) &&
1529 (full_update
|| surface_data(surface
) != s
->vram_ptr
1530 + (s
->start_addr
* 4))) {
1531 pixman_format_code_t format
=
1532 qemu_default_pixman_format(depth
, !byteswap
);
1533 surface
= qemu_create_displaysurface_from(disp_width
,
1534 height
, format
, s
->line_offset
,
1535 s
->vram_ptr
+ (s
->start_addr
* 4));
1536 dpy_gfx_replace_surface(s
->con
, surface
);
1539 if (shift_control
== 0) {
1540 full_update
|= update_palette16(s
);
1541 if (s
->sr
[VGA_SEQ_CLOCK_MODE
] & 8) {
1542 v
= VGA_DRAW_LINE4D2
;
1547 } else if (shift_control
== 1) {
1548 full_update
|= update_palette16(s
);
1549 if (s
->sr
[VGA_SEQ_CLOCK_MODE
] & 8) {
1550 v
= VGA_DRAW_LINE2D2
;
1556 switch(s
->get_bpp(s
)) {
1559 full_update
|= update_palette256(s
);
1560 v
= VGA_DRAW_LINE8D2
;
1564 full_update
|= update_palette256(s
);
1569 v
= s
->big_endian_fb
? VGA_DRAW_LINE15_BE
: VGA_DRAW_LINE15_LE
;
1573 v
= s
->big_endian_fb
? VGA_DRAW_LINE16_BE
: VGA_DRAW_LINE16_LE
;
1577 v
= s
->big_endian_fb
? VGA_DRAW_LINE24_BE
: VGA_DRAW_LINE24_LE
;
1581 v
= s
->big_endian_fb
? VGA_DRAW_LINE32_BE
: VGA_DRAW_LINE32_LE
;
1586 vga_draw_line
= vga_draw_line_table
[v
];
1588 if (!is_buffer_shared(surface
) && s
->cursor_invalidate
) {
1589 s
->cursor_invalidate(s
);
1592 line_offset
= s
->line_offset
;
1594 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",
1595 width
, height
, v
, line_offset
, s
->cr
[9], s
->cr
[VGA_CRTC_MODE
],
1596 s
->line_compare
, s
->sr
[VGA_SEQ_CLOCK_MODE
]);
1598 addr1
= (s
->start_addr
* 4);
1599 bwidth
= (width
* bits
+ 7) / 8;
1603 d
= surface_data(surface
);
1604 linesize
= surface_stride(surface
);
1606 for(y
= 0; y
< height
; y
++) {
1608 if (!(s
->cr
[VGA_CRTC_MODE
] & 1)) {
1610 /* CGA compatibility handling */
1611 shift
= 14 + ((s
->cr
[VGA_CRTC_MODE
] >> 6) & 1);
1612 addr
= (addr
& ~(1 << shift
)) | ((y1
& 1) << shift
);
1614 if (!(s
->cr
[VGA_CRTC_MODE
] & 2)) {
1615 addr
= (addr
& ~0x8000) | ((y1
& 2) << 14);
1617 update
= full_update
;
1619 page1
= addr
+ bwidth
- 1;
1620 update
|= memory_region_get_dirty(&s
->vram
, page0
, page1
- page0
,
1622 /* explicit invalidation for the hardware cursor */
1623 update
|= (s
->invalidated_y_table
[y
>> 5] >> (y
& 0x1f)) & 1;
1627 if (page0
< page_min
)
1629 if (page1
> page_max
)
1631 if (!(is_buffer_shared(surface
))) {
1632 vga_draw_line(s
, d
, s
->vram_ptr
+ addr
, width
);
1633 if (s
->cursor_draw_line
)
1634 s
->cursor_draw_line(s
, d
, y
);
1638 /* flush to display */
1639 dpy_gfx_update(s
->con
, 0, y_start
,
1640 disp_width
, y
- y_start
);
1645 mask
= (s
->cr
[VGA_CRTC_MODE
] & 3) ^ 3;
1646 if ((y1
& mask
) == mask
)
1647 addr1
+= line_offset
;
1649 multi_run
= multi_scan
;
1653 /* line compare acts on the displayed lines */
1654 if (y
== s
->line_compare
)
1659 /* flush to display */
1660 dpy_gfx_update(s
->con
, 0, y_start
,
1661 disp_width
, y
- y_start
);
1663 /* reset modified pages */
1664 if (page_max
>= page_min
) {
1665 memory_region_reset_dirty(&s
->vram
,
1667 page_max
- page_min
,
1670 memset(s
->invalidated_y_table
, 0, ((height
+ 31) >> 5) * 4);
1673 static void vga_draw_blank(VGACommonState
*s
, int full_update
)
1675 DisplaySurface
*surface
= qemu_console_surface(s
->con
);
1681 if (s
->last_scr_width
<= 0 || s
->last_scr_height
<= 0)
1684 w
= s
->last_scr_width
* surface_bytes_per_pixel(surface
);
1685 d
= surface_data(surface
);
1686 for(i
= 0; i
< s
->last_scr_height
; i
++) {
1688 d
+= surface_stride(surface
);
1690 dpy_gfx_update(s
->con
, 0, 0,
1691 s
->last_scr_width
, s
->last_scr_height
);
1694 #define GMODE_TEXT 0
1695 #define GMODE_GRAPH 1
1696 #define GMODE_BLANK 2
1698 static void vga_update_display(void *opaque
)
1700 VGACommonState
*s
= opaque
;
1701 DisplaySurface
*surface
= qemu_console_surface(s
->con
);
1702 int full_update
, graphic_mode
;
1704 qemu_flush_coalesced_mmio_buffer();
1706 if (surface_bits_per_pixel(surface
) == 0) {
1710 if (!(s
->ar_index
& 0x20)) {
1711 graphic_mode
= GMODE_BLANK
;
1713 graphic_mode
= s
->gr
[VGA_GFX_MISC
] & VGA_GR06_GRAPHICS_MODE
;
1715 if (graphic_mode
!= s
->graphic_mode
) {
1716 s
->graphic_mode
= graphic_mode
;
1717 s
->cursor_blink_time
= qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL
);
1720 switch(graphic_mode
) {
1722 vga_draw_text(s
, full_update
);
1725 vga_draw_graphic(s
, full_update
);
1729 vga_draw_blank(s
, full_update
);
1735 /* force a full display refresh */
1736 static void vga_invalidate_display(void *opaque
)
1738 VGACommonState
*s
= opaque
;
1741 s
->last_height
= -1;
1744 void vga_common_reset(VGACommonState
*s
)
1747 memset(s
->sr
, '\0', sizeof(s
->sr
));
1749 memset(s
->gr
, '\0', sizeof(s
->gr
));
1751 memset(s
->ar
, '\0', sizeof(s
->ar
));
1752 s
->ar_flip_flop
= 0;
1754 memset(s
->cr
, '\0', sizeof(s
->cr
));
1760 s
->dac_sub_index
= 0;
1761 s
->dac_read_index
= 0;
1762 s
->dac_write_index
= 0;
1763 memset(s
->dac_cache
, '\0', sizeof(s
->dac_cache
));
1765 memset(s
->palette
, '\0', sizeof(s
->palette
));
1768 memset(s
->vbe_regs
, '\0', sizeof(s
->vbe_regs
));
1769 s
->vbe_regs
[VBE_DISPI_INDEX_ID
] = VBE_DISPI_ID5
;
1770 s
->vbe_start_addr
= 0;
1771 s
->vbe_line_offset
= 0;
1772 s
->vbe_bank_mask
= (s
->vram_size
>> 16) - 1;
1773 memset(s
->font_offsets
, '\0', sizeof(s
->font_offsets
));
1774 s
->graphic_mode
= -1; /* force full update */
1775 s
->shift_control
= 0;
1778 s
->line_compare
= 0;
1780 s
->plane_updated
= 0;
1785 s
->last_scr_width
= 0;
1786 s
->last_scr_height
= 0;
1787 s
->cursor_start
= 0;
1789 s
->cursor_offset
= 0;
1790 s
->big_endian_fb
= s
->default_endian_fb
;
1791 memset(s
->invalidated_y_table
, '\0', sizeof(s
->invalidated_y_table
));
1792 memset(s
->last_palette
, '\0', sizeof(s
->last_palette
));
1793 memset(s
->last_ch_attr
, '\0', sizeof(s
->last_ch_attr
));
1794 switch (vga_retrace_method
) {
1795 case VGA_RETRACE_DUMB
:
1797 case VGA_RETRACE_PRECISE
:
1798 memset(&s
->retrace_info
, 0, sizeof (s
->retrace_info
));
1801 vga_update_memory_access(s
);
1804 static void vga_reset(void *opaque
)
1806 VGACommonState
*s
= opaque
;
1807 vga_common_reset(s
);
1810 #define TEXTMODE_X(x) ((x) % width)
1811 #define TEXTMODE_Y(x) ((x) / width)
1812 #define VMEM2CHTYPE(v) ((v & 0xff0007ff) | \
1813 ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1))
1814 /* relay text rendering to the display driver
1815 * instead of doing a full vga_update_display() */
1816 static void vga_update_text(void *opaque
, console_ch_t
*chardata
)
1818 VGACommonState
*s
= opaque
;
1819 int graphic_mode
, i
, cursor_offset
, cursor_visible
;
1820 int cw
, cheight
, width
, height
, size
, c_min
, c_max
;
1822 console_ch_t
*dst
, val
;
1823 char msg_buffer
[80];
1824 int full_update
= 0;
1826 qemu_flush_coalesced_mmio_buffer();
1828 if (!(s
->ar_index
& 0x20)) {
1829 graphic_mode
= GMODE_BLANK
;
1831 graphic_mode
= s
->gr
[VGA_GFX_MISC
] & VGA_GR06_GRAPHICS_MODE
;
1833 if (graphic_mode
!= s
->graphic_mode
) {
1834 s
->graphic_mode
= graphic_mode
;
1837 if (s
->last_width
== -1) {
1842 switch (graphic_mode
) {
1844 /* TODO: update palette */
1845 full_update
|= update_basic_params(s
);
1847 /* total width & height */
1848 cheight
= (s
->cr
[VGA_CRTC_MAX_SCAN
] & 0x1f) + 1;
1850 if (!(s
->sr
[VGA_SEQ_CLOCK_MODE
] & VGA_SR01_CHAR_CLK_8DOTS
)) {
1853 if (s
->sr
[VGA_SEQ_CLOCK_MODE
] & 0x08) {
1854 cw
= 16; /* NOTE: no 18 pixel wide */
1856 width
= (s
->cr
[VGA_CRTC_H_DISP
] + 1);
1857 if (s
->cr
[VGA_CRTC_V_TOTAL
] == 100) {
1858 /* ugly hack for CGA 160x100x16 - explain me the logic */
1861 height
= s
->cr
[VGA_CRTC_V_DISP_END
] |
1862 ((s
->cr
[VGA_CRTC_OVERFLOW
] & 0x02) << 7) |
1863 ((s
->cr
[VGA_CRTC_OVERFLOW
] & 0x40) << 3);
1864 height
= (height
+ 1) / cheight
;
1867 size
= (height
* width
);
1868 if (size
> CH_ATTR_SIZE
) {
1872 snprintf(msg_buffer
, sizeof(msg_buffer
), "%i x %i Text mode",
1877 if (width
!= s
->last_width
|| height
!= s
->last_height
||
1878 cw
!= s
->last_cw
|| cheight
!= s
->last_ch
) {
1879 s
->last_scr_width
= width
* cw
;
1880 s
->last_scr_height
= height
* cheight
;
1881 qemu_console_resize(s
->con
, s
->last_scr_width
, s
->last_scr_height
);
1882 dpy_text_resize(s
->con
, width
, height
);
1884 s
->last_width
= width
;
1885 s
->last_height
= height
;
1886 s
->last_ch
= cheight
;
1892 s
->full_update_gfx
= 1;
1894 if (s
->full_update_text
) {
1895 s
->full_update_text
= 0;
1899 /* Update "hardware" cursor */
1900 cursor_offset
= ((s
->cr
[VGA_CRTC_CURSOR_HI
] << 8) |
1901 s
->cr
[VGA_CRTC_CURSOR_LO
]) - s
->start_addr
;
1902 if (cursor_offset
!= s
->cursor_offset
||
1903 s
->cr
[VGA_CRTC_CURSOR_START
] != s
->cursor_start
||
1904 s
->cr
[VGA_CRTC_CURSOR_END
] != s
->cursor_end
|| full_update
) {
1905 cursor_visible
= !(s
->cr
[VGA_CRTC_CURSOR_START
] & 0x20);
1906 if (cursor_visible
&& cursor_offset
< size
&& cursor_offset
>= 0)
1907 dpy_text_cursor(s
->con
,
1908 TEXTMODE_X(cursor_offset
),
1909 TEXTMODE_Y(cursor_offset
));
1911 dpy_text_cursor(s
->con
, -1, -1);
1912 s
->cursor_offset
= cursor_offset
;
1913 s
->cursor_start
= s
->cr
[VGA_CRTC_CURSOR_START
];
1914 s
->cursor_end
= s
->cr
[VGA_CRTC_CURSOR_END
];
1917 src
= (uint32_t *) s
->vram_ptr
+ s
->start_addr
;
1921 for (i
= 0; i
< size
; src
++, dst
++, i
++)
1922 console_write_ch(dst
, VMEM2CHTYPE(le32_to_cpu(*src
)));
1924 dpy_text_update(s
->con
, 0, 0, width
, height
);
1928 for (i
= 0; i
< size
; src
++, dst
++, i
++) {
1929 console_write_ch(&val
, VMEM2CHTYPE(le32_to_cpu(*src
)));
1937 for (; i
< size
; src
++, dst
++, i
++) {
1938 console_write_ch(&val
, VMEM2CHTYPE(le32_to_cpu(*src
)));
1945 if (c_min
<= c_max
) {
1946 i
= TEXTMODE_Y(c_min
);
1947 dpy_text_update(s
->con
, 0, i
, width
, TEXTMODE_Y(c_max
) - i
+ 1);
1956 s
->get_resolution(s
, &width
, &height
);
1957 snprintf(msg_buffer
, sizeof(msg_buffer
), "%i x %i Graphic mode",
1965 snprintf(msg_buffer
, sizeof(msg_buffer
), "VGA Blank mode");
1969 /* Display a message */
1971 s
->last_height
= height
= 3;
1972 dpy_text_cursor(s
->con
, -1, -1);
1973 dpy_text_resize(s
->con
, s
->last_width
, height
);
1975 for (dst
= chardata
, i
= 0; i
< s
->last_width
* height
; i
++)
1976 console_write_ch(dst
++, ' ');
1978 size
= strlen(msg_buffer
);
1979 width
= (s
->last_width
- size
) / 2;
1980 dst
= chardata
+ s
->last_width
+ width
;
1981 for (i
= 0; i
< size
; i
++)
1982 console_write_ch(dst
++, ATTR2CHTYPE(msg_buffer
[i
], QEMU_COLOR_BLUE
,
1983 QEMU_COLOR_BLACK
, 1));
1985 dpy_text_update(s
->con
, 0, 0, s
->last_width
, height
);
1988 static uint64_t vga_mem_read(void *opaque
, hwaddr addr
,
1991 VGACommonState
*s
= opaque
;
1993 return vga_mem_readb(s
, addr
);
1996 static void vga_mem_write(void *opaque
, hwaddr addr
,
1997 uint64_t data
, unsigned size
)
1999 VGACommonState
*s
= opaque
;
2001 vga_mem_writeb(s
, addr
, data
);
2004 const MemoryRegionOps vga_mem_ops
= {
2005 .read
= vga_mem_read
,
2006 .write
= vga_mem_write
,
2007 .endianness
= DEVICE_LITTLE_ENDIAN
,
2009 .min_access_size
= 1,
2010 .max_access_size
= 1,
2014 static int vga_common_post_load(void *opaque
, int version_id
)
2016 VGACommonState
*s
= opaque
;
2019 s
->graphic_mode
= -1;
2023 static bool vga_endian_state_needed(void *opaque
)
2025 VGACommonState
*s
= opaque
;
2028 * Only send the endian state if it's different from the
2029 * default one, thus ensuring backward compatibility for
2030 * migration of the common case
2032 return s
->default_endian_fb
!= s
->big_endian_fb
;
2035 static const VMStateDescription vmstate_vga_endian
= {
2036 .name
= "vga.endian",
2038 .minimum_version_id
= 1,
2039 .needed
= vga_endian_state_needed
,
2040 .fields
= (VMStateField
[]) {
2041 VMSTATE_BOOL(big_endian_fb
, VGACommonState
),
2042 VMSTATE_END_OF_LIST()
2046 const VMStateDescription vmstate_vga_common
= {
2049 .minimum_version_id
= 2,
2050 .post_load
= vga_common_post_load
,
2051 .fields
= (VMStateField
[]) {
2052 VMSTATE_UINT32(latch
, VGACommonState
),
2053 VMSTATE_UINT8(sr_index
, VGACommonState
),
2054 VMSTATE_PARTIAL_BUFFER(sr
, VGACommonState
, 8),
2055 VMSTATE_UINT8(gr_index
, VGACommonState
),
2056 VMSTATE_PARTIAL_BUFFER(gr
, VGACommonState
, 16),
2057 VMSTATE_UINT8(ar_index
, VGACommonState
),
2058 VMSTATE_BUFFER(ar
, VGACommonState
),
2059 VMSTATE_INT32(ar_flip_flop
, VGACommonState
),
2060 VMSTATE_UINT8(cr_index
, VGACommonState
),
2061 VMSTATE_BUFFER(cr
, VGACommonState
),
2062 VMSTATE_UINT8(msr
, VGACommonState
),
2063 VMSTATE_UINT8(fcr
, VGACommonState
),
2064 VMSTATE_UINT8(st00
, VGACommonState
),
2065 VMSTATE_UINT8(st01
, VGACommonState
),
2067 VMSTATE_UINT8(dac_state
, VGACommonState
),
2068 VMSTATE_UINT8(dac_sub_index
, VGACommonState
),
2069 VMSTATE_UINT8(dac_read_index
, VGACommonState
),
2070 VMSTATE_UINT8(dac_write_index
, VGACommonState
),
2071 VMSTATE_BUFFER(dac_cache
, VGACommonState
),
2072 VMSTATE_BUFFER(palette
, VGACommonState
),
2074 VMSTATE_INT32(bank_offset
, VGACommonState
),
2075 VMSTATE_UINT8_EQUAL(is_vbe_vmstate
, VGACommonState
),
2076 VMSTATE_UINT16(vbe_index
, VGACommonState
),
2077 VMSTATE_UINT16_ARRAY(vbe_regs
, VGACommonState
, VBE_DISPI_INDEX_NB
),
2078 VMSTATE_UINT32(vbe_start_addr
, VGACommonState
),
2079 VMSTATE_UINT32(vbe_line_offset
, VGACommonState
),
2080 VMSTATE_UINT32(vbe_bank_mask
, VGACommonState
),
2081 VMSTATE_END_OF_LIST()
2083 .subsections
= (const VMStateDescription
*[]) {
2084 &vmstate_vga_endian
,
2089 static const GraphicHwOps vga_ops
= {
2090 .invalidate
= vga_invalidate_display
,
2091 .gfx_update
= vga_update_display
,
2092 .text_update
= vga_update_text
,
2095 static inline uint32_t uint_clamp(uint32_t val
, uint32_t vmin
, uint32_t vmax
)
2106 void vga_common_init(VGACommonState
*s
, Object
*obj
, bool global_vmstate
)
2110 for(i
= 0;i
< 256; i
++) {
2112 for(j
= 0; j
< 8; j
++) {
2113 v
|= ((i
>> j
) & 1) << (j
* 4);
2118 for(j
= 0; j
< 4; j
++) {
2119 v
|= ((i
>> (2 * j
)) & 3) << (j
* 4);
2123 for(i
= 0; i
< 16; i
++) {
2125 for(j
= 0; j
< 4; j
++) {
2128 v
|= b
<< (2 * j
+ 1);
2133 s
->vram_size_mb
= uint_clamp(s
->vram_size_mb
, 1, 512);
2134 s
->vram_size_mb
= pow2ceil(s
->vram_size_mb
);
2135 s
->vram_size
= s
->vram_size_mb
<< 20;
2138 s
->vbe_size
= s
->vram_size
;
2141 s
->is_vbe_vmstate
= 1;
2142 memory_region_init_ram(&s
->vram
, obj
, "vga.vram", s
->vram_size
,
2144 vmstate_register_ram(&s
->vram
, global_vmstate
? NULL
: DEVICE(obj
));
2145 xen_register_framebuffer(&s
->vram
);
2146 s
->vram_ptr
= memory_region_get_ram_ptr(&s
->vram
);
2147 s
->get_bpp
= vga_get_bpp
;
2148 s
->get_offsets
= vga_get_offsets
;
2149 s
->get_resolution
= vga_get_resolution
;
2150 s
->hw_ops
= &vga_ops
;
2151 switch (vga_retrace_method
) {
2152 case VGA_RETRACE_DUMB
:
2153 s
->retrace
= vga_dumb_retrace
;
2154 s
->update_retrace_info
= vga_dumb_update_retrace_info
;
2157 case VGA_RETRACE_PRECISE
:
2158 s
->retrace
= vga_precise_retrace
;
2159 s
->update_retrace_info
= vga_precise_update_retrace_info
;
2164 * Set default fb endian based on target, could probably be turned
2165 * into a device attribute set by the machine/platform to remove
2166 * all target endian dependencies from this file.
2168 #ifdef TARGET_WORDS_BIGENDIAN
2169 s
->default_endian_fb
= true;
2171 s
->default_endian_fb
= false;
2173 vga_dirty_log_start(s
);
2176 static const MemoryRegionPortio vga_portio_list
[] = {
2177 { 0x04, 2, 1, .read
= vga_ioport_read
, .write
= vga_ioport_write
}, /* 3b4 */
2178 { 0x0a, 1, 1, .read
= vga_ioport_read
, .write
= vga_ioport_write
}, /* 3ba */
2179 { 0x10, 16, 1, .read
= vga_ioport_read
, .write
= vga_ioport_write
}, /* 3c0 */
2180 { 0x24, 2, 1, .read
= vga_ioport_read
, .write
= vga_ioport_write
}, /* 3d4 */
2181 { 0x2a, 1, 1, .read
= vga_ioport_read
, .write
= vga_ioport_write
}, /* 3da */
2182 PORTIO_END_OF_LIST(),
2185 static const MemoryRegionPortio vbe_portio_list
[] = {
2186 { 0, 1, 2, .read
= vbe_ioport_read_index
, .write
= vbe_ioport_write_index
},
2188 { 1, 1, 2, .read
= vbe_ioport_read_data
, .write
= vbe_ioport_write_data
},
2190 { 2, 1, 2, .read
= vbe_ioport_read_data
, .write
= vbe_ioport_write_data
},
2191 PORTIO_END_OF_LIST(),
2194 /* Used by both ISA and PCI */
2195 MemoryRegion
*vga_init_io(VGACommonState
*s
, Object
*obj
,
2196 const MemoryRegionPortio
**vga_ports
,
2197 const MemoryRegionPortio
**vbe_ports
)
2199 MemoryRegion
*vga_mem
;
2201 *vga_ports
= vga_portio_list
;
2202 *vbe_ports
= vbe_portio_list
;
2204 vga_mem
= g_malloc(sizeof(*vga_mem
));
2205 memory_region_init_io(vga_mem
, obj
, &vga_mem_ops
, s
,
2206 "vga-lowmem", 0x20000);
2207 memory_region_set_flush_coalesced(vga_mem
);
2212 void vga_init(VGACommonState
*s
, Object
*obj
, MemoryRegion
*address_space
,
2213 MemoryRegion
*address_space_io
, bool init_vga_ports
)
2215 MemoryRegion
*vga_io_memory
;
2216 const MemoryRegionPortio
*vga_ports
, *vbe_ports
;
2218 qemu_register_reset(vga_reset
, s
);
2222 s
->legacy_address_space
= address_space
;
2224 vga_io_memory
= vga_init_io(s
, obj
, &vga_ports
, &vbe_ports
);
2225 memory_region_add_subregion_overlap(address_space
,
2229 memory_region_set_coalescing(vga_io_memory
);
2230 if (init_vga_ports
) {
2231 portio_list_init(&s
->vga_port_list
, obj
, vga_ports
, s
, "vga");
2232 portio_list_set_flush_coalesced(&s
->vga_port_list
);
2233 portio_list_add(&s
->vga_port_list
, address_space_io
, 0x3b0);
2236 portio_list_init(&s
->vbe_port_list
, obj
, vbe_ports
, s
, "vbe");
2237 portio_list_add(&s
->vbe_port_list
, address_space_io
, 0x1ce);
2241 void vga_init_vbe(VGACommonState
*s
, Object
*obj
, MemoryRegion
*system_memory
)
2243 /* With pc-0.12 and below we map both the PCI BAR and the fixed VBE region,
2244 * so use an alias to avoid double-mapping the same region.
2246 memory_region_init_alias(&s
->vram_vbe
, obj
, "vram.vbe",
2247 &s
->vram
, 0, memory_region_size(&s
->vram
));
2248 /* XXX: use optimized standard vga accesses */
2249 memory_region_add_subregion(system_memory
,
2250 VBE_DISPI_LFB_PHYSICAL_ADDRESS
,