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
29 #include "pixel_ops.h"
35 //#define DEBUG_VGA_MEM
36 //#define DEBUG_VGA_REG
38 //#define DEBUG_BOCHS_VBE
40 /* force some bits to zero */
41 const uint8_t sr_mask
[8] = {
52 const uint8_t gr_mask
[16] = {
53 (uint8_t)~0xf0, /* 0x00 */
54 (uint8_t)~0xf0, /* 0x01 */
55 (uint8_t)~0xf0, /* 0x02 */
56 (uint8_t)~0xe0, /* 0x03 */
57 (uint8_t)~0xfc, /* 0x04 */
58 (uint8_t)~0x84, /* 0x05 */
59 (uint8_t)~0xf0, /* 0x06 */
60 (uint8_t)~0xf0, /* 0x07 */
61 (uint8_t)~0x00, /* 0x08 */
62 (uint8_t)~0xff, /* 0x09 */
63 (uint8_t)~0xff, /* 0x0a */
64 (uint8_t)~0xff, /* 0x0b */
65 (uint8_t)~0xff, /* 0x0c */
66 (uint8_t)~0xff, /* 0x0d */
67 (uint8_t)~0xff, /* 0x0e */
68 (uint8_t)~0xff, /* 0x0f */
71 #define cbswap_32(__x) \
73 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
74 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
75 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
76 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
78 #ifdef WORDS_BIGENDIAN
79 #define PAT(x) cbswap_32(x)
84 #ifdef WORDS_BIGENDIAN
90 #ifdef WORDS_BIGENDIAN
91 #define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
93 #define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
96 static const uint32_t mask16
[16] = {
117 #ifdef WORDS_BIGENDIAN
120 #define PAT(x) cbswap_32(x)
123 static const uint32_t dmask16
[16] = {
142 static const uint32_t dmask4
[4] = {
149 static uint32_t expand4
[256];
150 static uint16_t expand2
[256];
151 static uint8_t expand4to8
[16];
153 static void vga_screen_dump(void *opaque
, const char *filename
);
155 static uint32_t vga_ioport_read(void *opaque
, uint32_t addr
)
157 VGAState
*s
= opaque
;
160 /* check port range access depending on color/monochrome mode */
161 if ((addr
>= 0x3b0 && addr
<= 0x3bf && (s
->msr
& MSR_COLOR_EMULATION
)) ||
162 (addr
>= 0x3d0 && addr
<= 0x3df && !(s
->msr
& MSR_COLOR_EMULATION
))) {
167 if (s
->ar_flip_flop
== 0) {
174 index
= s
->ar_index
& 0x1f;
187 val
= s
->sr
[s
->sr_index
];
189 printf("vga: read SR%x = 0x%02x\n", s
->sr_index
, val
);
196 val
= s
->dac_write_index
;
199 val
= s
->palette
[s
->dac_read_index
* 3 + s
->dac_sub_index
];
200 if (++s
->dac_sub_index
== 3) {
201 s
->dac_sub_index
= 0;
215 val
= s
->gr
[s
->gr_index
];
217 printf("vga: read GR%x = 0x%02x\n", s
->gr_index
, val
);
226 val
= s
->cr
[s
->cr_index
];
228 printf("vga: read CR%x = 0x%02x\n", s
->cr_index
, val
);
233 /* just toggle to fool polling */
234 s
->st01
^= ST01_V_RETRACE
| ST01_DISP_ENABLE
;
243 #if defined(DEBUG_VGA)
244 printf("VGA: read addr=0x%04x data=0x%02x\n", addr
, val
);
249 static void vga_ioport_write(void *opaque
, uint32_t addr
, uint32_t val
)
251 VGAState
*s
= opaque
;
254 /* check port range access depending on color/monochrome mode */
255 if ((addr
>= 0x3b0 && addr
<= 0x3bf && (s
->msr
& MSR_COLOR_EMULATION
)) ||
256 (addr
>= 0x3d0 && addr
<= 0x3df && !(s
->msr
& MSR_COLOR_EMULATION
)))
260 printf("VGA: write addr=0x%04x data=0x%02x\n", addr
, val
);
265 if (s
->ar_flip_flop
== 0) {
269 index
= s
->ar_index
& 0x1f;
272 s
->ar
[index
] = val
& 0x3f;
275 s
->ar
[index
] = val
& ~0x10;
281 s
->ar
[index
] = val
& ~0xc0;
284 s
->ar
[index
] = val
& ~0xf0;
287 s
->ar
[index
] = val
& ~0xf0;
293 s
->ar_flip_flop
^= 1;
296 s
->msr
= val
& ~0x10;
299 s
->sr_index
= val
& 7;
303 printf("vga: write SR%x = 0x%02x\n", s
->sr_index
, val
);
305 s
->sr
[s
->sr_index
] = val
& sr_mask
[s
->sr_index
];
308 s
->dac_read_index
= val
;
309 s
->dac_sub_index
= 0;
313 s
->dac_write_index
= val
;
314 s
->dac_sub_index
= 0;
318 s
->dac_cache
[s
->dac_sub_index
] = val
;
319 if (++s
->dac_sub_index
== 3) {
320 memcpy(&s
->palette
[s
->dac_write_index
* 3], s
->dac_cache
, 3);
321 s
->dac_sub_index
= 0;
322 s
->dac_write_index
++;
326 s
->gr_index
= val
& 0x0f;
330 printf("vga: write GR%x = 0x%02x\n", s
->gr_index
, val
);
332 s
->gr
[s
->gr_index
] = val
& gr_mask
[s
->gr_index
];
341 printf("vga: write CR%x = 0x%02x\n", s
->cr_index
, val
);
343 /* handle CR0-7 protection */
344 if ((s
->cr
[0x11] & 0x80) && s
->cr_index
<= 7) {
345 /* can always write bit 4 of CR7 */
346 if (s
->cr_index
== 7)
347 s
->cr
[7] = (s
->cr
[7] & ~0x10) | (val
& 0x10);
350 switch(s
->cr_index
) {
351 case 0x01: /* horizontal display end */
356 case 0x12: /* vertical display end */
357 s
->cr
[s
->cr_index
] = val
;
360 s
->cr
[s
->cr_index
] = val
;
371 #ifdef CONFIG_BOCHS_VBE
372 static uint32_t vbe_ioport_read_index(void *opaque
, uint32_t addr
)
374 VGAState
*s
= opaque
;
380 static uint32_t vbe_ioport_read_data(void *opaque
, uint32_t addr
)
382 VGAState
*s
= opaque
;
385 if (s
->vbe_index
<= VBE_DISPI_INDEX_NB
) {
386 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_GETCAPS
) {
387 switch(s
->vbe_index
) {
388 /* XXX: do not hardcode ? */
389 case VBE_DISPI_INDEX_XRES
:
390 val
= VBE_DISPI_MAX_XRES
;
392 case VBE_DISPI_INDEX_YRES
:
393 val
= VBE_DISPI_MAX_YRES
;
395 case VBE_DISPI_INDEX_BPP
:
396 val
= VBE_DISPI_MAX_BPP
;
399 val
= s
->vbe_regs
[s
->vbe_index
];
403 val
= s
->vbe_regs
[s
->vbe_index
];
408 #ifdef DEBUG_BOCHS_VBE
409 printf("VBE: read index=0x%x val=0x%x\n", s
->vbe_index
, val
);
414 static void vbe_ioport_write_index(void *opaque
, uint32_t addr
, uint32_t val
)
416 VGAState
*s
= opaque
;
420 static void vbe_ioport_write_data(void *opaque
, uint32_t addr
, uint32_t val
)
422 VGAState
*s
= opaque
;
424 if (s
->vbe_index
<= VBE_DISPI_INDEX_NB
) {
425 #ifdef DEBUG_BOCHS_VBE
426 printf("VBE: write index=0x%x val=0x%x\n", s
->vbe_index
, val
);
428 switch(s
->vbe_index
) {
429 case VBE_DISPI_INDEX_ID
:
430 if (val
== VBE_DISPI_ID0
||
431 val
== VBE_DISPI_ID1
||
432 val
== VBE_DISPI_ID2
||
433 val
== VBE_DISPI_ID3
||
434 val
== VBE_DISPI_ID4
) {
435 s
->vbe_regs
[s
->vbe_index
] = val
;
438 case VBE_DISPI_INDEX_XRES
:
439 if ((val
<= VBE_DISPI_MAX_XRES
) && ((val
& 7) == 0)) {
440 s
->vbe_regs
[s
->vbe_index
] = val
;
443 case VBE_DISPI_INDEX_YRES
:
444 if (val
<= VBE_DISPI_MAX_YRES
) {
445 s
->vbe_regs
[s
->vbe_index
] = val
;
448 case VBE_DISPI_INDEX_BPP
:
451 if (val
== 4 || val
== 8 || val
== 15 ||
452 val
== 16 || val
== 24 || val
== 32) {
453 s
->vbe_regs
[s
->vbe_index
] = val
;
456 case VBE_DISPI_INDEX_BANK
:
457 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4) {
458 val
&= (s
->vbe_bank_mask
>> 2);
460 val
&= s
->vbe_bank_mask
;
462 s
->vbe_regs
[s
->vbe_index
] = val
;
463 s
->bank_offset
= (val
<< 16);
465 case VBE_DISPI_INDEX_ENABLE
:
466 if ((val
& VBE_DISPI_ENABLED
) &&
467 !(s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
)) {
468 int h
, shift_control
;
470 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_WIDTH
] =
471 s
->vbe_regs
[VBE_DISPI_INDEX_XRES
];
472 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_HEIGHT
] =
473 s
->vbe_regs
[VBE_DISPI_INDEX_YRES
];
474 s
->vbe_regs
[VBE_DISPI_INDEX_X_OFFSET
] = 0;
475 s
->vbe_regs
[VBE_DISPI_INDEX_Y_OFFSET
] = 0;
477 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4)
478 s
->vbe_line_offset
= s
->vbe_regs
[VBE_DISPI_INDEX_XRES
] >> 1;
480 s
->vbe_line_offset
= s
->vbe_regs
[VBE_DISPI_INDEX_XRES
] *
481 ((s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] + 7) >> 3);
482 s
->vbe_start_addr
= 0;
484 /* clear the screen (should be done in BIOS) */
485 if (!(val
& VBE_DISPI_NOCLEARMEM
)) {
486 memset(s
->vram_ptr
, 0,
487 s
->vbe_regs
[VBE_DISPI_INDEX_YRES
] * s
->vbe_line_offset
);
490 /* we initialize the VGA graphic mode (should be done
492 s
->gr
[0x06] = (s
->gr
[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
493 s
->cr
[0x17] |= 3; /* no CGA modes */
494 s
->cr
[0x13] = s
->vbe_line_offset
>> 3;
496 s
->cr
[0x01] = (s
->vbe_regs
[VBE_DISPI_INDEX_XRES
] >> 3) - 1;
497 /* height (only meaningful if < 1024) */
498 h
= s
->vbe_regs
[VBE_DISPI_INDEX_YRES
] - 1;
500 s
->cr
[0x07] = (s
->cr
[0x07] & ~0x42) |
501 ((h
>> 7) & 0x02) | ((h
>> 3) & 0x40);
502 /* line compare to 1023 */
507 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4) {
509 s
->sr
[0x01] &= ~8; /* no double line */
512 s
->sr
[4] |= 0x08; /* set chain 4 mode */
513 s
->sr
[2] |= 0x0f; /* activate all planes */
515 s
->gr
[0x05] = (s
->gr
[0x05] & ~0x60) | (shift_control
<< 5);
516 s
->cr
[0x09] &= ~0x9f; /* no double scan */
518 /* XXX: the bios should do that */
521 s
->dac_8bit
= (val
& VBE_DISPI_8BIT_DAC
) > 0;
522 s
->vbe_regs
[s
->vbe_index
] = val
;
524 case VBE_DISPI_INDEX_VIRT_WIDTH
:
526 int w
, h
, line_offset
;
528 if (val
< s
->vbe_regs
[VBE_DISPI_INDEX_XRES
])
531 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4)
532 line_offset
= w
>> 1;
534 line_offset
= w
* ((s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] + 7) >> 3);
535 h
= s
->vram_size
/ line_offset
;
536 /* XXX: support weird bochs semantics ? */
537 if (h
< s
->vbe_regs
[VBE_DISPI_INDEX_YRES
])
539 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_WIDTH
] = w
;
540 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_HEIGHT
] = h
;
541 s
->vbe_line_offset
= line_offset
;
544 case VBE_DISPI_INDEX_X_OFFSET
:
545 case VBE_DISPI_INDEX_Y_OFFSET
:
548 s
->vbe_regs
[s
->vbe_index
] = val
;
549 s
->vbe_start_addr
= s
->vbe_line_offset
* s
->vbe_regs
[VBE_DISPI_INDEX_Y_OFFSET
];
550 x
= s
->vbe_regs
[VBE_DISPI_INDEX_X_OFFSET
];
551 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4)
552 s
->vbe_start_addr
+= x
>> 1;
554 s
->vbe_start_addr
+= x
* ((s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] + 7) >> 3);
555 s
->vbe_start_addr
>>= 2;
565 /* called for accesses between 0xa0000 and 0xc0000 */
566 uint32_t vga_mem_readb(void *opaque
, target_phys_addr_t addr
)
568 VGAState
*s
= opaque
;
569 int memory_map_mode
, plane
;
572 /* convert to VGA memory offset */
573 memory_map_mode
= (s
->gr
[6] >> 2) & 3;
575 switch(memory_map_mode
) {
581 addr
+= s
->bank_offset
;
596 if (s
->sr
[4] & 0x08) {
597 /* chain 4 mode : simplest access */
598 ret
= s
->vram_ptr
[addr
];
599 } else if (s
->gr
[5] & 0x10) {
600 /* odd/even mode (aka text mode mapping) */
601 plane
= (s
->gr
[4] & 2) | (addr
& 1);
602 ret
= s
->vram_ptr
[((addr
& ~1) << 1) | plane
];
604 /* standard VGA latched access */
605 s
->latch
= ((uint32_t *)s
->vram_ptr
)[addr
];
607 if (!(s
->gr
[5] & 0x08)) {
610 ret
= GET_PLANE(s
->latch
, plane
);
613 ret
= (s
->latch
^ mask16
[s
->gr
[2]]) & mask16
[s
->gr
[7]];
622 static uint32_t vga_mem_readw(void *opaque
, target_phys_addr_t addr
)
625 #ifdef TARGET_WORDS_BIGENDIAN
626 v
= vga_mem_readb(opaque
, addr
) << 8;
627 v
|= vga_mem_readb(opaque
, addr
+ 1);
629 v
= vga_mem_readb(opaque
, addr
);
630 v
|= vga_mem_readb(opaque
, addr
+ 1) << 8;
635 static uint32_t vga_mem_readl(void *opaque
, target_phys_addr_t addr
)
638 #ifdef TARGET_WORDS_BIGENDIAN
639 v
= vga_mem_readb(opaque
, addr
) << 24;
640 v
|= vga_mem_readb(opaque
, addr
+ 1) << 16;
641 v
|= vga_mem_readb(opaque
, addr
+ 2) << 8;
642 v
|= vga_mem_readb(opaque
, addr
+ 3);
644 v
= vga_mem_readb(opaque
, addr
);
645 v
|= vga_mem_readb(opaque
, addr
+ 1) << 8;
646 v
|= vga_mem_readb(opaque
, addr
+ 2) << 16;
647 v
|= vga_mem_readb(opaque
, addr
+ 3) << 24;
652 /* called for accesses between 0xa0000 and 0xc0000 */
653 void vga_mem_writeb(void *opaque
, target_phys_addr_t addr
, uint32_t val
)
655 VGAState
*s
= opaque
;
656 int memory_map_mode
, plane
, write_mode
, b
, func_select
, mask
;
657 uint32_t write_mask
, bit_mask
, set_mask
;
660 printf("vga: [0x%x] = 0x%02x\n", addr
, val
);
662 /* convert to VGA memory offset */
663 memory_map_mode
= (s
->gr
[6] >> 2) & 3;
665 switch(memory_map_mode
) {
671 addr
+= s
->bank_offset
;
686 if (s
->sr
[4] & 0x08) {
687 /* chain 4 mode : simplest access */
690 if (s
->sr
[2] & mask
) {
691 s
->vram_ptr
[addr
] = val
;
693 printf("vga: chain4: [0x%x]\n", addr
);
695 s
->plane_updated
|= mask
; /* only used to detect font change */
696 cpu_physical_memory_set_dirty(s
->vram_offset
+ addr
);
698 } else if (s
->gr
[5] & 0x10) {
699 /* odd/even mode (aka text mode mapping) */
700 plane
= (s
->gr
[4] & 2) | (addr
& 1);
702 if (s
->sr
[2] & mask
) {
703 addr
= ((addr
& ~1) << 1) | plane
;
704 s
->vram_ptr
[addr
] = val
;
706 printf("vga: odd/even: [0x%x]\n", addr
);
708 s
->plane_updated
|= mask
; /* only used to detect font change */
709 cpu_physical_memory_set_dirty(s
->vram_offset
+ addr
);
712 /* standard VGA latched access */
713 write_mode
= s
->gr
[5] & 3;
719 val
= ((val
>> b
) | (val
<< (8 - b
))) & 0xff;
723 /* apply set/reset mask */
724 set_mask
= mask16
[s
->gr
[1]];
725 val
= (val
& ~set_mask
) | (mask16
[s
->gr
[0]] & set_mask
);
732 val
= mask16
[val
& 0x0f];
738 val
= (val
>> b
) | (val
<< (8 - b
));
740 bit_mask
= s
->gr
[8] & val
;
741 val
= mask16
[s
->gr
[0]];
745 /* apply logical operation */
746 func_select
= s
->gr
[3] >> 3;
747 switch(func_select
) {
767 bit_mask
|= bit_mask
<< 8;
768 bit_mask
|= bit_mask
<< 16;
769 val
= (val
& bit_mask
) | (s
->latch
& ~bit_mask
);
772 /* mask data according to sr[2] */
774 s
->plane_updated
|= mask
; /* only used to detect font change */
775 write_mask
= mask16
[mask
];
776 ((uint32_t *)s
->vram_ptr
)[addr
] =
777 (((uint32_t *)s
->vram_ptr
)[addr
] & ~write_mask
) |
780 printf("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n",
781 addr
* 4, write_mask
, val
);
783 cpu_physical_memory_set_dirty(s
->vram_offset
+ (addr
<< 2));
787 static void vga_mem_writew(void *opaque
, target_phys_addr_t addr
, uint32_t val
)
789 #ifdef TARGET_WORDS_BIGENDIAN
790 vga_mem_writeb(opaque
, addr
, (val
>> 8) & 0xff);
791 vga_mem_writeb(opaque
, addr
+ 1, val
& 0xff);
793 vga_mem_writeb(opaque
, addr
, val
& 0xff);
794 vga_mem_writeb(opaque
, addr
+ 1, (val
>> 8) & 0xff);
798 static void vga_mem_writel(void *opaque
, target_phys_addr_t addr
, uint32_t val
)
800 #ifdef TARGET_WORDS_BIGENDIAN
801 vga_mem_writeb(opaque
, addr
, (val
>> 24) & 0xff);
802 vga_mem_writeb(opaque
, addr
+ 1, (val
>> 16) & 0xff);
803 vga_mem_writeb(opaque
, addr
+ 2, (val
>> 8) & 0xff);
804 vga_mem_writeb(opaque
, addr
+ 3, val
& 0xff);
806 vga_mem_writeb(opaque
, addr
, val
& 0xff);
807 vga_mem_writeb(opaque
, addr
+ 1, (val
>> 8) & 0xff);
808 vga_mem_writeb(opaque
, addr
+ 2, (val
>> 16) & 0xff);
809 vga_mem_writeb(opaque
, addr
+ 3, (val
>> 24) & 0xff);
813 typedef void vga_draw_glyph8_func(uint8_t *d
, int linesize
,
814 const uint8_t *font_ptr
, int h
,
815 uint32_t fgcol
, uint32_t bgcol
);
816 typedef void vga_draw_glyph9_func(uint8_t *d
, int linesize
,
817 const uint8_t *font_ptr
, int h
,
818 uint32_t fgcol
, uint32_t bgcol
, int dup9
);
819 typedef void vga_draw_line_func(VGAState
*s1
, uint8_t *d
,
820 const uint8_t *s
, int width
);
823 #include "vga_template.h"
826 #include "vga_template.h"
830 #include "vga_template.h"
833 #include "vga_template.h"
837 #include "vga_template.h"
840 #include "vga_template.h"
844 #include "vga_template.h"
846 static unsigned int rgb_to_pixel8_dup(unsigned int r
, unsigned int g
, unsigned b
)
849 col
= rgb_to_pixel8(r
, g
, b
);
855 static unsigned int rgb_to_pixel15_dup(unsigned int r
, unsigned int g
, unsigned b
)
858 col
= rgb_to_pixel15(r
, g
, b
);
863 static unsigned int rgb_to_pixel15bgr_dup(unsigned int r
, unsigned int g
,
867 col
= rgb_to_pixel15bgr(r
, g
, b
);
872 static unsigned int rgb_to_pixel16_dup(unsigned int r
, unsigned int g
, unsigned b
)
875 col
= rgb_to_pixel16(r
, g
, b
);
880 static unsigned int rgb_to_pixel16bgr_dup(unsigned int r
, unsigned int g
,
884 col
= rgb_to_pixel16bgr(r
, g
, b
);
889 static unsigned int rgb_to_pixel32_dup(unsigned int r
, unsigned int g
, unsigned b
)
892 col
= rgb_to_pixel32(r
, g
, b
);
896 static unsigned int rgb_to_pixel32bgr_dup(unsigned int r
, unsigned int g
, unsigned b
)
899 col
= rgb_to_pixel32bgr(r
, g
, b
);
903 /* return true if the palette was modified */
904 static int update_palette16(VGAState
*s
)
907 uint32_t v
, col
, *palette
;
910 palette
= s
->last_palette
;
911 for(i
= 0; i
< 16; i
++) {
913 if (s
->ar
[0x10] & 0x80)
914 v
= ((s
->ar
[0x14] & 0xf) << 4) | (v
& 0xf);
916 v
= ((s
->ar
[0x14] & 0xc) << 4) | (v
& 0x3f);
918 col
= s
->rgb_to_pixel(c6_to_8(s
->palette
[v
]),
919 c6_to_8(s
->palette
[v
+ 1]),
920 c6_to_8(s
->palette
[v
+ 2]));
921 if (col
!= palette
[i
]) {
929 /* return true if the palette was modified */
930 static int update_palette256(VGAState
*s
)
933 uint32_t v
, col
, *palette
;
936 palette
= s
->last_palette
;
938 for(i
= 0; i
< 256; i
++) {
940 col
= s
->rgb_to_pixel(s
->palette
[v
],
944 col
= s
->rgb_to_pixel(c6_to_8(s
->palette
[v
]),
945 c6_to_8(s
->palette
[v
+ 1]),
946 c6_to_8(s
->palette
[v
+ 2]));
948 if (col
!= palette
[i
]) {
957 static void vga_get_offsets(VGAState
*s
,
958 uint32_t *pline_offset
,
959 uint32_t *pstart_addr
,
960 uint32_t *pline_compare
)
962 uint32_t start_addr
, line_offset
, line_compare
;
963 #ifdef CONFIG_BOCHS_VBE
964 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
) {
965 line_offset
= s
->vbe_line_offset
;
966 start_addr
= s
->vbe_start_addr
;
967 line_compare
= 65535;
971 /* compute line_offset in bytes */
972 line_offset
= s
->cr
[0x13];
975 /* starting address */
976 start_addr
= s
->cr
[0x0d] | (s
->cr
[0x0c] << 8);
979 line_compare
= s
->cr
[0x18] |
980 ((s
->cr
[0x07] & 0x10) << 4) |
981 ((s
->cr
[0x09] & 0x40) << 3);
983 *pline_offset
= line_offset
;
984 *pstart_addr
= start_addr
;
985 *pline_compare
= line_compare
;
988 /* update start_addr and line_offset. Return TRUE if modified */
989 static int update_basic_params(VGAState
*s
)
992 uint32_t start_addr
, line_offset
, line_compare
;
996 s
->get_offsets(s
, &line_offset
, &start_addr
, &line_compare
);
998 if (line_offset
!= s
->line_offset
||
999 start_addr
!= s
->start_addr
||
1000 line_compare
!= s
->line_compare
) {
1001 s
->line_offset
= line_offset
;
1002 s
->start_addr
= start_addr
;
1003 s
->line_compare
= line_compare
;
1011 static inline int get_depth_index(DisplayState
*s
)
1035 static vga_draw_glyph8_func
*vga_draw_glyph8_table
[NB_DEPTHS
] = {
1045 static vga_draw_glyph8_func
*vga_draw_glyph16_table
[NB_DEPTHS
] = {
1047 vga_draw_glyph16_16
,
1048 vga_draw_glyph16_16
,
1049 vga_draw_glyph16_32
,
1050 vga_draw_glyph16_32
,
1051 vga_draw_glyph16_16
,
1052 vga_draw_glyph16_16
,
1055 static vga_draw_glyph9_func
*vga_draw_glyph9_table
[NB_DEPTHS
] = {
1065 static const uint8_t cursor_glyph
[32 * 4] = {
1066 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1067 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1068 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1069 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1070 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1071 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1072 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1073 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1074 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1075 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1076 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1077 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1078 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1079 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1080 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1081 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1092 static void vga_draw_text(VGAState
*s
, int full_update
)
1094 int cx
, cy
, cheight
, cw
, ch
, cattr
, height
, width
, ch_attr
;
1095 int cx_min
, cx_max
, linesize
, x_incr
;
1096 uint32_t offset
, fgcol
, bgcol
, v
, cursor_offset
;
1097 uint8_t *d1
, *d
, *src
, *s1
, *dest
, *cursor_ptr
;
1098 const uint8_t *font_ptr
, *font_base
[2];
1099 int dup9
, line_offset
, depth_index
;
1101 uint32_t *ch_attr_ptr
;
1102 vga_draw_glyph8_func
*vga_draw_glyph8
;
1103 vga_draw_glyph9_func
*vga_draw_glyph9
;
1105 full_update
|= update_palette16(s
);
1106 palette
= s
->last_palette
;
1108 /* compute font data address (in plane 2) */
1110 offset
= (((v
>> 4) & 1) | ((v
<< 1) & 6)) * 8192 * 4 + 2;
1111 if (offset
!= s
->font_offsets
[0]) {
1112 s
->font_offsets
[0] = offset
;
1115 font_base
[0] = s
->vram_ptr
+ offset
;
1117 offset
= (((v
>> 5) & 1) | ((v
>> 1) & 6)) * 8192 * 4 + 2;
1118 font_base
[1] = s
->vram_ptr
+ offset
;
1119 if (offset
!= s
->font_offsets
[1]) {
1120 s
->font_offsets
[1] = offset
;
1123 if (s
->plane_updated
& (1 << 2)) {
1124 /* if the plane 2 was modified since the last display, it
1125 indicates the font may have been modified */
1126 s
->plane_updated
= 0;
1129 full_update
|= update_basic_params(s
);
1131 line_offset
= s
->line_offset
;
1132 s1
= s
->vram_ptr
+ (s
->start_addr
* 4);
1134 /* total width & height */
1135 cheight
= (s
->cr
[9] & 0x1f) + 1;
1137 if (!(s
->sr
[1] & 0x01))
1139 if (s
->sr
[1] & 0x08)
1140 cw
= 16; /* NOTE: no 18 pixel wide */
1141 x_incr
= cw
* ((s
->ds
->depth
+ 7) >> 3);
1142 width
= (s
->cr
[0x01] + 1);
1143 if (s
->cr
[0x06] == 100) {
1144 /* ugly hack for CGA 160x100x16 - explain me the logic */
1147 height
= s
->cr
[0x12] |
1148 ((s
->cr
[0x07] & 0x02) << 7) |
1149 ((s
->cr
[0x07] & 0x40) << 3);
1150 height
= (height
+ 1) / cheight
;
1152 if ((height
* width
) > CH_ATTR_SIZE
) {
1153 /* better than nothing: exit if transient size is too big */
1157 if (width
!= s
->last_width
|| height
!= s
->last_height
||
1158 cw
!= s
->last_cw
|| cheight
!= s
->last_ch
) {
1159 s
->last_scr_width
= width
* cw
;
1160 s
->last_scr_height
= height
* cheight
;
1161 dpy_resize(s
->ds
, s
->last_scr_width
, s
->last_scr_height
);
1162 s
->last_width
= width
;
1163 s
->last_height
= height
;
1164 s
->last_ch
= cheight
;
1168 cursor_offset
= ((s
->cr
[0x0e] << 8) | s
->cr
[0x0f]) - s
->start_addr
;
1169 if (cursor_offset
!= s
->cursor_offset
||
1170 s
->cr
[0xa] != s
->cursor_start
||
1171 s
->cr
[0xb] != s
->cursor_end
) {
1172 /* if the cursor position changed, we update the old and new
1174 if (s
->cursor_offset
< CH_ATTR_SIZE
)
1175 s
->last_ch_attr
[s
->cursor_offset
] = -1;
1176 if (cursor_offset
< CH_ATTR_SIZE
)
1177 s
->last_ch_attr
[cursor_offset
] = -1;
1178 s
->cursor_offset
= cursor_offset
;
1179 s
->cursor_start
= s
->cr
[0xa];
1180 s
->cursor_end
= s
->cr
[0xb];
1182 cursor_ptr
= s
->vram_ptr
+ (s
->start_addr
+ cursor_offset
) * 4;
1184 depth_index
= get_depth_index(s
->ds
);
1186 vga_draw_glyph8
= vga_draw_glyph16_table
[depth_index
];
1188 vga_draw_glyph8
= vga_draw_glyph8_table
[depth_index
];
1189 vga_draw_glyph9
= vga_draw_glyph9_table
[depth_index
];
1192 linesize
= s
->ds
->linesize
;
1193 ch_attr_ptr
= s
->last_ch_attr
;
1194 for(cy
= 0; cy
< height
; cy
++) {
1199 for(cx
= 0; cx
< width
; cx
++) {
1200 ch_attr
= *(uint16_t *)src
;
1201 if (full_update
|| ch_attr
!= *ch_attr_ptr
) {
1206 *ch_attr_ptr
= ch_attr
;
1207 #ifdef WORDS_BIGENDIAN
1209 cattr
= ch_attr
& 0xff;
1211 ch
= ch_attr
& 0xff;
1212 cattr
= ch_attr
>> 8;
1214 font_ptr
= font_base
[(cattr
>> 3) & 1];
1215 font_ptr
+= 32 * 4 * ch
;
1216 bgcol
= palette
[cattr
>> 4];
1217 fgcol
= palette
[cattr
& 0x0f];
1219 vga_draw_glyph8(d1
, linesize
,
1220 font_ptr
, cheight
, fgcol
, bgcol
);
1223 if (ch
>= 0xb0 && ch
<= 0xdf && (s
->ar
[0x10] & 0x04))
1225 vga_draw_glyph9(d1
, linesize
,
1226 font_ptr
, cheight
, fgcol
, bgcol
, dup9
);
1228 if (src
== cursor_ptr
&&
1229 !(s
->cr
[0x0a] & 0x20)) {
1230 int line_start
, line_last
, h
;
1231 /* draw the cursor */
1232 line_start
= s
->cr
[0x0a] & 0x1f;
1233 line_last
= s
->cr
[0x0b] & 0x1f;
1234 /* XXX: check that */
1235 if (line_last
> cheight
- 1)
1236 line_last
= cheight
- 1;
1237 if (line_last
>= line_start
&& line_start
< cheight
) {
1238 h
= line_last
- line_start
+ 1;
1239 d
= d1
+ linesize
* line_start
;
1241 vga_draw_glyph8(d
, linesize
,
1242 cursor_glyph
, h
, fgcol
, bgcol
);
1244 vga_draw_glyph9(d
, linesize
,
1245 cursor_glyph
, h
, fgcol
, bgcol
, 1);
1255 dpy_update(s
->ds
, cx_min
* cw
, cy
* cheight
,
1256 (cx_max
- cx_min
+ 1) * cw
, cheight
);
1258 dest
+= linesize
* cheight
;
1277 static vga_draw_line_func
*vga_draw_line_table
[NB_DEPTHS
* VGA_DRAW_LINE_NB
] = {
1287 vga_draw_line2d2_16
,
1288 vga_draw_line2d2_16
,
1289 vga_draw_line2d2_32
,
1290 vga_draw_line2d2_32
,
1291 vga_draw_line2d2_16
,
1292 vga_draw_line2d2_16
,
1303 vga_draw_line4d2_16
,
1304 vga_draw_line4d2_16
,
1305 vga_draw_line4d2_32
,
1306 vga_draw_line4d2_32
,
1307 vga_draw_line4d2_16
,
1308 vga_draw_line4d2_16
,
1311 vga_draw_line8d2_16
,
1312 vga_draw_line8d2_16
,
1313 vga_draw_line8d2_32
,
1314 vga_draw_line8d2_32
,
1315 vga_draw_line8d2_16
,
1316 vga_draw_line8d2_16
,
1330 vga_draw_line15_32bgr
,
1331 vga_draw_line15_15bgr
,
1332 vga_draw_line15_16bgr
,
1338 vga_draw_line16_32bgr
,
1339 vga_draw_line16_15bgr
,
1340 vga_draw_line16_16bgr
,
1346 vga_draw_line24_32bgr
,
1347 vga_draw_line24_15bgr
,
1348 vga_draw_line24_16bgr
,
1354 vga_draw_line32_32bgr
,
1355 vga_draw_line32_15bgr
,
1356 vga_draw_line32_16bgr
,
1359 typedef unsigned int rgb_to_pixel_dup_func(unsigned int r
, unsigned int g
, unsigned b
);
1361 static rgb_to_pixel_dup_func
*rgb_to_pixel_dup_table
[NB_DEPTHS
] = {
1366 rgb_to_pixel32bgr_dup
,
1367 rgb_to_pixel15bgr_dup
,
1368 rgb_to_pixel16bgr_dup
,
1371 static int vga_get_bpp(VGAState
*s
)
1374 #ifdef CONFIG_BOCHS_VBE
1375 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
) {
1376 ret
= s
->vbe_regs
[VBE_DISPI_INDEX_BPP
];
1385 static void vga_get_resolution(VGAState
*s
, int *pwidth
, int *pheight
)
1389 #ifdef CONFIG_BOCHS_VBE
1390 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
) {
1391 width
= s
->vbe_regs
[VBE_DISPI_INDEX_XRES
];
1392 height
= s
->vbe_regs
[VBE_DISPI_INDEX_YRES
];
1396 width
= (s
->cr
[0x01] + 1) * 8;
1397 height
= s
->cr
[0x12] |
1398 ((s
->cr
[0x07] & 0x02) << 7) |
1399 ((s
->cr
[0x07] & 0x40) << 3);
1400 height
= (height
+ 1);
1406 void vga_invalidate_scanlines(VGAState
*s
, int y1
, int y2
)
1409 if (y1
>= VGA_MAX_HEIGHT
)
1411 if (y2
>= VGA_MAX_HEIGHT
)
1412 y2
= VGA_MAX_HEIGHT
;
1413 for(y
= y1
; y
< y2
; y
++) {
1414 s
->invalidated_y_table
[y
>> 5] |= 1 << (y
& 0x1f);
1418 static int bitmap_get_dirty(unsigned long *bitmap
, unsigned nr
)
1420 unsigned word
= nr
/ ((sizeof bitmap
[0]) * 8);
1421 unsigned bit
= nr
% ((sizeof bitmap
[0]) * 8);
1423 //printf("%x -> %ld\n", nr, (bitmap[word] >> bit) & 1);
1424 return (bitmap
[word
] >> bit
) & 1;
1431 static void vga_draw_graphic(VGAState
*s
, int full_update
)
1433 int y1
, y
, update
, linesize
, y_start
, double_scan
, mask
;
1434 int width
, height
, shift_control
, line_offset
, bwidth
;
1435 int disp_width
, multi_scan
, multi_run
;
1437 uint32_t v
, addr1
, addr
;
1438 long page0
, page1
, page_min
, page_max
;
1439 vga_draw_line_func
*vga_draw_line
;
1441 #define VGA_BITMAP_SIZE ((8*1024*1024) / 4096 / 8 / sizeof(long))
1442 unsigned long bitmap
[VGA_BITMAP_SIZE
];
1445 if (kvm_enabled()) {
1446 r
= qemu_kvm_get_dirty_pages(s
->map_addr
, &bitmap
);
1448 fprintf(stderr
, "kvm: get_dirty_pages returned %d\n", r
);
1451 memset(bitmap
, 0xff, VGA_BITMAP_SIZE
*sizeof(long));
1452 //FIXME:Always flush full screen before log dirty ready!!
1455 full_update
|= update_basic_params(s
);
1457 s
->get_resolution(s
, &width
, &height
);
1460 shift_control
= (s
->gr
[0x05] >> 5) & 3;
1461 double_scan
= (s
->cr
[0x09] >> 7);
1462 if (shift_control
!= 1) {
1463 multi_scan
= (((s
->cr
[0x09] & 0x1f) + 1) << double_scan
) - 1;
1465 /* in CGA modes, multi_scan is ignored */
1466 /* XXX: is it correct ? */
1467 multi_scan
= double_scan
;
1469 multi_run
= multi_scan
;
1470 if (shift_control
!= s
->shift_control
||
1471 double_scan
!= s
->double_scan
) {
1473 s
->shift_control
= shift_control
;
1474 s
->double_scan
= double_scan
;
1477 if (shift_control
== 0) {
1478 full_update
|= update_palette16(s
);
1479 if (s
->sr
[0x01] & 8) {
1480 v
= VGA_DRAW_LINE4D2
;
1485 } else if (shift_control
== 1) {
1486 full_update
|= update_palette16(s
);
1487 if (s
->sr
[0x01] & 8) {
1488 v
= VGA_DRAW_LINE2D2
;
1494 switch(s
->get_bpp(s
)) {
1497 full_update
|= update_palette256(s
);
1498 v
= VGA_DRAW_LINE8D2
;
1501 full_update
|= update_palette256(s
);
1505 v
= VGA_DRAW_LINE15
;
1508 v
= VGA_DRAW_LINE16
;
1511 v
= VGA_DRAW_LINE24
;
1514 v
= VGA_DRAW_LINE32
;
1518 vga_draw_line
= vga_draw_line_table
[v
* NB_DEPTHS
+ get_depth_index(s
->ds
)];
1520 if (disp_width
!= s
->last_width
||
1521 height
!= s
->last_height
) {
1522 dpy_resize(s
->ds
, disp_width
, height
);
1523 s
->last_scr_width
= disp_width
;
1524 s
->last_scr_height
= height
;
1525 s
->last_width
= disp_width
;
1526 s
->last_height
= height
;
1529 if (s
->cursor_invalidate
)
1530 s
->cursor_invalidate(s
);
1532 line_offset
= s
->line_offset
;
1534 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",
1535 width
, height
, v
, line_offset
, s
->cr
[9], s
->cr
[0x17], s
->line_compare
, s
->sr
[0x01]);
1537 addr1
= (s
->start_addr
* 4);
1540 page_min
= 0x7fffffff;
1543 linesize
= s
->ds
->linesize
;
1545 for(y
= 0; y
< height
; y
++) {
1547 if (!(s
->cr
[0x17] & 1)) {
1549 /* CGA compatibility handling */
1550 shift
= 14 + ((s
->cr
[0x17] >> 6) & 1);
1551 addr
= (addr
& ~(1 << shift
)) | ((y1
& 1) << shift
);
1553 if (!(s
->cr
[0x17] & 2)) {
1554 addr
= (addr
& ~0x8000) | ((y1
& 2) << 14);
1556 page0
= s
->vram_offset
+ (addr
& TARGET_PAGE_MASK
);
1557 page1
= s
->vram_offset
+ ((addr
+ bwidth
- 1) & TARGET_PAGE_MASK
);
1558 update
= full_update
|
1559 cpu_physical_memory_get_dirty(page0
, VGA_DIRTY_FLAG
) |
1560 cpu_physical_memory_get_dirty(page1
, VGA_DIRTY_FLAG
);
1561 if (kvm_enabled()) {
1562 update
|= bitmap_get_dirty(bitmap
, (page0
- s
->vram_offset
) >> TARGET_PAGE_BITS
);
1563 update
|= bitmap_get_dirty(bitmap
, (page1
- s
->vram_offset
) >> TARGET_PAGE_BITS
);
1566 if ((page1
- page0
) > TARGET_PAGE_SIZE
) {
1567 /* if wide line, can use another page */
1568 update
|= cpu_physical_memory_get_dirty(page0
+ TARGET_PAGE_SIZE
,
1571 update
|= bitmap_get_dirty(bitmap
, (page0
+ TARGET_PAGE_SIZE
- s
->vram_offset
) >> TARGET_PAGE_BITS
);
1573 /* explicit invalidation for the hardware cursor */
1574 update
|= (s
->invalidated_y_table
[y
>> 5] >> (y
& 0x1f)) & 1;
1578 if (page0
< page_min
)
1580 if (page1
> page_max
)
1582 vga_draw_line(s
, d
, s
->vram_ptr
+ addr
, width
);
1583 if (s
->cursor_draw_line
)
1584 s
->cursor_draw_line(s
, d
, y
);
1587 /* flush to display */
1588 dpy_update(s
->ds
, 0, y_start
,
1589 disp_width
, y
- y_start
);
1594 mask
= (s
->cr
[0x17] & 3) ^ 3;
1595 if ((y1
& mask
) == mask
)
1596 addr1
+= line_offset
;
1598 multi_run
= multi_scan
;
1602 /* line compare acts on the displayed lines */
1603 if (y
== s
->line_compare
)
1608 /* flush to display */
1609 dpy_update(s
->ds
, 0, y_start
,
1610 disp_width
, y
- y_start
);
1612 /* reset modified pages */
1613 if (page_max
!= -1) {
1614 cpu_physical_memory_reset_dirty(page_min
, page_max
+ TARGET_PAGE_SIZE
,
1617 memset(s
->invalidated_y_table
, 0, ((height
+ 31) >> 5) * 4);
1620 static void vga_draw_blank(VGAState
*s
, int full_update
)
1627 if (s
->last_scr_width
<= 0 || s
->last_scr_height
<= 0)
1629 if (s
->ds
->depth
== 8)
1630 val
= s
->rgb_to_pixel(0, 0, 0);
1633 w
= s
->last_scr_width
* ((s
->ds
->depth
+ 7) >> 3);
1635 for(i
= 0; i
< s
->last_scr_height
; i
++) {
1637 d
+= s
->ds
->linesize
;
1639 dpy_update(s
->ds
, 0, 0,
1640 s
->last_scr_width
, s
->last_scr_height
);
1643 #define GMODE_TEXT 0
1644 #define GMODE_GRAPH 1
1645 #define GMODE_BLANK 2
1647 static void vga_update_display(void *opaque
)
1649 VGAState
*s
= (VGAState
*)opaque
;
1650 int full_update
, graphic_mode
;
1652 if (s
->ds
->depth
== 0) {
1656 rgb_to_pixel_dup_table
[get_depth_index(s
->ds
)];
1659 if (!(s
->ar_index
& 0x20)) {
1660 graphic_mode
= GMODE_BLANK
;
1662 graphic_mode
= s
->gr
[6] & 1;
1664 if (graphic_mode
!= s
->graphic_mode
) {
1665 s
->graphic_mode
= graphic_mode
;
1668 switch(graphic_mode
) {
1670 vga_draw_text(s
, full_update
);
1673 vga_draw_graphic(s
, full_update
);
1677 vga_draw_blank(s
, full_update
);
1683 /* force a full display refresh */
1684 static void vga_invalidate_display(void *opaque
)
1686 VGAState
*s
= (VGAState
*)opaque
;
1689 s
->last_height
= -1;
1692 static void vga_reset(VGAState
*s
)
1694 memset(s
, 0, sizeof(VGAState
));
1695 s
->graphic_mode
= -1; /* force full update */
1698 static CPUReadMemoryFunc
*vga_mem_read
[3] = {
1704 static CPUWriteMemoryFunc
*vga_mem_write
[3] = {
1710 static void vga_save(QEMUFile
*f
, void *opaque
)
1712 VGAState
*s
= opaque
;
1716 pci_device_save(s
->pci_dev
, f
);
1718 qemu_put_be32s(f
, &s
->latch
);
1719 qemu_put_8s(f
, &s
->sr_index
);
1720 qemu_put_buffer(f
, s
->sr
, 8);
1721 qemu_put_8s(f
, &s
->gr_index
);
1722 qemu_put_buffer(f
, s
->gr
, 16);
1723 qemu_put_8s(f
, &s
->ar_index
);
1724 qemu_put_buffer(f
, s
->ar
, 21);
1725 qemu_put_be32(f
, s
->ar_flip_flop
);
1726 qemu_put_8s(f
, &s
->cr_index
);
1727 qemu_put_buffer(f
, s
->cr
, 256);
1728 qemu_put_8s(f
, &s
->msr
);
1729 qemu_put_8s(f
, &s
->fcr
);
1730 qemu_put_byte(f
, s
->st00
);
1731 qemu_put_8s(f
, &s
->st01
);
1733 qemu_put_8s(f
, &s
->dac_state
);
1734 qemu_put_8s(f
, &s
->dac_sub_index
);
1735 qemu_put_8s(f
, &s
->dac_read_index
);
1736 qemu_put_8s(f
, &s
->dac_write_index
);
1737 qemu_put_buffer(f
, s
->dac_cache
, 3);
1738 qemu_put_buffer(f
, s
->palette
, 768);
1740 qemu_put_be32(f
, s
->bank_offset
);
1741 #ifdef CONFIG_BOCHS_VBE
1742 qemu_put_byte(f
, 1);
1743 qemu_put_be16s(f
, &s
->vbe_index
);
1744 for(i
= 0; i
< VBE_DISPI_INDEX_NB
; i
++)
1745 qemu_put_be16s(f
, &s
->vbe_regs
[i
]);
1746 qemu_put_be32s(f
, &s
->vbe_start_addr
);
1747 qemu_put_be32s(f
, &s
->vbe_line_offset
);
1748 qemu_put_be32s(f
, &s
->vbe_bank_mask
);
1750 qemu_put_byte(f
, 0);
1754 static int vga_load(QEMUFile
*f
, void *opaque
, int version_id
)
1756 VGAState
*s
= opaque
;
1762 if (s
->pci_dev
&& version_id
>= 2) {
1763 ret
= pci_device_load(s
->pci_dev
, f
);
1768 qemu_get_be32s(f
, &s
->latch
);
1769 qemu_get_8s(f
, &s
->sr_index
);
1770 qemu_get_buffer(f
, s
->sr
, 8);
1771 qemu_get_8s(f
, &s
->gr_index
);
1772 qemu_get_buffer(f
, s
->gr
, 16);
1773 qemu_get_8s(f
, &s
->ar_index
);
1774 qemu_get_buffer(f
, s
->ar
, 21);
1775 s
->ar_flip_flop
=qemu_get_be32(f
);
1776 qemu_get_8s(f
, &s
->cr_index
);
1777 qemu_get_buffer(f
, s
->cr
, 256);
1778 qemu_get_8s(f
, &s
->msr
);
1779 qemu_get_8s(f
, &s
->fcr
);
1780 qemu_get_8s(f
, &s
->st00
);
1781 qemu_get_8s(f
, &s
->st01
);
1783 qemu_get_8s(f
, &s
->dac_state
);
1784 qemu_get_8s(f
, &s
->dac_sub_index
);
1785 qemu_get_8s(f
, &s
->dac_read_index
);
1786 qemu_get_8s(f
, &s
->dac_write_index
);
1787 qemu_get_buffer(f
, s
->dac_cache
, 3);
1788 qemu_get_buffer(f
, s
->palette
, 768);
1790 s
->bank_offset
=qemu_get_be32(f
);
1791 is_vbe
= qemu_get_byte(f
);
1792 #ifdef CONFIG_BOCHS_VBE
1795 qemu_get_be16s(f
, &s
->vbe_index
);
1796 for(i
= 0; i
< VBE_DISPI_INDEX_NB
; i
++)
1797 qemu_get_be16s(f
, &s
->vbe_regs
[i
]);
1798 qemu_get_be32s(f
, &s
->vbe_start_addr
);
1799 qemu_get_be32s(f
, &s
->vbe_line_offset
);
1800 qemu_get_be32s(f
, &s
->vbe_bank_mask
);
1807 s
->graphic_mode
= -1;
1811 typedef struct PCIVGAState
{
1816 void vga_update_vram_mapping(VGAState
*s
, unsigned long vga_ram_begin
,
1817 unsigned long vga_ram_end
)
1819 void *vram_pointer
, *old_vram
;
1821 if (vga_ram_begin
== s
->map_addr
&&
1822 vga_ram_end
== s
->map_end
) {
1826 if (s
->map_addr
&& s
->map_end
)
1827 unset_vram_mapping(s
->map_addr
, s
->map_end
);
1829 vram_pointer
= set_vram_mapping(vga_ram_begin
, vga_ram_end
);
1830 if (!vram_pointer
) {
1831 fprintf(stderr
, "set_vram_mapping failed\n");
1832 s
->map_addr
= s
->map_end
= 0;
1835 old_vram
= vga_update_vram((VGAState
*)s
, vram_pointer
,
1837 if (s
->map_addr
&& s
->map_end
)
1838 munmap(old_vram
, s
->map_end
- s
->map_addr
);
1840 qemu_free(old_vram
);
1841 s
->map_addr
= vga_ram_begin
;
1842 s
->map_end
= vga_ram_end
;
1846 static void vga_map(PCIDevice
*pci_dev
, int region_num
,
1847 uint32_t addr
, uint32_t size
, int type
)
1849 PCIVGAState
*d
= (PCIVGAState
*)pci_dev
;
1850 VGAState
*s
= &d
->vga_state
;
1851 if (region_num
== PCI_ROM_SLOT
) {
1852 cpu_register_physical_memory(addr
, s
->bios_size
, s
->bios_offset
);
1854 cpu_register_physical_memory(addr
, s
->vram_size
, s
->vram_offset
);
1856 vga_update_vram_mapping(s
, addr
, addr
+ VGA_RAM_SIZE
);
1861 /* do the same job as vgabios before vgabios get ready - yeah */
1862 void vga_bios_init(VGAState
*s
)
1864 uint8_t palette_model
[192] = {
1865 0, 0, 0, 0, 0, 170, 0, 170,
1866 0, 0, 170, 170, 170, 0, 0, 170,
1867 0, 170, 170, 85, 0, 170, 170, 170,
1868 85, 85, 85, 85, 85, 255, 85, 255,
1869 85, 85, 255, 255, 255, 85, 85, 255,
1870 85, 255, 255, 255, 85, 255, 255, 255,
1871 0, 21, 0, 0, 21, 42, 0, 63,
1872 0, 0, 63, 42, 42, 21, 0, 42,
1873 21, 42, 42, 63, 0, 42, 63, 42,
1874 0, 21, 21, 0, 21, 63, 0, 63,
1875 21, 0, 63, 63, 42, 21, 21, 42,
1876 21, 63, 42, 63, 21, 42, 63, 63,
1877 21, 0, 0, 21, 0, 42, 21, 42,
1878 0, 21, 42, 42, 63, 0, 0, 63,
1879 0, 42, 63, 42, 0, 63, 42, 42,
1880 21, 0, 21, 21, 0, 63, 21, 42,
1881 21, 21, 42, 63, 63, 0, 21, 63,
1882 0, 63, 63, 42, 21, 63, 42, 63,
1883 21, 21, 0, 21, 21, 42, 21, 63,
1884 0, 21, 63, 42, 63, 21, 0, 63,
1885 21, 42, 63, 63, 0, 63, 63, 42,
1886 21, 21, 21, 21, 21, 63, 21, 63,
1887 21, 21, 63, 63, 63, 21, 21, 63,
1888 21, 63, 63, 63, 21, 63, 63, 63
1914 /* changed by out 0x03c0 */
1938 s
->ar_flip_flop
= 1;
1972 /* dac_* & palette will be initialized by os through out 0x03c8 &
1973 * out 0c03c9(1:3) */
1975 s
->dac_sub_index
= 0;
1976 s
->dac_read_index
= 0;
1977 s
->dac_write_index
= 16;
1978 s
->dac_cache
[0] = 255;
1979 s
->dac_cache
[1] = 255;
1980 s
->dac_cache
[2] = 255;
1983 memcpy(s
->palette
, palette_model
, 192);
1986 s
->graphic_mode
= -1;
1988 /* TODO: add vbe support if enabled */
1992 /* when used on xen/kvm environment, the vga_ram_base is not used */
1993 void vga_common_init(VGAState
*s
, DisplayState
*ds
, uint8_t *vga_ram_base
,
1994 unsigned long vga_ram_offset
, int vga_ram_size
)
1998 for(i
= 0;i
< 256; i
++) {
2000 for(j
= 0; j
< 8; j
++) {
2001 v
|= ((i
>> j
) & 1) << (j
* 4);
2006 for(j
= 0; j
< 4; j
++) {
2007 v
|= ((i
>> (2 * j
)) & 3) << (j
* 4);
2011 for(i
= 0; i
< 16; i
++) {
2013 for(j
= 0; j
< 4; j
++) {
2016 v
|= b
<< (2 * j
+ 1);
2024 s
->vram_ptr
= qemu_malloc(vga_ram_size
);
2026 s
->vram_ptr
= vga_ram_base
;
2027 s
->vram_offset
= vga_ram_offset
;
2028 s
->vram_size
= vga_ram_size
;
2030 s
->get_bpp
= vga_get_bpp
;
2031 s
->get_offsets
= vga_get_offsets
;
2032 s
->get_resolution
= vga_get_resolution
;
2033 s
->update
= vga_update_display
;
2034 s
->invalidate
= vga_invalidate_display
;
2035 s
->screen_dump
= vga_screen_dump
;
2041 /* used by both ISA and PCI */
2042 void vga_init(VGAState
*s
)
2046 register_savevm("vga", 0, 2, vga_save
, vga_load
, s
);
2048 register_ioport_write(0x3c0, 16, 1, vga_ioport_write
, s
);
2050 register_ioport_write(0x3b4, 2, 1, vga_ioport_write
, s
);
2051 register_ioport_write(0x3d4, 2, 1, vga_ioport_write
, s
);
2052 register_ioport_write(0x3ba, 1, 1, vga_ioport_write
, s
);
2053 register_ioport_write(0x3da, 1, 1, vga_ioport_write
, s
);
2055 register_ioport_read(0x3c0, 16, 1, vga_ioport_read
, s
);
2057 register_ioport_read(0x3b4, 2, 1, vga_ioport_read
, s
);
2058 register_ioport_read(0x3d4, 2, 1, vga_ioport_read
, s
);
2059 register_ioport_read(0x3ba, 1, 1, vga_ioport_read
, s
);
2060 register_ioport_read(0x3da, 1, 1, vga_ioport_read
, s
);
2063 #ifdef CONFIG_BOCHS_VBE
2064 s
->vbe_regs
[VBE_DISPI_INDEX_ID
] = VBE_DISPI_ID0
;
2065 s
->vbe_bank_mask
= ((s
->vram_size
>> 16) - 1);
2066 #if defined (TARGET_I386)
2067 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index
, s
);
2068 register_ioport_read(0x1cf, 1, 2, vbe_ioport_read_data
, s
);
2070 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index
, s
);
2071 register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data
, s
);
2073 /* old Bochs IO ports */
2074 register_ioport_read(0xff80, 1, 2, vbe_ioport_read_index
, s
);
2075 register_ioport_read(0xff81, 1, 2, vbe_ioport_read_data
, s
);
2077 register_ioport_write(0xff80, 1, 2, vbe_ioport_write_index
, s
);
2078 register_ioport_write(0xff81, 1, 2, vbe_ioport_write_data
, s
);
2080 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index
, s
);
2081 register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data
, s
);
2083 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index
, s
);
2084 register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data
, s
);
2086 #endif /* CONFIG_BOCHS_VBE */
2088 vga_io_memory
= cpu_register_io_memory(0, vga_mem_read
, vga_mem_write
, s
);
2089 cpu_register_physical_memory(isa_mem_base
+ 0x000a0000, 0x20000,
2093 /* Memory mapped interface */
2094 static uint32_t vga_mm_readb (void *opaque
, target_phys_addr_t addr
)
2096 VGAState
*s
= opaque
;
2098 return vga_ioport_read(s
, (addr
- s
->base_ctrl
) >> s
->it_shift
) & 0xff;
2101 static void vga_mm_writeb (void *opaque
,
2102 target_phys_addr_t addr
, uint32_t value
)
2104 VGAState
*s
= opaque
;
2106 vga_ioport_write(s
, (addr
- s
->base_ctrl
) >> s
->it_shift
, value
& 0xff);
2109 static uint32_t vga_mm_readw (void *opaque
, target_phys_addr_t addr
)
2111 VGAState
*s
= opaque
;
2113 return vga_ioport_read(s
, (addr
- s
->base_ctrl
) >> s
->it_shift
) & 0xffff;
2116 static void vga_mm_writew (void *opaque
,
2117 target_phys_addr_t addr
, uint32_t value
)
2119 VGAState
*s
= opaque
;
2121 vga_ioport_write(s
, (addr
- s
->base_ctrl
) >> s
->it_shift
, value
& 0xffff);
2124 static uint32_t vga_mm_readl (void *opaque
, target_phys_addr_t addr
)
2126 VGAState
*s
= opaque
;
2128 return vga_ioport_read(s
, (addr
- s
->base_ctrl
) >> s
->it_shift
);
2131 static void vga_mm_writel (void *opaque
,
2132 target_phys_addr_t addr
, uint32_t value
)
2134 VGAState
*s
= opaque
;
2136 vga_ioport_write(s
, (addr
- s
->base_ctrl
) >> s
->it_shift
, value
);
2139 static CPUReadMemoryFunc
*vga_mm_read_ctrl
[] = {
2145 static CPUWriteMemoryFunc
*vga_mm_write_ctrl
[] = {
2151 static void vga_mm_init(VGAState
*s
, target_phys_addr_t vram_base
,
2152 target_phys_addr_t ctrl_base
, int it_shift
)
2154 int s_ioport_ctrl
, vga_io_memory
;
2156 s
->base_ctrl
= ctrl_base
;
2157 s
->it_shift
= it_shift
;
2158 s_ioport_ctrl
= cpu_register_io_memory(0, vga_mm_read_ctrl
, vga_mm_write_ctrl
, s
);
2159 vga_io_memory
= cpu_register_io_memory(0, vga_mem_read
, vga_mem_write
, s
);
2161 register_savevm("vga", 0, 2, vga_save
, vga_load
, s
);
2163 cpu_register_physical_memory(ctrl_base
, 0x100000, s_ioport_ctrl
);
2165 cpu_register_physical_memory(vram_base
+ 0x000a0000, 0x20000, vga_io_memory
);
2168 int isa_vga_init(DisplayState
*ds
, uint8_t *vga_ram_base
,
2169 unsigned long vga_ram_offset
, int vga_ram_size
)
2173 s
= qemu_mallocz(sizeof(VGAState
));
2177 vga_common_init(s
, ds
, vga_ram_base
, vga_ram_offset
, vga_ram_size
);
2180 graphic_console_init(s
->ds
, s
->update
, s
->invalidate
, s
->screen_dump
, s
);
2182 #ifdef CONFIG_BOCHS_VBE
2183 /* XXX: use optimized standard vga accesses */
2184 cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS
,
2185 vga_ram_size
, vga_ram_offset
);
2190 int isa_vga_mm_init(DisplayState
*ds
, uint8_t *vga_ram_base
,
2191 unsigned long vga_ram_offset
, int vga_ram_size
,
2192 target_phys_addr_t vram_base
, target_phys_addr_t ctrl_base
,
2197 s
= qemu_mallocz(sizeof(VGAState
));
2201 vga_common_init(s
, ds
, vga_ram_base
, vga_ram_offset
, vga_ram_size
);
2202 vga_mm_init(s
, vram_base
, ctrl_base
, it_shift
);
2204 graphic_console_init(s
->ds
, s
->update
, s
->invalidate
, s
->screen_dump
, s
);
2206 #ifdef CONFIG_BOCHS_VBE
2207 /* XXX: use optimized standard vga accesses */
2208 cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS
,
2209 vga_ram_size
, vga_ram_offset
);
2214 int pci_vga_init(PCIBus
*bus
, DisplayState
*ds
, uint8_t *vga_ram_base
,
2215 unsigned long vga_ram_offset
, int vga_ram_size
,
2216 unsigned long vga_bios_offset
, int vga_bios_size
)
2222 d
= (PCIVGAState
*)pci_register_device(bus
, "VGA",
2223 sizeof(PCIVGAState
),
2229 vga_common_init(s
, ds
, vga_ram_base
, vga_ram_offset
, vga_ram_size
);
2232 graphic_console_init(s
->ds
, s
->update
, s
->invalidate
, s
->screen_dump
, s
);
2234 s
->pci_dev
= &d
->dev
;
2236 pci_conf
= d
->dev
.config
;
2237 pci_conf
[0x00] = 0x34; // dummy VGA (same as Bochs ID)
2238 pci_conf
[0x01] = 0x12;
2239 pci_conf
[0x02] = 0x11;
2240 pci_conf
[0x03] = 0x11;
2241 pci_conf
[0x0a] = 0x00; // VGA controller
2242 pci_conf
[0x0b] = 0x03;
2243 pci_conf
[0x0e] = 0x00; // header_type
2245 /* XXX: vga_ram_size must be a power of two */
2246 pci_register_io_region(&d
->dev
, 0, vga_ram_size
,
2247 PCI_ADDRESS_SPACE_MEM_PREFETCH
, vga_map
);
2248 if (vga_bios_size
!= 0) {
2249 unsigned int bios_total_size
;
2250 s
->bios_offset
= vga_bios_offset
;
2251 s
->bios_size
= vga_bios_size
;
2252 /* must be a power of two */
2253 bios_total_size
= 1;
2254 while (bios_total_size
< vga_bios_size
)
2255 bios_total_size
<<= 1;
2256 pci_register_io_region(&d
->dev
, PCI_ROM_SLOT
, bios_total_size
,
2257 PCI_ADDRESS_SPACE_MEM_PREFETCH
, vga_map
);
2262 void *vga_update_vram(VGAState
*s
, void *vga_ram_base
, int vga_ram_size
)
2264 uint8_t *old_pointer
;
2266 if (s
->vram_size
!= vga_ram_size
) {
2267 fprintf(stderr
, "No support to change vga_ram_size\n");
2271 if (!vga_ram_base
) {
2272 vga_ram_base
= qemu_malloc(vga_ram_size
);
2273 if (!vga_ram_base
) {
2274 fprintf(stderr
, "reallocate error\n");
2279 /* XXX lock needed? */
2280 memcpy(vga_ram_base
, s
->vram_ptr
, vga_ram_size
);
2281 old_pointer
= s
->vram_ptr
;
2282 s
->vram_ptr
= vga_ram_base
;
2287 /********************************************************/
2288 /* vga screen dump */
2290 static int vga_save_w
, vga_save_h
;
2292 static void vga_save_dpy_update(DisplayState
*s
,
2293 int x
, int y
, int w
, int h
)
2297 static void vga_save_dpy_resize(DisplayState
*s
, int w
, int h
)
2299 s
->linesize
= w
* 4;
2300 s
->data
= qemu_malloc(h
* s
->linesize
);
2305 static void vga_save_dpy_refresh(DisplayState
*s
)
2309 int ppm_save(const char *filename
, uint8_t *data
,
2310 int w
, int h
, int linesize
)
2317 f
= fopen(filename
, "wb");
2320 fprintf(f
, "P6\n%d %d\n%d\n",
2323 for(y
= 0; y
< h
; y
++) {
2325 for(x
= 0; x
< w
; x
++) {
2327 fputc((v
>> 16) & 0xff, f
);
2328 fputc((v
>> 8) & 0xff, f
);
2329 fputc((v
) & 0xff, f
);
2338 /* save the vga display in a PPM image even if no display is
2340 static void vga_screen_dump(void *opaque
, const char *filename
)
2342 VGAState
*s
= (VGAState
*)opaque
;
2343 DisplayState
*saved_ds
, ds1
, *ds
= &ds1
;
2345 /* XXX: this is a little hackish */
2346 vga_invalidate_display(s
);
2349 memset(ds
, 0, sizeof(DisplayState
));
2350 ds
->dpy_update
= vga_save_dpy_update
;
2351 ds
->dpy_resize
= vga_save_dpy_resize
;
2352 ds
->dpy_refresh
= vga_save_dpy_refresh
;
2356 s
->graphic_mode
= -1;
2357 vga_update_display(s
);
2360 ppm_save(filename
, ds
->data
, vga_save_w
, vga_save_h
,
2362 qemu_free(ds
->data
);