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 const uint32_t dmask16
[16] = {
158 static const uint32_t dmask4
[4] = {
165 static uint32_t expand4
[256];
166 static uint16_t expand2
[256];
167 static uint8_t expand4to8
[16];
169 static void vga_update_memory_access(VGACommonState
*s
)
171 hwaddr base
, offset
, size
;
173 if (s
->legacy_address_space
== NULL
) {
177 if (s
->has_chain4_alias
) {
178 memory_region_del_subregion(s
->legacy_address_space
, &s
->chain4_alias
);
179 object_unparent(OBJECT(&s
->chain4_alias
));
180 s
->has_chain4_alias
= false;
181 s
->plane_updated
= 0xf;
183 if ((s
->sr
[VGA_SEQ_PLANE_WRITE
] & VGA_SR02_ALL_PLANES
) ==
184 VGA_SR02_ALL_PLANES
&& s
->sr
[VGA_SEQ_MEMORY_MODE
] & VGA_SR04_CHN_4M
) {
186 switch ((s
->gr
[VGA_GFX_MISC
] >> 2) & 3) {
194 offset
= s
->bank_offset
;
206 base
+= isa_mem_base
;
207 memory_region_init_alias(&s
->chain4_alias
, memory_region_owner(&s
->vram
),
208 "vga.chain4", &s
->vram
, offset
, size
);
209 memory_region_add_subregion_overlap(s
->legacy_address_space
, base
,
210 &s
->chain4_alias
, 2);
211 s
->has_chain4_alias
= true;
215 static void vga_dumb_update_retrace_info(VGACommonState
*s
)
220 static void vga_precise_update_retrace_info(VGACommonState
*s
)
223 int hretr_start_char
;
224 int hretr_skew_chars
;
228 int vretr_start_line
;
237 const int clk_hz
[] = {25175000, 28322000, 25175000, 25175000};
238 int64_t chars_per_sec
;
239 struct vga_precise_retrace
*r
= &s
->retrace_info
.precise
;
241 htotal_chars
= s
->cr
[VGA_CRTC_H_TOTAL
] + 5;
242 hretr_start_char
= s
->cr
[VGA_CRTC_H_SYNC_START
];
243 hretr_skew_chars
= (s
->cr
[VGA_CRTC_H_SYNC_END
] >> 5) & 3;
244 hretr_end_char
= s
->cr
[VGA_CRTC_H_SYNC_END
] & 0x1f;
246 vtotal_lines
= (s
->cr
[VGA_CRTC_V_TOTAL
] |
247 (((s
->cr
[VGA_CRTC_OVERFLOW
] & 1) |
248 ((s
->cr
[VGA_CRTC_OVERFLOW
] >> 4) & 2)) << 8)) + 2;
249 vretr_start_line
= s
->cr
[VGA_CRTC_V_SYNC_START
] |
250 ((((s
->cr
[VGA_CRTC_OVERFLOW
] >> 2) & 1) |
251 ((s
->cr
[VGA_CRTC_OVERFLOW
] >> 6) & 2)) << 8);
252 vretr_end_line
= s
->cr
[VGA_CRTC_V_SYNC_END
] & 0xf;
254 clocking_mode
= (s
->sr
[VGA_SEQ_CLOCK_MODE
] >> 3) & 1;
255 clock_sel
= (s
->msr
>> 2) & 3;
256 dots
= (s
->msr
& 1) ? 8 : 9;
258 chars_per_sec
= clk_hz
[clock_sel
] / dots
;
260 htotal_chars
<<= clocking_mode
;
262 r
->total_chars
= vtotal_lines
* htotal_chars
;
264 r
->ticks_per_char
= get_ticks_per_sec() / (r
->total_chars
* r
->freq
);
266 r
->ticks_per_char
= get_ticks_per_sec() / chars_per_sec
;
269 r
->vstart
= vretr_start_line
;
270 r
->vend
= r
->vstart
+ vretr_end_line
+ 1;
272 r
->hstart
= hretr_start_char
+ hretr_skew_chars
;
273 r
->hend
= r
->hstart
+ hretr_end_char
+ 1;
274 r
->htotal
= htotal_chars
;
277 div2
= (s
->cr
[VGA_CRTC_MODE
] >> 2) & 1;
278 sldiv2
= (s
->cr
[VGA_CRTC_MODE
] >> 3) & 1;
288 "div2 = %d sldiv2 = %d\n"
289 "clocking_mode = %d\n"
290 "clock_sel = %d %d\n"
292 "ticks/char = %" PRId64
"\n"
294 (double) get_ticks_per_sec() / (r
->ticks_per_char
* r
->total_chars
),
312 static uint8_t vga_precise_retrace(VGACommonState
*s
)
314 struct vga_precise_retrace
*r
= &s
->retrace_info
.precise
;
315 uint8_t val
= s
->st01
& ~(ST01_V_RETRACE
| ST01_DISP_ENABLE
);
317 if (r
->total_chars
) {
318 int cur_line
, cur_line_char
, cur_char
;
321 cur_tick
= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
);
323 cur_char
= (cur_tick
/ r
->ticks_per_char
) % r
->total_chars
;
324 cur_line
= cur_char
/ r
->htotal
;
326 if (cur_line
>= r
->vstart
&& cur_line
<= r
->vend
) {
327 val
|= ST01_V_RETRACE
| ST01_DISP_ENABLE
;
329 cur_line_char
= cur_char
% r
->htotal
;
330 if (cur_line_char
>= r
->hstart
&& cur_line_char
<= r
->hend
) {
331 val
|= ST01_DISP_ENABLE
;
337 return s
->st01
^ (ST01_V_RETRACE
| ST01_DISP_ENABLE
);
341 static uint8_t vga_dumb_retrace(VGACommonState
*s
)
343 return s
->st01
^ (ST01_V_RETRACE
| ST01_DISP_ENABLE
);
346 int vga_ioport_invalid(VGACommonState
*s
, uint32_t addr
)
348 if (s
->msr
& VGA_MIS_COLOR
) {
350 return (addr
>= 0x3b0 && addr
<= 0x3bf);
353 return (addr
>= 0x3d0 && addr
<= 0x3df);
357 uint32_t vga_ioport_read(void *opaque
, uint32_t addr
)
359 VGACommonState
*s
= opaque
;
362 if (vga_ioport_invalid(s
, addr
)) {
367 if (s
->ar_flip_flop
== 0) {
374 index
= s
->ar_index
& 0x1f;
375 if (index
< VGA_ATT_C
) {
388 val
= s
->sr
[s
->sr_index
];
390 fprintf(stderr
, "vga: read SR%x = 0x%02x\n", s
->sr_index
, val
);
397 val
= s
->dac_write_index
;
400 val
= s
->palette
[s
->dac_read_index
* 3 + s
->dac_sub_index
];
401 if (++s
->dac_sub_index
== 3) {
402 s
->dac_sub_index
= 0;
416 val
= s
->gr
[s
->gr_index
];
418 fprintf(stderr
, "vga: read GR%x = 0x%02x\n", s
->gr_index
, val
);
427 val
= s
->cr
[s
->cr_index
];
429 fprintf(stderr
, "vga: read CR%x = 0x%02x\n", s
->cr_index
, val
);
434 /* just toggle to fool polling */
435 val
= s
->st01
= s
->retrace(s
);
443 #if defined(DEBUG_VGA)
444 fprintf(stderr
, "VGA: read addr=0x%04x data=0x%02x\n", addr
, val
);
449 void vga_ioport_write(void *opaque
, uint32_t addr
, uint32_t val
)
451 VGACommonState
*s
= opaque
;
454 /* check port range access depending on color/monochrome mode */
455 if (vga_ioport_invalid(s
, addr
)) {
459 fprintf(stderr
, "VGA: write addr=0x%04x data=0x%02x\n", addr
, val
);
464 if (s
->ar_flip_flop
== 0) {
468 index
= s
->ar_index
& 0x1f;
470 case VGA_ATC_PALETTE0
... VGA_ATC_PALETTEF
:
471 s
->ar
[index
] = val
& 0x3f;
474 s
->ar
[index
] = val
& ~0x10;
476 case VGA_ATC_OVERSCAN
:
479 case VGA_ATC_PLANE_ENABLE
:
480 s
->ar
[index
] = val
& ~0xc0;
483 s
->ar
[index
] = val
& ~0xf0;
485 case VGA_ATC_COLOR_PAGE
:
486 s
->ar
[index
] = val
& ~0xf0;
492 s
->ar_flip_flop
^= 1;
495 s
->msr
= val
& ~0x10;
496 s
->update_retrace_info(s
);
499 s
->sr_index
= val
& 7;
503 fprintf(stderr
, "vga: write SR%x = 0x%02x\n", s
->sr_index
, val
);
505 s
->sr
[s
->sr_index
] = val
& sr_mask
[s
->sr_index
];
506 if (s
->sr_index
== VGA_SEQ_CLOCK_MODE
) {
507 s
->update_retrace_info(s
);
509 vga_update_memory_access(s
);
512 s
->dac_read_index
= val
;
513 s
->dac_sub_index
= 0;
517 s
->dac_write_index
= val
;
518 s
->dac_sub_index
= 0;
522 s
->dac_cache
[s
->dac_sub_index
] = val
;
523 if (++s
->dac_sub_index
== 3) {
524 memcpy(&s
->palette
[s
->dac_write_index
* 3], s
->dac_cache
, 3);
525 s
->dac_sub_index
= 0;
526 s
->dac_write_index
++;
530 s
->gr_index
= val
& 0x0f;
534 fprintf(stderr
, "vga: write GR%x = 0x%02x\n", s
->gr_index
, val
);
536 s
->gr
[s
->gr_index
] = val
& gr_mask
[s
->gr_index
];
537 vga_update_memory_access(s
);
546 fprintf(stderr
, "vga: write CR%x = 0x%02x\n", s
->cr_index
, val
);
548 /* handle CR0-7 protection */
549 if ((s
->cr
[VGA_CRTC_V_SYNC_END
] & VGA_CR11_LOCK_CR0_CR7
) &&
550 s
->cr_index
<= VGA_CRTC_OVERFLOW
) {
551 /* can always write bit 4 of CR7 */
552 if (s
->cr_index
== VGA_CRTC_OVERFLOW
) {
553 s
->cr
[VGA_CRTC_OVERFLOW
] = (s
->cr
[VGA_CRTC_OVERFLOW
] & ~0x10) |
558 s
->cr
[s
->cr_index
] = val
;
560 switch(s
->cr_index
) {
561 case VGA_CRTC_H_TOTAL
:
562 case VGA_CRTC_H_SYNC_START
:
563 case VGA_CRTC_H_SYNC_END
:
564 case VGA_CRTC_V_TOTAL
:
565 case VGA_CRTC_OVERFLOW
:
566 case VGA_CRTC_V_SYNC_END
:
568 s
->update_retrace_info(s
);
580 * Sanity check vbe register writes.
582 * As we don't have a way to signal errors to the guest in the bochs
583 * dispi interface we'll go adjust the registers to the closest valid
586 static void vbe_fixup_regs(VGACommonState
*s
)
588 uint16_t *r
= s
->vbe_regs
;
589 uint32_t bits
, linelength
, maxy
, offset
;
591 if (!(r
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
)) {
592 /* vbe is turned off -- nothing to do */
597 switch (r
[VBE_DISPI_INDEX_BPP
]) {
603 bits
= r
[VBE_DISPI_INDEX_BPP
];
609 bits
= r
[VBE_DISPI_INDEX_BPP
] = 8;
614 r
[VBE_DISPI_INDEX_XRES
] &= ~7u;
615 if (r
[VBE_DISPI_INDEX_XRES
] == 0) {
616 r
[VBE_DISPI_INDEX_XRES
] = 8;
618 if (r
[VBE_DISPI_INDEX_XRES
] > VBE_DISPI_MAX_XRES
) {
619 r
[VBE_DISPI_INDEX_XRES
] = VBE_DISPI_MAX_XRES
;
621 r
[VBE_DISPI_INDEX_VIRT_WIDTH
] &= ~7u;
622 if (r
[VBE_DISPI_INDEX_VIRT_WIDTH
] > VBE_DISPI_MAX_XRES
) {
623 r
[VBE_DISPI_INDEX_VIRT_WIDTH
] = VBE_DISPI_MAX_XRES
;
625 if (r
[VBE_DISPI_INDEX_VIRT_WIDTH
] < r
[VBE_DISPI_INDEX_XRES
]) {
626 r
[VBE_DISPI_INDEX_VIRT_WIDTH
] = r
[VBE_DISPI_INDEX_XRES
];
630 linelength
= r
[VBE_DISPI_INDEX_VIRT_WIDTH
] * bits
/ 8;
631 maxy
= s
->vbe_size
/ linelength
;
632 if (r
[VBE_DISPI_INDEX_YRES
] == 0) {
633 r
[VBE_DISPI_INDEX_YRES
] = 1;
635 if (r
[VBE_DISPI_INDEX_YRES
] > VBE_DISPI_MAX_YRES
) {
636 r
[VBE_DISPI_INDEX_YRES
] = VBE_DISPI_MAX_YRES
;
638 if (r
[VBE_DISPI_INDEX_YRES
] > maxy
) {
639 r
[VBE_DISPI_INDEX_YRES
] = maxy
;
643 if (r
[VBE_DISPI_INDEX_X_OFFSET
] > VBE_DISPI_MAX_XRES
) {
644 r
[VBE_DISPI_INDEX_X_OFFSET
] = VBE_DISPI_MAX_XRES
;
646 if (r
[VBE_DISPI_INDEX_Y_OFFSET
] > VBE_DISPI_MAX_YRES
) {
647 r
[VBE_DISPI_INDEX_Y_OFFSET
] = VBE_DISPI_MAX_YRES
;
649 offset
= r
[VBE_DISPI_INDEX_X_OFFSET
] * bits
/ 8;
650 offset
+= r
[VBE_DISPI_INDEX_Y_OFFSET
] * linelength
;
651 if (offset
+ r
[VBE_DISPI_INDEX_YRES
] * linelength
> s
->vbe_size
) {
652 r
[VBE_DISPI_INDEX_Y_OFFSET
] = 0;
653 offset
= r
[VBE_DISPI_INDEX_X_OFFSET
] * bits
/ 8;
654 if (offset
+ r
[VBE_DISPI_INDEX_YRES
] * linelength
> s
->vbe_size
) {
655 r
[VBE_DISPI_INDEX_X_OFFSET
] = 0;
660 /* update vga state */
661 r
[VBE_DISPI_INDEX_VIRT_HEIGHT
] = maxy
;
662 s
->vbe_line_offset
= linelength
;
663 s
->vbe_start_addr
= offset
/ 4;
666 static uint32_t vbe_ioport_read_index(void *opaque
, uint32_t addr
)
668 VGACommonState
*s
= opaque
;
674 uint32_t vbe_ioport_read_data(void *opaque
, uint32_t addr
)
676 VGACommonState
*s
= opaque
;
679 if (s
->vbe_index
< VBE_DISPI_INDEX_NB
) {
680 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_GETCAPS
) {
681 switch(s
->vbe_index
) {
682 /* XXX: do not hardcode ? */
683 case VBE_DISPI_INDEX_XRES
:
684 val
= VBE_DISPI_MAX_XRES
;
686 case VBE_DISPI_INDEX_YRES
:
687 val
= VBE_DISPI_MAX_YRES
;
689 case VBE_DISPI_INDEX_BPP
:
690 val
= VBE_DISPI_MAX_BPP
;
693 val
= s
->vbe_regs
[s
->vbe_index
];
697 val
= s
->vbe_regs
[s
->vbe_index
];
699 } else if (s
->vbe_index
== VBE_DISPI_INDEX_VIDEO_MEMORY_64K
) {
700 val
= s
->vbe_size
/ (64 * 1024);
704 #ifdef DEBUG_BOCHS_VBE
705 fprintf(stderr
, "VBE: read index=0x%x val=0x%x\n", s
->vbe_index
, val
);
710 void vbe_ioport_write_index(void *opaque
, uint32_t addr
, uint32_t val
)
712 VGACommonState
*s
= opaque
;
716 void vbe_ioport_write_data(void *opaque
, uint32_t addr
, uint32_t val
)
718 VGACommonState
*s
= opaque
;
720 if (s
->vbe_index
<= VBE_DISPI_INDEX_NB
) {
721 #ifdef DEBUG_BOCHS_VBE
722 fprintf(stderr
, "VBE: write index=0x%x val=0x%x\n", s
->vbe_index
, val
);
724 switch(s
->vbe_index
) {
725 case VBE_DISPI_INDEX_ID
:
726 if (val
== VBE_DISPI_ID0
||
727 val
== VBE_DISPI_ID1
||
728 val
== VBE_DISPI_ID2
||
729 val
== VBE_DISPI_ID3
||
730 val
== VBE_DISPI_ID4
) {
731 s
->vbe_regs
[s
->vbe_index
] = val
;
734 case VBE_DISPI_INDEX_XRES
:
735 case VBE_DISPI_INDEX_YRES
:
736 case VBE_DISPI_INDEX_BPP
:
737 case VBE_DISPI_INDEX_VIRT_WIDTH
:
738 case VBE_DISPI_INDEX_X_OFFSET
:
739 case VBE_DISPI_INDEX_Y_OFFSET
:
740 s
->vbe_regs
[s
->vbe_index
] = val
;
743 case VBE_DISPI_INDEX_BANK
:
744 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4) {
745 val
&= (s
->vbe_bank_mask
>> 2);
747 val
&= s
->vbe_bank_mask
;
749 s
->vbe_regs
[s
->vbe_index
] = val
;
750 s
->bank_offset
= (val
<< 16);
751 vga_update_memory_access(s
);
753 case VBE_DISPI_INDEX_ENABLE
:
754 if ((val
& VBE_DISPI_ENABLED
) &&
755 !(s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
)) {
756 int h
, shift_control
;
758 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_WIDTH
] = 0;
759 s
->vbe_regs
[VBE_DISPI_INDEX_X_OFFSET
] = 0;
760 s
->vbe_regs
[VBE_DISPI_INDEX_Y_OFFSET
] = 0;
761 s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] |= VBE_DISPI_ENABLED
;
764 /* clear the screen */
765 if (!(val
& VBE_DISPI_NOCLEARMEM
)) {
766 memset(s
->vram_ptr
, 0,
767 s
->vbe_regs
[VBE_DISPI_INDEX_YRES
] * s
->vbe_line_offset
);
770 /* we initialize the VGA graphic mode */
771 /* graphic mode + memory map 1 */
772 s
->gr
[VGA_GFX_MISC
] = (s
->gr
[VGA_GFX_MISC
] & ~0x0c) | 0x04 |
773 VGA_GR06_GRAPHICS_MODE
;
774 s
->cr
[VGA_CRTC_MODE
] |= 3; /* no CGA modes */
775 s
->cr
[VGA_CRTC_OFFSET
] = s
->vbe_line_offset
>> 3;
777 s
->cr
[VGA_CRTC_H_DISP
] =
778 (s
->vbe_regs
[VBE_DISPI_INDEX_XRES
] >> 3) - 1;
779 /* height (only meaningful if < 1024) */
780 h
= s
->vbe_regs
[VBE_DISPI_INDEX_YRES
] - 1;
781 s
->cr
[VGA_CRTC_V_DISP_END
] = h
;
782 s
->cr
[VGA_CRTC_OVERFLOW
] = (s
->cr
[VGA_CRTC_OVERFLOW
] & ~0x42) |
783 ((h
>> 7) & 0x02) | ((h
>> 3) & 0x40);
784 /* line compare to 1023 */
785 s
->cr
[VGA_CRTC_LINE_COMPARE
] = 0xff;
786 s
->cr
[VGA_CRTC_OVERFLOW
] |= 0x10;
787 s
->cr
[VGA_CRTC_MAX_SCAN
] |= 0x40;
789 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4) {
791 s
->sr
[VGA_SEQ_CLOCK_MODE
] &= ~8; /* no double line */
794 /* set chain 4 mode */
795 s
->sr
[VGA_SEQ_MEMORY_MODE
] |= VGA_SR04_CHN_4M
;
796 /* activate all planes */
797 s
->sr
[VGA_SEQ_PLANE_WRITE
] |= VGA_SR02_ALL_PLANES
;
799 s
->gr
[VGA_GFX_MODE
] = (s
->gr
[VGA_GFX_MODE
] & ~0x60) |
800 (shift_control
<< 5);
801 s
->cr
[VGA_CRTC_MAX_SCAN
] &= ~0x9f; /* no double scan */
805 s
->dac_8bit
= (val
& VBE_DISPI_8BIT_DAC
) > 0;
806 s
->vbe_regs
[s
->vbe_index
] = val
;
807 vga_update_memory_access(s
);
815 /* called for accesses between 0xa0000 and 0xc0000 */
816 uint32_t vga_mem_readb(VGACommonState
*s
, hwaddr addr
)
818 int memory_map_mode
, plane
;
821 /* convert to VGA memory offset */
822 memory_map_mode
= (s
->gr
[VGA_GFX_MISC
] >> 2) & 3;
824 switch(memory_map_mode
) {
830 addr
+= s
->bank_offset
;
845 if (s
->sr
[VGA_SEQ_MEMORY_MODE
] & VGA_SR04_CHN_4M
) {
846 /* chain 4 mode : simplest access */
847 ret
= s
->vram_ptr
[addr
];
848 } else if (s
->gr
[VGA_GFX_MODE
] & 0x10) {
849 /* odd/even mode (aka text mode mapping) */
850 plane
= (s
->gr
[VGA_GFX_PLANE_READ
] & 2) | (addr
& 1);
851 ret
= s
->vram_ptr
[((addr
& ~1) << 1) | plane
];
853 /* standard VGA latched access */
854 s
->latch
= ((uint32_t *)s
->vram_ptr
)[addr
];
856 if (!(s
->gr
[VGA_GFX_MODE
] & 0x08)) {
858 plane
= s
->gr
[VGA_GFX_PLANE_READ
];
859 ret
= GET_PLANE(s
->latch
, plane
);
862 ret
= (s
->latch
^ mask16
[s
->gr
[VGA_GFX_COMPARE_VALUE
]]) &
863 mask16
[s
->gr
[VGA_GFX_COMPARE_MASK
]];
872 /* called for accesses between 0xa0000 and 0xc0000 */
873 void vga_mem_writeb(VGACommonState
*s
, hwaddr addr
, uint32_t val
)
875 int memory_map_mode
, plane
, write_mode
, b
, func_select
, mask
;
876 uint32_t write_mask
, bit_mask
, set_mask
;
879 fprintf(stderr
, "vga: [0x" TARGET_FMT_plx
"] = 0x%02x\n", addr
, val
);
881 /* convert to VGA memory offset */
882 memory_map_mode
= (s
->gr
[VGA_GFX_MISC
] >> 2) & 3;
884 switch(memory_map_mode
) {
890 addr
+= s
->bank_offset
;
905 if (s
->sr
[VGA_SEQ_MEMORY_MODE
] & VGA_SR04_CHN_4M
) {
906 /* chain 4 mode : simplest access */
909 if (s
->sr
[VGA_SEQ_PLANE_WRITE
] & mask
) {
910 s
->vram_ptr
[addr
] = val
;
912 fprintf(stderr
, "vga: chain4: [0x" TARGET_FMT_plx
"]\n", addr
);
914 s
->plane_updated
|= mask
; /* only used to detect font change */
915 memory_region_set_dirty(&s
->vram
, addr
, 1);
917 } else if (s
->gr
[VGA_GFX_MODE
] & 0x10) {
918 /* odd/even mode (aka text mode mapping) */
919 plane
= (s
->gr
[VGA_GFX_PLANE_READ
] & 2) | (addr
& 1);
921 if (s
->sr
[VGA_SEQ_PLANE_WRITE
] & mask
) {
922 addr
= ((addr
& ~1) << 1) | plane
;
923 s
->vram_ptr
[addr
] = val
;
925 fprintf(stderr
, "vga: odd/even: [0x" TARGET_FMT_plx
"]\n", addr
);
927 s
->plane_updated
|= mask
; /* only used to detect font change */
928 memory_region_set_dirty(&s
->vram
, addr
, 1);
931 /* standard VGA latched access */
932 write_mode
= s
->gr
[VGA_GFX_MODE
] & 3;
937 b
= s
->gr
[VGA_GFX_DATA_ROTATE
] & 7;
938 val
= ((val
>> b
) | (val
<< (8 - b
))) & 0xff;
942 /* apply set/reset mask */
943 set_mask
= mask16
[s
->gr
[VGA_GFX_SR_ENABLE
]];
944 val
= (val
& ~set_mask
) |
945 (mask16
[s
->gr
[VGA_GFX_SR_VALUE
]] & set_mask
);
946 bit_mask
= s
->gr
[VGA_GFX_BIT_MASK
];
952 val
= mask16
[val
& 0x0f];
953 bit_mask
= s
->gr
[VGA_GFX_BIT_MASK
];
957 b
= s
->gr
[VGA_GFX_DATA_ROTATE
] & 7;
958 val
= (val
>> b
) | (val
<< (8 - b
));
960 bit_mask
= s
->gr
[VGA_GFX_BIT_MASK
] & val
;
961 val
= mask16
[s
->gr
[VGA_GFX_SR_VALUE
]];
965 /* apply logical operation */
966 func_select
= s
->gr
[VGA_GFX_DATA_ROTATE
] >> 3;
967 switch(func_select
) {
987 bit_mask
|= bit_mask
<< 8;
988 bit_mask
|= bit_mask
<< 16;
989 val
= (val
& bit_mask
) | (s
->latch
& ~bit_mask
);
992 /* mask data according to sr[2] */
993 mask
= s
->sr
[VGA_SEQ_PLANE_WRITE
];
994 s
->plane_updated
|= mask
; /* only used to detect font change */
995 write_mask
= mask16
[mask
];
996 ((uint32_t *)s
->vram_ptr
)[addr
] =
997 (((uint32_t *)s
->vram_ptr
)[addr
] & ~write_mask
) |
1001 "vga: latch: [0x" TARGET_FMT_plx
"] mask=0x%08x val=0x%08x\n",
1002 addr
* 4, write_mask
, val
);
1004 memory_region_set_dirty(&s
->vram
, addr
<< 2, sizeof(uint32_t));
1008 typedef void vga_draw_line_func(VGACommonState
*s1
, uint8_t *d
,
1009 const uint8_t *s
, int width
);
1011 #include "vga-helpers.h"
1013 /* return true if the palette was modified */
1014 static int update_palette16(VGACommonState
*s
)
1017 uint32_t v
, col
, *palette
;
1020 palette
= s
->last_palette
;
1021 for(i
= 0; i
< 16; i
++) {
1023 if (s
->ar
[VGA_ATC_MODE
] & 0x80) {
1024 v
= ((s
->ar
[VGA_ATC_COLOR_PAGE
] & 0xf) << 4) | (v
& 0xf);
1026 v
= ((s
->ar
[VGA_ATC_COLOR_PAGE
] & 0xc) << 4) | (v
& 0x3f);
1029 col
= rgb_to_pixel32(c6_to_8(s
->palette
[v
]),
1030 c6_to_8(s
->palette
[v
+ 1]),
1031 c6_to_8(s
->palette
[v
+ 2]));
1032 if (col
!= palette
[i
]) {
1040 /* return true if the palette was modified */
1041 static int update_palette256(VGACommonState
*s
)
1044 uint32_t v
, col
, *palette
;
1047 palette
= s
->last_palette
;
1049 for(i
= 0; i
< 256; i
++) {
1051 col
= rgb_to_pixel32(s
->palette
[v
],
1055 col
= rgb_to_pixel32(c6_to_8(s
->palette
[v
]),
1056 c6_to_8(s
->palette
[v
+ 1]),
1057 c6_to_8(s
->palette
[v
+ 2]));
1059 if (col
!= palette
[i
]) {
1068 static void vga_get_offsets(VGACommonState
*s
,
1069 uint32_t *pline_offset
,
1070 uint32_t *pstart_addr
,
1071 uint32_t *pline_compare
)
1073 uint32_t start_addr
, line_offset
, line_compare
;
1075 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
) {
1076 line_offset
= s
->vbe_line_offset
;
1077 start_addr
= s
->vbe_start_addr
;
1078 line_compare
= 65535;
1080 /* compute line_offset in bytes */
1081 line_offset
= s
->cr
[VGA_CRTC_OFFSET
];
1084 /* starting address */
1085 start_addr
= s
->cr
[VGA_CRTC_START_LO
] |
1086 (s
->cr
[VGA_CRTC_START_HI
] << 8);
1089 line_compare
= s
->cr
[VGA_CRTC_LINE_COMPARE
] |
1090 ((s
->cr
[VGA_CRTC_OVERFLOW
] & 0x10) << 4) |
1091 ((s
->cr
[VGA_CRTC_MAX_SCAN
] & 0x40) << 3);
1093 *pline_offset
= line_offset
;
1094 *pstart_addr
= start_addr
;
1095 *pline_compare
= line_compare
;
1098 /* update start_addr and line_offset. Return TRUE if modified */
1099 static int update_basic_params(VGACommonState
*s
)
1102 uint32_t start_addr
, line_offset
, line_compare
;
1106 s
->get_offsets(s
, &line_offset
, &start_addr
, &line_compare
);
1108 if (line_offset
!= s
->line_offset
||
1109 start_addr
!= s
->start_addr
||
1110 line_compare
!= s
->line_compare
) {
1111 s
->line_offset
= line_offset
;
1112 s
->start_addr
= start_addr
;
1113 s
->line_compare
= line_compare
;
1120 static const uint8_t cursor_glyph
[32 * 4] = {
1121 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1122 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1123 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1124 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1125 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1126 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1127 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1128 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1129 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1130 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1131 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1132 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1133 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1134 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1135 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1136 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1139 static void vga_get_text_resolution(VGACommonState
*s
, int *pwidth
, int *pheight
,
1140 int *pcwidth
, int *pcheight
)
1142 int width
, cwidth
, height
, cheight
;
1144 /* total width & height */
1145 cheight
= (s
->cr
[VGA_CRTC_MAX_SCAN
] & 0x1f) + 1;
1147 if (!(s
->sr
[VGA_SEQ_CLOCK_MODE
] & VGA_SR01_CHAR_CLK_8DOTS
)) {
1150 if (s
->sr
[VGA_SEQ_CLOCK_MODE
] & 0x08) {
1151 cwidth
= 16; /* NOTE: no 18 pixel wide */
1153 width
= (s
->cr
[VGA_CRTC_H_DISP
] + 1);
1154 if (s
->cr
[VGA_CRTC_V_TOTAL
] == 100) {
1155 /* ugly hack for CGA 160x100x16 - explain me the logic */
1158 height
= s
->cr
[VGA_CRTC_V_DISP_END
] |
1159 ((s
->cr
[VGA_CRTC_OVERFLOW
] & 0x02) << 7) |
1160 ((s
->cr
[VGA_CRTC_OVERFLOW
] & 0x40) << 3);
1161 height
= (height
+ 1) / cheight
;
1167 *pcheight
= cheight
;
1178 static void vga_draw_text(VGACommonState
*s
, int full_update
)
1180 DisplaySurface
*surface
= qemu_console_surface(s
->con
);
1181 int cx
, cy
, cheight
, cw
, ch
, cattr
, height
, width
, ch_attr
;
1182 int cx_min
, cx_max
, linesize
, x_incr
, line
, line1
;
1183 uint32_t offset
, fgcol
, bgcol
, v
, cursor_offset
;
1184 uint8_t *d1
, *d
, *src
, *dest
, *cursor_ptr
;
1185 const uint8_t *font_ptr
, *font_base
[2];
1186 int dup9
, line_offset
;
1188 uint32_t *ch_attr_ptr
;
1189 int64_t now
= qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL
);
1191 /* compute font data address (in plane 2) */
1192 v
= s
->sr
[VGA_SEQ_CHARACTER_MAP
];
1193 offset
= (((v
>> 4) & 1) | ((v
<< 1) & 6)) * 8192 * 4 + 2;
1194 if (offset
!= s
->font_offsets
[0]) {
1195 s
->font_offsets
[0] = offset
;
1198 font_base
[0] = s
->vram_ptr
+ offset
;
1200 offset
= (((v
>> 5) & 1) | ((v
>> 1) & 6)) * 8192 * 4 + 2;
1201 font_base
[1] = s
->vram_ptr
+ offset
;
1202 if (offset
!= s
->font_offsets
[1]) {
1203 s
->font_offsets
[1] = offset
;
1206 if (s
->plane_updated
& (1 << 2) || s
->has_chain4_alias
) {
1207 /* if the plane 2 was modified since the last display, it
1208 indicates the font may have been modified */
1209 s
->plane_updated
= 0;
1212 full_update
|= update_basic_params(s
);
1214 line_offset
= s
->line_offset
;
1216 vga_get_text_resolution(s
, &width
, &height
, &cw
, &cheight
);
1217 if ((height
* width
) <= 1) {
1218 /* better than nothing: exit if transient size is too small */
1221 if ((height
* width
) > CH_ATTR_SIZE
) {
1222 /* better than nothing: exit if transient size is too big */
1226 if (width
!= s
->last_width
|| height
!= s
->last_height
||
1227 cw
!= s
->last_cw
|| cheight
!= s
->last_ch
|| s
->last_depth
) {
1228 s
->last_scr_width
= width
* cw
;
1229 s
->last_scr_height
= height
* cheight
;
1230 qemu_console_resize(s
->con
, s
->last_scr_width
, s
->last_scr_height
);
1231 surface
= qemu_console_surface(s
->con
);
1232 dpy_text_resize(s
->con
, width
, height
);
1234 s
->last_width
= width
;
1235 s
->last_height
= height
;
1236 s
->last_ch
= cheight
;
1240 full_update
|= update_palette16(s
);
1241 palette
= s
->last_palette
;
1242 x_incr
= cw
* surface_bytes_per_pixel(surface
);
1245 s
->full_update_text
= 1;
1247 if (s
->full_update_gfx
) {
1248 s
->full_update_gfx
= 0;
1252 cursor_offset
= ((s
->cr
[VGA_CRTC_CURSOR_HI
] << 8) |
1253 s
->cr
[VGA_CRTC_CURSOR_LO
]) - s
->start_addr
;
1254 if (cursor_offset
!= s
->cursor_offset
||
1255 s
->cr
[VGA_CRTC_CURSOR_START
] != s
->cursor_start
||
1256 s
->cr
[VGA_CRTC_CURSOR_END
] != s
->cursor_end
) {
1257 /* if the cursor position changed, we update the old and new
1259 if (s
->cursor_offset
< CH_ATTR_SIZE
)
1260 s
->last_ch_attr
[s
->cursor_offset
] = -1;
1261 if (cursor_offset
< CH_ATTR_SIZE
)
1262 s
->last_ch_attr
[cursor_offset
] = -1;
1263 s
->cursor_offset
= cursor_offset
;
1264 s
->cursor_start
= s
->cr
[VGA_CRTC_CURSOR_START
];
1265 s
->cursor_end
= s
->cr
[VGA_CRTC_CURSOR_END
];
1267 cursor_ptr
= s
->vram_ptr
+ (s
->start_addr
+ cursor_offset
) * 4;
1268 if (now
>= s
->cursor_blink_time
) {
1269 s
->cursor_blink_time
= now
+ VGA_TEXT_CURSOR_PERIOD_MS
/ 2;
1270 s
->cursor_visible_phase
= !s
->cursor_visible_phase
;
1273 dest
= surface_data(surface
);
1274 linesize
= surface_stride(surface
);
1275 ch_attr_ptr
= s
->last_ch_attr
;
1277 offset
= s
->start_addr
* 4;
1278 for(cy
= 0; cy
< height
; cy
++) {
1280 src
= s
->vram_ptr
+ offset
;
1283 for(cx
= 0; cx
< width
; cx
++) {
1284 ch_attr
= *(uint16_t *)src
;
1285 if (full_update
|| ch_attr
!= *ch_attr_ptr
|| src
== cursor_ptr
) {
1290 *ch_attr_ptr
= ch_attr
;
1291 #ifdef HOST_WORDS_BIGENDIAN
1293 cattr
= ch_attr
& 0xff;
1295 ch
= ch_attr
& 0xff;
1296 cattr
= ch_attr
>> 8;
1298 font_ptr
= font_base
[(cattr
>> 3) & 1];
1299 font_ptr
+= 32 * 4 * ch
;
1300 bgcol
= palette
[cattr
>> 4];
1301 fgcol
= palette
[cattr
& 0x0f];
1303 vga_draw_glyph16(d1
, linesize
,
1304 font_ptr
, cheight
, fgcol
, bgcol
);
1305 } else if (cw
!= 9) {
1306 vga_draw_glyph8(d1
, linesize
,
1307 font_ptr
, cheight
, fgcol
, bgcol
);
1310 if (ch
>= 0xb0 && ch
<= 0xdf &&
1311 (s
->ar
[VGA_ATC_MODE
] & 0x04)) {
1314 vga_draw_glyph9(d1
, linesize
,
1315 font_ptr
, cheight
, fgcol
, bgcol
, dup9
);
1317 if (src
== cursor_ptr
&&
1318 !(s
->cr
[VGA_CRTC_CURSOR_START
] & 0x20) &&
1319 s
->cursor_visible_phase
) {
1320 int line_start
, line_last
, h
;
1321 /* draw the cursor */
1322 line_start
= s
->cr
[VGA_CRTC_CURSOR_START
] & 0x1f;
1323 line_last
= s
->cr
[VGA_CRTC_CURSOR_END
] & 0x1f;
1324 /* XXX: check that */
1325 if (line_last
> cheight
- 1)
1326 line_last
= cheight
- 1;
1327 if (line_last
>= line_start
&& line_start
< cheight
) {
1328 h
= line_last
- line_start
+ 1;
1329 d
= d1
+ linesize
* line_start
;
1331 vga_draw_glyph16(d
, linesize
,
1332 cursor_glyph
, h
, fgcol
, bgcol
);
1333 } else if (cw
!= 9) {
1334 vga_draw_glyph8(d
, linesize
,
1335 cursor_glyph
, h
, fgcol
, bgcol
);
1337 vga_draw_glyph9(d
, linesize
,
1338 cursor_glyph
, h
, fgcol
, bgcol
, 1);
1348 dpy_gfx_update(s
->con
, cx_min
* cw
, cy
* cheight
,
1349 (cx_max
- cx_min
+ 1) * cw
, cheight
);
1351 dest
+= linesize
* cheight
;
1352 line1
= line
+ cheight
;
1353 offset
+= line_offset
;
1354 if (line
< s
->line_compare
&& line1
>= s
->line_compare
) {
1379 static vga_draw_line_func
* const vga_draw_line_table
[VGA_DRAW_LINE_NB
] = {
1396 static int vga_get_bpp(VGACommonState
*s
)
1400 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
) {
1401 ret
= s
->vbe_regs
[VBE_DISPI_INDEX_BPP
];
1408 static void vga_get_resolution(VGACommonState
*s
, int *pwidth
, int *pheight
)
1412 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
) {
1413 width
= s
->vbe_regs
[VBE_DISPI_INDEX_XRES
];
1414 height
= s
->vbe_regs
[VBE_DISPI_INDEX_YRES
];
1416 width
= (s
->cr
[VGA_CRTC_H_DISP
] + 1) * 8;
1417 height
= s
->cr
[VGA_CRTC_V_DISP_END
] |
1418 ((s
->cr
[VGA_CRTC_OVERFLOW
] & 0x02) << 7) |
1419 ((s
->cr
[VGA_CRTC_OVERFLOW
] & 0x40) << 3);
1420 height
= (height
+ 1);
1426 void vga_invalidate_scanlines(VGACommonState
*s
, int y1
, int y2
)
1429 if (y1
>= VGA_MAX_HEIGHT
)
1431 if (y2
>= VGA_MAX_HEIGHT
)
1432 y2
= VGA_MAX_HEIGHT
;
1433 for(y
= y1
; y
< y2
; y
++) {
1434 s
->invalidated_y_table
[y
>> 5] |= 1 << (y
& 0x1f);
1438 void vga_sync_dirty_bitmap(VGACommonState
*s
)
1440 memory_region_sync_dirty_bitmap(&s
->vram
);
1443 void vga_dirty_log_start(VGACommonState
*s
)
1445 memory_region_set_log(&s
->vram
, true, DIRTY_MEMORY_VGA
);
1448 void vga_dirty_log_stop(VGACommonState
*s
)
1450 memory_region_set_log(&s
->vram
, false, DIRTY_MEMORY_VGA
);
1456 static void vga_draw_graphic(VGACommonState
*s
, int full_update
)
1458 DisplaySurface
*surface
= qemu_console_surface(s
->con
);
1459 int y1
, y
, update
, linesize
, y_start
, double_scan
, mask
, depth
;
1460 int width
, height
, shift_control
, line_offset
, bwidth
, bits
;
1461 ram_addr_t page0
, page1
, page_min
, page_max
;
1462 int disp_width
, multi_scan
, multi_run
;
1464 uint32_t v
, addr1
, addr
;
1465 vga_draw_line_func
*vga_draw_line
= NULL
;
1466 #ifdef HOST_WORDS_BIGENDIAN
1467 bool byteswap
= !s
->big_endian_fb
;
1469 bool byteswap
= s
->big_endian_fb
;
1472 full_update
|= update_basic_params(s
);
1475 vga_sync_dirty_bitmap(s
);
1477 s
->get_resolution(s
, &width
, &height
);
1480 shift_control
= (s
->gr
[VGA_GFX_MODE
] >> 5) & 3;
1481 double_scan
= (s
->cr
[VGA_CRTC_MAX_SCAN
] >> 7);
1482 if (shift_control
!= 1) {
1483 multi_scan
= (((s
->cr
[VGA_CRTC_MAX_SCAN
] & 0x1f) + 1) << double_scan
)
1486 /* in CGA modes, multi_scan is ignored */
1487 /* XXX: is it correct ? */
1488 multi_scan
= double_scan
;
1490 multi_run
= multi_scan
;
1491 if (shift_control
!= s
->shift_control
||
1492 double_scan
!= s
->double_scan
) {
1494 s
->shift_control
= shift_control
;
1495 s
->double_scan
= double_scan
;
1498 if (shift_control
== 0) {
1499 if (s
->sr
[VGA_SEQ_CLOCK_MODE
] & 8) {
1502 } else if (shift_control
== 1) {
1503 if (s
->sr
[VGA_SEQ_CLOCK_MODE
] & 8) {
1508 depth
= s
->get_bpp(s
);
1509 if (s
->line_offset
!= s
->last_line_offset
||
1510 disp_width
!= s
->last_width
||
1511 height
!= s
->last_height
||
1512 s
->last_depth
!= depth
||
1513 s
->last_byteswap
!= byteswap
) {
1514 if (depth
== 32 || (depth
== 16 && !byteswap
)) {
1515 pixman_format_code_t format
=
1516 qemu_default_pixman_format(depth
, !byteswap
);
1517 surface
= qemu_create_displaysurface_from(disp_width
,
1518 height
, format
, s
->line_offset
,
1519 s
->vram_ptr
+ (s
->start_addr
* 4));
1520 dpy_gfx_replace_surface(s
->con
, surface
);
1522 qemu_console_resize(s
->con
, disp_width
, height
);
1523 surface
= qemu_console_surface(s
->con
);
1525 s
->last_scr_width
= disp_width
;
1526 s
->last_scr_height
= height
;
1527 s
->last_width
= disp_width
;
1528 s
->last_height
= height
;
1529 s
->last_line_offset
= s
->line_offset
;
1530 s
->last_depth
= depth
;
1531 s
->last_byteswap
= byteswap
;
1533 } else if (is_buffer_shared(surface
) &&
1534 (full_update
|| surface_data(surface
) != s
->vram_ptr
1535 + (s
->start_addr
* 4))) {
1536 pixman_format_code_t format
=
1537 qemu_default_pixman_format(depth
, !byteswap
);
1538 surface
= qemu_create_displaysurface_from(disp_width
,
1539 height
, format
, s
->line_offset
,
1540 s
->vram_ptr
+ (s
->start_addr
* 4));
1541 dpy_gfx_replace_surface(s
->con
, surface
);
1544 if (shift_control
== 0) {
1545 full_update
|= update_palette16(s
);
1546 if (s
->sr
[VGA_SEQ_CLOCK_MODE
] & 8) {
1547 v
= VGA_DRAW_LINE4D2
;
1552 } else if (shift_control
== 1) {
1553 full_update
|= update_palette16(s
);
1554 if (s
->sr
[VGA_SEQ_CLOCK_MODE
] & 8) {
1555 v
= VGA_DRAW_LINE2D2
;
1561 switch(s
->get_bpp(s
)) {
1564 full_update
|= update_palette256(s
);
1565 v
= VGA_DRAW_LINE8D2
;
1569 full_update
|= update_palette256(s
);
1574 v
= s
->big_endian_fb
? VGA_DRAW_LINE15_BE
: VGA_DRAW_LINE15_LE
;
1578 v
= s
->big_endian_fb
? VGA_DRAW_LINE16_BE
: VGA_DRAW_LINE16_LE
;
1582 v
= s
->big_endian_fb
? VGA_DRAW_LINE24_BE
: VGA_DRAW_LINE24_LE
;
1586 v
= s
->big_endian_fb
? VGA_DRAW_LINE32_BE
: VGA_DRAW_LINE32_LE
;
1591 vga_draw_line
= vga_draw_line_table
[v
];
1593 if (!is_buffer_shared(surface
) && s
->cursor_invalidate
) {
1594 s
->cursor_invalidate(s
);
1597 line_offset
= s
->line_offset
;
1600 "w=%d h=%d v=%d line_offset=%d cr[0x09]=0x%02x cr[0x17]=0x%02x "
1601 "linecmp=%d sr[0x01]=0x%02x\n",
1602 width
, height
, v
, line_offset
, s
->cr
[9], s
->cr
[VGA_CRTC_MODE
],
1603 s
->line_compare
, s
->sr
[VGA_SEQ_CLOCK_MODE
]);
1605 addr1
= (s
->start_addr
* 4);
1606 bwidth
= (width
* bits
+ 7) / 8;
1610 d
= surface_data(surface
);
1611 linesize
= surface_stride(surface
);
1613 for(y
= 0; y
< height
; y
++) {
1615 if (!(s
->cr
[VGA_CRTC_MODE
] & 1)) {
1617 /* CGA compatibility handling */
1618 shift
= 14 + ((s
->cr
[VGA_CRTC_MODE
] >> 6) & 1);
1619 addr
= (addr
& ~(1 << shift
)) | ((y1
& 1) << shift
);
1621 if (!(s
->cr
[VGA_CRTC_MODE
] & 2)) {
1622 addr
= (addr
& ~0x8000) | ((y1
& 2) << 14);
1624 update
= full_update
;
1626 page1
= addr
+ bwidth
- 1;
1627 update
|= memory_region_get_dirty(&s
->vram
, page0
, page1
- page0
,
1629 /* explicit invalidation for the hardware cursor */
1630 update
|= (s
->invalidated_y_table
[y
>> 5] >> (y
& 0x1f)) & 1;
1634 if (page0
< page_min
)
1636 if (page1
> page_max
)
1638 if (!(is_buffer_shared(surface
))) {
1639 vga_draw_line(s
, d
, s
->vram_ptr
+ addr
, width
);
1640 if (s
->cursor_draw_line
)
1641 s
->cursor_draw_line(s
, d
, y
);
1645 /* flush to display */
1646 dpy_gfx_update(s
->con
, 0, y_start
,
1647 disp_width
, y
- y_start
);
1652 mask
= (s
->cr
[VGA_CRTC_MODE
] & 3) ^ 3;
1653 if ((y1
& mask
) == mask
)
1654 addr1
+= line_offset
;
1656 multi_run
= multi_scan
;
1660 /* line compare acts on the displayed lines */
1661 if (y
== s
->line_compare
)
1666 /* flush to display */
1667 dpy_gfx_update(s
->con
, 0, y_start
,
1668 disp_width
, y
- y_start
);
1670 /* reset modified pages */
1671 if (page_max
>= page_min
) {
1672 memory_region_reset_dirty(&s
->vram
,
1674 page_max
- page_min
,
1677 memset(s
->invalidated_y_table
, 0, ((height
+ 31) >> 5) * 4);
1680 static void vga_draw_blank(VGACommonState
*s
, int full_update
)
1682 DisplaySurface
*surface
= qemu_console_surface(s
->con
);
1688 if (s
->last_scr_width
<= 0 || s
->last_scr_height
<= 0)
1691 w
= s
->last_scr_width
* surface_bytes_per_pixel(surface
);
1692 d
= surface_data(surface
);
1693 for(i
= 0; i
< s
->last_scr_height
; i
++) {
1695 d
+= surface_stride(surface
);
1697 dpy_gfx_update(s
->con
, 0, 0,
1698 s
->last_scr_width
, s
->last_scr_height
);
1701 #define GMODE_TEXT 0
1702 #define GMODE_GRAPH 1
1703 #define GMODE_BLANK 2
1705 static void vga_update_display(void *opaque
)
1707 VGACommonState
*s
= opaque
;
1708 DisplaySurface
*surface
= qemu_console_surface(s
->con
);
1709 int full_update
, graphic_mode
;
1711 qemu_flush_coalesced_mmio_buffer();
1713 if (surface_bits_per_pixel(surface
) == 0) {
1717 if (!(s
->ar_index
& 0x20)) {
1718 graphic_mode
= GMODE_BLANK
;
1720 graphic_mode
= s
->gr
[VGA_GFX_MISC
] & VGA_GR06_GRAPHICS_MODE
;
1722 if (graphic_mode
!= s
->graphic_mode
) {
1723 s
->graphic_mode
= graphic_mode
;
1724 s
->cursor_blink_time
= qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL
);
1727 switch(graphic_mode
) {
1729 vga_draw_text(s
, full_update
);
1732 vga_draw_graphic(s
, full_update
);
1736 vga_draw_blank(s
, full_update
);
1742 /* force a full display refresh */
1743 static void vga_invalidate_display(void *opaque
)
1745 VGACommonState
*s
= opaque
;
1748 s
->last_height
= -1;
1751 void vga_common_reset(VGACommonState
*s
)
1754 memset(s
->sr
, '\0', sizeof(s
->sr
));
1756 memset(s
->gr
, '\0', sizeof(s
->gr
));
1758 memset(s
->ar
, '\0', sizeof(s
->ar
));
1759 s
->ar_flip_flop
= 0;
1761 memset(s
->cr
, '\0', sizeof(s
->cr
));
1767 s
->dac_sub_index
= 0;
1768 s
->dac_read_index
= 0;
1769 s
->dac_write_index
= 0;
1770 memset(s
->dac_cache
, '\0', sizeof(s
->dac_cache
));
1772 memset(s
->palette
, '\0', sizeof(s
->palette
));
1775 memset(s
->vbe_regs
, '\0', sizeof(s
->vbe_regs
));
1776 s
->vbe_regs
[VBE_DISPI_INDEX_ID
] = VBE_DISPI_ID5
;
1777 s
->vbe_start_addr
= 0;
1778 s
->vbe_line_offset
= 0;
1779 s
->vbe_bank_mask
= (s
->vram_size
>> 16) - 1;
1780 memset(s
->font_offsets
, '\0', sizeof(s
->font_offsets
));
1781 s
->graphic_mode
= -1; /* force full update */
1782 s
->shift_control
= 0;
1785 s
->line_compare
= 0;
1787 s
->plane_updated
= 0;
1792 s
->last_scr_width
= 0;
1793 s
->last_scr_height
= 0;
1794 s
->cursor_start
= 0;
1796 s
->cursor_offset
= 0;
1797 s
->big_endian_fb
= s
->default_endian_fb
;
1798 memset(s
->invalidated_y_table
, '\0', sizeof(s
->invalidated_y_table
));
1799 memset(s
->last_palette
, '\0', sizeof(s
->last_palette
));
1800 memset(s
->last_ch_attr
, '\0', sizeof(s
->last_ch_attr
));
1801 switch (vga_retrace_method
) {
1802 case VGA_RETRACE_DUMB
:
1804 case VGA_RETRACE_PRECISE
:
1805 memset(&s
->retrace_info
, 0, sizeof (s
->retrace_info
));
1808 vga_update_memory_access(s
);
1811 static void vga_reset(void *opaque
)
1813 VGACommonState
*s
= opaque
;
1814 vga_common_reset(s
);
1817 #define TEXTMODE_X(x) ((x) % width)
1818 #define TEXTMODE_Y(x) ((x) / width)
1819 #define VMEM2CHTYPE(v) ((v & 0xff0007ff) | \
1820 ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1))
1821 /* relay text rendering to the display driver
1822 * instead of doing a full vga_update_display() */
1823 static void vga_update_text(void *opaque
, console_ch_t
*chardata
)
1825 VGACommonState
*s
= opaque
;
1826 int graphic_mode
, i
, cursor_offset
, cursor_visible
;
1827 int cw
, cheight
, width
, height
, size
, c_min
, c_max
;
1829 console_ch_t
*dst
, val
;
1830 char msg_buffer
[80];
1831 int full_update
= 0;
1833 qemu_flush_coalesced_mmio_buffer();
1835 if (!(s
->ar_index
& 0x20)) {
1836 graphic_mode
= GMODE_BLANK
;
1838 graphic_mode
= s
->gr
[VGA_GFX_MISC
] & VGA_GR06_GRAPHICS_MODE
;
1840 if (graphic_mode
!= s
->graphic_mode
) {
1841 s
->graphic_mode
= graphic_mode
;
1844 if (s
->last_width
== -1) {
1849 switch (graphic_mode
) {
1851 /* TODO: update palette */
1852 full_update
|= update_basic_params(s
);
1854 /* total width & height */
1855 cheight
= (s
->cr
[VGA_CRTC_MAX_SCAN
] & 0x1f) + 1;
1857 if (!(s
->sr
[VGA_SEQ_CLOCK_MODE
] & VGA_SR01_CHAR_CLK_8DOTS
)) {
1860 if (s
->sr
[VGA_SEQ_CLOCK_MODE
] & 0x08) {
1861 cw
= 16; /* NOTE: no 18 pixel wide */
1863 width
= (s
->cr
[VGA_CRTC_H_DISP
] + 1);
1864 if (s
->cr
[VGA_CRTC_V_TOTAL
] == 100) {
1865 /* ugly hack for CGA 160x100x16 - explain me the logic */
1868 height
= s
->cr
[VGA_CRTC_V_DISP_END
] |
1869 ((s
->cr
[VGA_CRTC_OVERFLOW
] & 0x02) << 7) |
1870 ((s
->cr
[VGA_CRTC_OVERFLOW
] & 0x40) << 3);
1871 height
= (height
+ 1) / cheight
;
1874 size
= (height
* width
);
1875 if (size
> CH_ATTR_SIZE
) {
1879 snprintf(msg_buffer
, sizeof(msg_buffer
), "%i x %i Text mode",
1884 if (width
!= s
->last_width
|| height
!= s
->last_height
||
1885 cw
!= s
->last_cw
|| cheight
!= s
->last_ch
) {
1886 s
->last_scr_width
= width
* cw
;
1887 s
->last_scr_height
= height
* cheight
;
1888 qemu_console_resize(s
->con
, s
->last_scr_width
, s
->last_scr_height
);
1889 dpy_text_resize(s
->con
, width
, height
);
1891 s
->last_width
= width
;
1892 s
->last_height
= height
;
1893 s
->last_ch
= cheight
;
1899 s
->full_update_gfx
= 1;
1901 if (s
->full_update_text
) {
1902 s
->full_update_text
= 0;
1906 /* Update "hardware" cursor */
1907 cursor_offset
= ((s
->cr
[VGA_CRTC_CURSOR_HI
] << 8) |
1908 s
->cr
[VGA_CRTC_CURSOR_LO
]) - s
->start_addr
;
1909 if (cursor_offset
!= s
->cursor_offset
||
1910 s
->cr
[VGA_CRTC_CURSOR_START
] != s
->cursor_start
||
1911 s
->cr
[VGA_CRTC_CURSOR_END
] != s
->cursor_end
|| full_update
) {
1912 cursor_visible
= !(s
->cr
[VGA_CRTC_CURSOR_START
] & 0x20);
1913 if (cursor_visible
&& cursor_offset
< size
&& cursor_offset
>= 0)
1914 dpy_text_cursor(s
->con
,
1915 TEXTMODE_X(cursor_offset
),
1916 TEXTMODE_Y(cursor_offset
));
1918 dpy_text_cursor(s
->con
, -1, -1);
1919 s
->cursor_offset
= cursor_offset
;
1920 s
->cursor_start
= s
->cr
[VGA_CRTC_CURSOR_START
];
1921 s
->cursor_end
= s
->cr
[VGA_CRTC_CURSOR_END
];
1924 src
= (uint32_t *) s
->vram_ptr
+ s
->start_addr
;
1928 for (i
= 0; i
< size
; src
++, dst
++, i
++)
1929 console_write_ch(dst
, VMEM2CHTYPE(le32_to_cpu(*src
)));
1931 dpy_text_update(s
->con
, 0, 0, width
, height
);
1935 for (i
= 0; i
< size
; src
++, dst
++, i
++) {
1936 console_write_ch(&val
, VMEM2CHTYPE(le32_to_cpu(*src
)));
1944 for (; i
< size
; src
++, dst
++, i
++) {
1945 console_write_ch(&val
, VMEM2CHTYPE(le32_to_cpu(*src
)));
1952 if (c_min
<= c_max
) {
1953 i
= TEXTMODE_Y(c_min
);
1954 dpy_text_update(s
->con
, 0, i
, width
, TEXTMODE_Y(c_max
) - i
+ 1);
1963 s
->get_resolution(s
, &width
, &height
);
1964 snprintf(msg_buffer
, sizeof(msg_buffer
), "%i x %i Graphic mode",
1972 snprintf(msg_buffer
, sizeof(msg_buffer
), "VGA Blank mode");
1976 /* Display a message */
1978 s
->last_height
= height
= 3;
1979 dpy_text_cursor(s
->con
, -1, -1);
1980 dpy_text_resize(s
->con
, s
->last_width
, height
);
1982 for (dst
= chardata
, i
= 0; i
< s
->last_width
* height
; i
++)
1983 console_write_ch(dst
++, ' ');
1985 size
= strlen(msg_buffer
);
1986 width
= (s
->last_width
- size
) / 2;
1987 dst
= chardata
+ s
->last_width
+ width
;
1988 for (i
= 0; i
< size
; i
++)
1989 console_write_ch(dst
++, 0x00200100 | msg_buffer
[i
]);
1991 dpy_text_update(s
->con
, 0, 0, s
->last_width
, height
);
1994 static uint64_t vga_mem_read(void *opaque
, hwaddr addr
,
1997 VGACommonState
*s
= opaque
;
1999 return vga_mem_readb(s
, addr
);
2002 static void vga_mem_write(void *opaque
, hwaddr addr
,
2003 uint64_t data
, unsigned size
)
2005 VGACommonState
*s
= opaque
;
2007 return vga_mem_writeb(s
, addr
, data
);
2010 const MemoryRegionOps vga_mem_ops
= {
2011 .read
= vga_mem_read
,
2012 .write
= vga_mem_write
,
2013 .endianness
= DEVICE_LITTLE_ENDIAN
,
2015 .min_access_size
= 1,
2016 .max_access_size
= 1,
2020 static int vga_common_post_load(void *opaque
, int version_id
)
2022 VGACommonState
*s
= opaque
;
2025 s
->graphic_mode
= -1;
2029 static bool vga_endian_state_needed(void *opaque
)
2031 VGACommonState
*s
= opaque
;
2034 * Only send the endian state if it's different from the
2035 * default one, thus ensuring backward compatibility for
2036 * migration of the common case
2038 return s
->default_endian_fb
!= s
->big_endian_fb
;
2041 const VMStateDescription vmstate_vga_endian
= {
2042 .name
= "vga.endian",
2044 .minimum_version_id
= 1,
2045 .fields
= (VMStateField
[]) {
2046 VMSTATE_BOOL(big_endian_fb
, VGACommonState
),
2047 VMSTATE_END_OF_LIST()
2051 const VMStateDescription vmstate_vga_common
= {
2054 .minimum_version_id
= 2,
2055 .post_load
= vga_common_post_load
,
2056 .fields
= (VMStateField
[]) {
2057 VMSTATE_UINT32(latch
, VGACommonState
),
2058 VMSTATE_UINT8(sr_index
, VGACommonState
),
2059 VMSTATE_PARTIAL_BUFFER(sr
, VGACommonState
, 8),
2060 VMSTATE_UINT8(gr_index
, VGACommonState
),
2061 VMSTATE_PARTIAL_BUFFER(gr
, VGACommonState
, 16),
2062 VMSTATE_UINT8(ar_index
, VGACommonState
),
2063 VMSTATE_BUFFER(ar
, VGACommonState
),
2064 VMSTATE_INT32(ar_flip_flop
, VGACommonState
),
2065 VMSTATE_UINT8(cr_index
, VGACommonState
),
2066 VMSTATE_BUFFER(cr
, VGACommonState
),
2067 VMSTATE_UINT8(msr
, VGACommonState
),
2068 VMSTATE_UINT8(fcr
, VGACommonState
),
2069 VMSTATE_UINT8(st00
, VGACommonState
),
2070 VMSTATE_UINT8(st01
, VGACommonState
),
2072 VMSTATE_UINT8(dac_state
, VGACommonState
),
2073 VMSTATE_UINT8(dac_sub_index
, VGACommonState
),
2074 VMSTATE_UINT8(dac_read_index
, VGACommonState
),
2075 VMSTATE_UINT8(dac_write_index
, VGACommonState
),
2076 VMSTATE_BUFFER(dac_cache
, VGACommonState
),
2077 VMSTATE_BUFFER(palette
, VGACommonState
),
2079 VMSTATE_INT32(bank_offset
, VGACommonState
),
2080 VMSTATE_UINT8_EQUAL(is_vbe_vmstate
, VGACommonState
),
2081 VMSTATE_UINT16(vbe_index
, VGACommonState
),
2082 VMSTATE_UINT16_ARRAY(vbe_regs
, VGACommonState
, VBE_DISPI_INDEX_NB
),
2083 VMSTATE_UINT32(vbe_start_addr
, VGACommonState
),
2084 VMSTATE_UINT32(vbe_line_offset
, VGACommonState
),
2085 VMSTATE_UINT32(vbe_bank_mask
, VGACommonState
),
2086 VMSTATE_END_OF_LIST()
2088 .subsections
= (VMStateSubsection
[]) {
2090 .vmsd
= &vmstate_vga_endian
,
2091 .needed
= vga_endian_state_needed
,
2098 static const GraphicHwOps vga_ops
= {
2099 .invalidate
= vga_invalidate_display
,
2100 .gfx_update
= vga_update_display
,
2101 .text_update
= vga_update_text
,
2104 void vga_common_init(VGACommonState
*s
, Object
*obj
, bool global_vmstate
)
2108 for(i
= 0;i
< 256; i
++) {
2110 for(j
= 0; j
< 8; j
++) {
2111 v
|= ((i
>> j
) & 1) << (j
* 4);
2116 for(j
= 0; j
< 4; j
++) {
2117 v
|= ((i
>> (2 * j
)) & 3) << (j
* 4);
2121 for(i
= 0; i
< 16; i
++) {
2123 for(j
= 0; j
< 4; j
++) {
2126 v
|= b
<< (2 * j
+ 1);
2131 /* valid range: 1 MB -> 256 MB */
2132 s
->vram_size
= 1024 * 1024;
2133 while (s
->vram_size
< (s
->vram_size_mb
<< 20) &&
2134 s
->vram_size
< (256 << 20)) {
2137 s
->vram_size_mb
= s
->vram_size
>> 20;
2139 s
->vbe_size
= s
->vram_size
;
2142 s
->is_vbe_vmstate
= 1;
2143 memory_region_init_ram(&s
->vram
, obj
, "vga.vram", s
->vram_size
,
2145 vmstate_register_ram(&s
->vram
, global_vmstate
? NULL
: DEVICE(obj
));
2146 xen_register_framebuffer(&s
->vram
);
2147 s
->vram_ptr
= memory_region_get_ram_ptr(&s
->vram
);
2148 s
->get_bpp
= vga_get_bpp
;
2149 s
->get_offsets
= vga_get_offsets
;
2150 s
->get_resolution
= vga_get_resolution
;
2151 s
->hw_ops
= &vga_ops
;
2152 switch (vga_retrace_method
) {
2153 case VGA_RETRACE_DUMB
:
2154 s
->retrace
= vga_dumb_retrace
;
2155 s
->update_retrace_info
= vga_dumb_update_retrace_info
;
2158 case VGA_RETRACE_PRECISE
:
2159 s
->retrace
= vga_precise_retrace
;
2160 s
->update_retrace_info
= vga_precise_update_retrace_info
;
2165 * Set default fb endian based on target, could probably be turned
2166 * into a device attribute set by the machine/platform to remove
2167 * all target endian dependencies from this file.
2169 #ifdef TARGET_WORDS_BIGENDIAN
2170 s
->default_endian_fb
= true;
2172 s
->default_endian_fb
= false;
2174 vga_dirty_log_start(s
);
2177 static const MemoryRegionPortio vga_portio_list
[] = {
2178 { 0x04, 2, 1, .read
= vga_ioport_read
, .write
= vga_ioport_write
}, /* 3b4 */
2179 { 0x0a, 1, 1, .read
= vga_ioport_read
, .write
= vga_ioport_write
}, /* 3ba */
2180 { 0x10, 16, 1, .read
= vga_ioport_read
, .write
= vga_ioport_write
}, /* 3c0 */
2181 { 0x24, 2, 1, .read
= vga_ioport_read
, .write
= vga_ioport_write
}, /* 3d4 */
2182 { 0x2a, 1, 1, .read
= vga_ioport_read
, .write
= vga_ioport_write
}, /* 3da */
2183 PORTIO_END_OF_LIST(),
2186 static const MemoryRegionPortio vbe_portio_list
[] = {
2187 { 0, 1, 2, .read
= vbe_ioport_read_index
, .write
= vbe_ioport_write_index
},
2189 { 1, 1, 2, .read
= vbe_ioport_read_data
, .write
= vbe_ioport_write_data
},
2191 { 2, 1, 2, .read
= vbe_ioport_read_data
, .write
= vbe_ioport_write_data
},
2192 PORTIO_END_OF_LIST(),
2195 /* Used by both ISA and PCI */
2196 MemoryRegion
*vga_init_io(VGACommonState
*s
, Object
*obj
,
2197 const MemoryRegionPortio
**vga_ports
,
2198 const MemoryRegionPortio
**vbe_ports
)
2200 MemoryRegion
*vga_mem
;
2202 *vga_ports
= vga_portio_list
;
2203 *vbe_ports
= vbe_portio_list
;
2205 vga_mem
= g_malloc(sizeof(*vga_mem
));
2206 memory_region_init_io(vga_mem
, obj
, &vga_mem_ops
, s
,
2207 "vga-lowmem", 0x20000);
2208 memory_region_set_flush_coalesced(vga_mem
);
2213 void vga_init(VGACommonState
*s
, Object
*obj
, MemoryRegion
*address_space
,
2214 MemoryRegion
*address_space_io
, bool init_vga_ports
)
2216 MemoryRegion
*vga_io_memory
;
2217 const MemoryRegionPortio
*vga_ports
, *vbe_ports
;
2219 qemu_register_reset(vga_reset
, s
);
2223 s
->legacy_address_space
= address_space
;
2225 vga_io_memory
= vga_init_io(s
, obj
, &vga_ports
, &vbe_ports
);
2226 memory_region_add_subregion_overlap(address_space
,
2227 isa_mem_base
+ 0x000a0000,
2230 memory_region_set_coalescing(vga_io_memory
);
2231 if (init_vga_ports
) {
2232 portio_list_init(&s
->vga_port_list
, obj
, vga_ports
, s
, "vga");
2233 portio_list_set_flush_coalesced(&s
->vga_port_list
);
2234 portio_list_add(&s
->vga_port_list
, address_space_io
, 0x3b0);
2237 portio_list_init(&s
->vbe_port_list
, obj
, vbe_ports
, s
, "vbe");
2238 portio_list_add(&s
->vbe_port_list
, address_space_io
, 0x1ce);
2242 void vga_init_vbe(VGACommonState
*s
, Object
*obj
, MemoryRegion
*system_memory
)
2244 /* With pc-0.12 and below we map both the PCI BAR and the fixed VBE region,
2245 * so use an alias to avoid double-mapping the same region.
2247 memory_region_init_alias(&s
->vram_vbe
, obj
, "vram.vbe",
2248 &s
->vram
, 0, memory_region_size(&s
->vram
));
2249 /* XXX: use optimized standard vga accesses */
2250 memory_region_add_subregion(system_memory
,
2251 VBE_DISPI_LFB_PHYSICAL_ADDRESS
,