Merge commit 'd34e8f6e9d3a396c3327aa9807c83f9e1f4a7bd7' into upstream-merge
[qemu-kvm.git] / hw / vga.c
blob4dc26103144bdb70801e30eec5c3ff22b16737f5
1 /*
2 * QEMU VGA Emulator.
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
22 * THE SOFTWARE.
24 #include "hw.h"
25 #include "console.h"
26 #include "pc.h"
27 #include "pci.h"
28 #include "vga_int.h"
29 #include "pixel_ops.h"
30 #include "qemu-timer.h"
31 #include "xen.h"
33 //#define DEBUG_VGA
34 //#define DEBUG_VGA_MEM
35 //#define DEBUG_VGA_REG
37 //#define DEBUG_BOCHS_VBE
39 /* force some bits to zero */
40 const uint8_t sr_mask[8] = {
41 0x03,
42 0x3d,
43 0x0f,
44 0x3f,
45 0x0e,
46 0x00,
47 0x00,
48 0xff,
51 const uint8_t gr_mask[16] = {
52 0x0f, /* 0x00 */
53 0x0f, /* 0x01 */
54 0x0f, /* 0x02 */
55 0x1f, /* 0x03 */
56 0x03, /* 0x04 */
57 0x7b, /* 0x05 */
58 0x0f, /* 0x06 */
59 0x0f, /* 0x07 */
60 0xff, /* 0x08 */
61 0x00, /* 0x09 */
62 0x00, /* 0x0a */
63 0x00, /* 0x0b */
64 0x00, /* 0x0c */
65 0x00, /* 0x0d */
66 0x00, /* 0x0e */
67 0x00, /* 0x0f */
70 #define cbswap_32(__x) \
71 ((uint32_t)( \
72 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
73 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
74 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
75 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
77 #ifdef HOST_WORDS_BIGENDIAN
78 #define PAT(x) cbswap_32(x)
79 #else
80 #define PAT(x) (x)
81 #endif
83 #ifdef HOST_WORDS_BIGENDIAN
84 #define BIG 1
85 #else
86 #define BIG 0
87 #endif
89 #ifdef HOST_WORDS_BIGENDIAN
90 #define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
91 #else
92 #define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
93 #endif
95 static const uint32_t mask16[16] = {
96 PAT(0x00000000),
97 PAT(0x000000ff),
98 PAT(0x0000ff00),
99 PAT(0x0000ffff),
100 PAT(0x00ff0000),
101 PAT(0x00ff00ff),
102 PAT(0x00ffff00),
103 PAT(0x00ffffff),
104 PAT(0xff000000),
105 PAT(0xff0000ff),
106 PAT(0xff00ff00),
107 PAT(0xff00ffff),
108 PAT(0xffff0000),
109 PAT(0xffff00ff),
110 PAT(0xffffff00),
111 PAT(0xffffffff),
114 #undef PAT
116 #ifdef HOST_WORDS_BIGENDIAN
117 #define PAT(x) (x)
118 #else
119 #define PAT(x) cbswap_32(x)
120 #endif
122 static const uint32_t dmask16[16] = {
123 PAT(0x00000000),
124 PAT(0x000000ff),
125 PAT(0x0000ff00),
126 PAT(0x0000ffff),
127 PAT(0x00ff0000),
128 PAT(0x00ff00ff),
129 PAT(0x00ffff00),
130 PAT(0x00ffffff),
131 PAT(0xff000000),
132 PAT(0xff0000ff),
133 PAT(0xff00ff00),
134 PAT(0xff00ffff),
135 PAT(0xffff0000),
136 PAT(0xffff00ff),
137 PAT(0xffffff00),
138 PAT(0xffffffff),
141 static const uint32_t dmask4[4] = {
142 PAT(0x00000000),
143 PAT(0x0000ffff),
144 PAT(0xffff0000),
145 PAT(0xffffffff),
148 static uint32_t expand4[256];
149 static uint16_t expand2[256];
150 static uint8_t expand4to8[16];
152 static void vga_screen_dump(void *opaque, const char *filename);
153 static const char *screen_dump_filename;
154 static DisplayChangeListener *screen_dump_dcl;
156 static void vga_update_memory_access(VGACommonState *s)
158 MemoryRegion *region, *old_region = s->chain4_alias;
159 target_phys_addr_t base, offset, size;
161 s->chain4_alias = NULL;
163 if ((s->sr[0x02] & 0xf) == 0xf && s->sr[0x04] & 0x08) {
164 offset = 0;
165 switch ((s->gr[6] >> 2) & 3) {
166 case 0:
167 base = 0xa0000;
168 size = 0x20000;
169 break;
170 case 1:
171 base = 0xa0000;
172 size = 0x10000;
173 offset = s->bank_offset;
174 break;
175 case 2:
176 base = 0xb0000;
177 size = 0x8000;
178 break;
179 case 3:
180 default:
181 base = 0xb8000;
182 size = 0x8000;
183 break;
185 base += isa_mem_base;
186 region = g_malloc(sizeof(*region));
187 memory_region_init_alias(region, "vga.chain4", &s->vram, offset, size);
188 memory_region_add_subregion_overlap(s->legacy_address_space, base,
189 region, 2);
190 s->chain4_alias = region;
192 if (old_region) {
193 memory_region_del_subregion(s->legacy_address_space, old_region);
194 memory_region_destroy(old_region);
195 g_free(old_region);
196 s->plane_updated = 0xf;
200 static void vga_dumb_update_retrace_info(VGACommonState *s)
202 (void) s;
205 static void vga_precise_update_retrace_info(VGACommonState *s)
207 int htotal_chars;
208 int hretr_start_char;
209 int hretr_skew_chars;
210 int hretr_end_char;
212 int vtotal_lines;
213 int vretr_start_line;
214 int vretr_end_line;
216 int dots;
217 #if 0
218 int div2, sldiv2;
219 #endif
220 int clocking_mode;
221 int clock_sel;
222 const int clk_hz[] = {25175000, 28322000, 25175000, 25175000};
223 int64_t chars_per_sec;
224 struct vga_precise_retrace *r = &s->retrace_info.precise;
226 htotal_chars = s->cr[0x00] + 5;
227 hretr_start_char = s->cr[0x04];
228 hretr_skew_chars = (s->cr[0x05] >> 5) & 3;
229 hretr_end_char = s->cr[0x05] & 0x1f;
231 vtotal_lines = (s->cr[0x06]
232 | (((s->cr[0x07] & 1) | ((s->cr[0x07] >> 4) & 2)) << 8)) + 2
234 vretr_start_line = s->cr[0x10]
235 | ((((s->cr[0x07] >> 2) & 1) | ((s->cr[0x07] >> 6) & 2)) << 8)
237 vretr_end_line = s->cr[0x11] & 0xf;
241 clocking_mode = (s->sr[0x01] >> 3) & 1;
242 clock_sel = (s->msr >> 2) & 3;
243 dots = (s->msr & 1) ? 8 : 9;
245 chars_per_sec = clk_hz[clock_sel] / dots;
247 htotal_chars <<= clocking_mode;
249 r->total_chars = vtotal_lines * htotal_chars;
250 if (r->freq) {
251 r->ticks_per_char = get_ticks_per_sec() / (r->total_chars * r->freq);
252 } else {
253 r->ticks_per_char = get_ticks_per_sec() / chars_per_sec;
256 r->vstart = vretr_start_line;
257 r->vend = r->vstart + vretr_end_line + 1;
259 r->hstart = hretr_start_char + hretr_skew_chars;
260 r->hend = r->hstart + hretr_end_char + 1;
261 r->htotal = htotal_chars;
263 #if 0
264 div2 = (s->cr[0x17] >> 2) & 1;
265 sldiv2 = (s->cr[0x17] >> 3) & 1;
266 printf (
267 "hz=%f\n"
268 "htotal = %d\n"
269 "hretr_start = %d\n"
270 "hretr_skew = %d\n"
271 "hretr_end = %d\n"
272 "vtotal = %d\n"
273 "vretr_start = %d\n"
274 "vretr_end = %d\n"
275 "div2 = %d sldiv2 = %d\n"
276 "clocking_mode = %d\n"
277 "clock_sel = %d %d\n"
278 "dots = %d\n"
279 "ticks/char = %" PRId64 "\n"
280 "\n",
281 (double) get_ticks_per_sec() / (r->ticks_per_char * r->total_chars),
282 htotal_chars,
283 hretr_start_char,
284 hretr_skew_chars,
285 hretr_end_char,
286 vtotal_lines,
287 vretr_start_line,
288 vretr_end_line,
289 div2, sldiv2,
290 clocking_mode,
291 clock_sel,
292 clk_hz[clock_sel],
293 dots,
294 r->ticks_per_char
296 #endif
299 static uint8_t vga_precise_retrace(VGACommonState *s)
301 struct vga_precise_retrace *r = &s->retrace_info.precise;
302 uint8_t val = s->st01 & ~(ST01_V_RETRACE | ST01_DISP_ENABLE);
304 if (r->total_chars) {
305 int cur_line, cur_line_char, cur_char;
306 int64_t cur_tick;
308 cur_tick = qemu_get_clock_ns(vm_clock);
310 cur_char = (cur_tick / r->ticks_per_char) % r->total_chars;
311 cur_line = cur_char / r->htotal;
313 if (cur_line >= r->vstart && cur_line <= r->vend) {
314 val |= ST01_V_RETRACE | ST01_DISP_ENABLE;
315 } else {
316 cur_line_char = cur_char % r->htotal;
317 if (cur_line_char >= r->hstart && cur_line_char <= r->hend) {
318 val |= ST01_DISP_ENABLE;
322 return val;
323 } else {
324 return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
328 static uint8_t vga_dumb_retrace(VGACommonState *s)
330 return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
333 int vga_ioport_invalid(VGACommonState *s, uint32_t addr)
335 if (s->msr & MSR_COLOR_EMULATION) {
336 /* Color */
337 return (addr >= 0x3b0 && addr <= 0x3bf);
338 } else {
339 /* Monochrome */
340 return (addr >= 0x3d0 && addr <= 0x3df);
344 uint32_t vga_ioport_read(void *opaque, uint32_t addr)
346 VGACommonState *s = opaque;
347 int val, index;
349 if (vga_ioport_invalid(s, addr)) {
350 val = 0xff;
351 } else {
352 switch(addr) {
353 case 0x3c0:
354 if (s->ar_flip_flop == 0) {
355 val = s->ar_index;
356 } else {
357 val = 0;
359 break;
360 case 0x3c1:
361 index = s->ar_index & 0x1f;
362 if (index < 21)
363 val = s->ar[index];
364 else
365 val = 0;
366 break;
367 case 0x3c2:
368 val = s->st00;
369 break;
370 case 0x3c4:
371 val = s->sr_index;
372 break;
373 case 0x3c5:
374 val = s->sr[s->sr_index];
375 #ifdef DEBUG_VGA_REG
376 printf("vga: read SR%x = 0x%02x\n", s->sr_index, val);
377 #endif
378 break;
379 case 0x3c7:
380 val = s->dac_state;
381 break;
382 case 0x3c8:
383 val = s->dac_write_index;
384 break;
385 case 0x3c9:
386 val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
387 if (++s->dac_sub_index == 3) {
388 s->dac_sub_index = 0;
389 s->dac_read_index++;
391 break;
392 case 0x3ca:
393 val = s->fcr;
394 break;
395 case 0x3cc:
396 val = s->msr;
397 break;
398 case 0x3ce:
399 val = s->gr_index;
400 break;
401 case 0x3cf:
402 val = s->gr[s->gr_index];
403 #ifdef DEBUG_VGA_REG
404 printf("vga: read GR%x = 0x%02x\n", s->gr_index, val);
405 #endif
406 break;
407 case 0x3b4:
408 case 0x3d4:
409 val = s->cr_index;
410 break;
411 case 0x3b5:
412 case 0x3d5:
413 val = s->cr[s->cr_index];
414 #ifdef DEBUG_VGA_REG
415 printf("vga: read CR%x = 0x%02x\n", s->cr_index, val);
416 #endif
417 break;
418 case 0x3ba:
419 case 0x3da:
420 /* just toggle to fool polling */
421 val = s->st01 = s->retrace(s);
422 s->ar_flip_flop = 0;
423 break;
424 default:
425 val = 0x00;
426 break;
429 #if defined(DEBUG_VGA)
430 printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
431 #endif
432 return val;
435 void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
437 VGACommonState *s = opaque;
438 int index;
440 /* check port range access depending on color/monochrome mode */
441 if (vga_ioport_invalid(s, addr)) {
442 return;
444 #ifdef DEBUG_VGA
445 printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
446 #endif
448 switch(addr) {
449 case 0x3c0:
450 if (s->ar_flip_flop == 0) {
451 val &= 0x3f;
452 s->ar_index = val;
453 } else {
454 index = s->ar_index & 0x1f;
455 switch(index) {
456 case 0x00 ... 0x0f:
457 s->ar[index] = val & 0x3f;
458 break;
459 case 0x10:
460 s->ar[index] = val & ~0x10;
461 break;
462 case 0x11:
463 s->ar[index] = val;
464 break;
465 case 0x12:
466 s->ar[index] = val & ~0xc0;
467 break;
468 case 0x13:
469 s->ar[index] = val & ~0xf0;
470 break;
471 case 0x14:
472 s->ar[index] = val & ~0xf0;
473 break;
474 default:
475 break;
478 s->ar_flip_flop ^= 1;
479 break;
480 case 0x3c2:
481 s->msr = val & ~0x10;
482 s->update_retrace_info(s);
483 break;
484 case 0x3c4:
485 s->sr_index = val & 7;
486 break;
487 case 0x3c5:
488 #ifdef DEBUG_VGA_REG
489 printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
490 #endif
491 s->sr[s->sr_index] = val & sr_mask[s->sr_index];
492 if (s->sr_index == 1) s->update_retrace_info(s);
493 vga_update_memory_access(s);
494 break;
495 case 0x3c7:
496 s->dac_read_index = val;
497 s->dac_sub_index = 0;
498 s->dac_state = 3;
499 break;
500 case 0x3c8:
501 s->dac_write_index = val;
502 s->dac_sub_index = 0;
503 s->dac_state = 0;
504 break;
505 case 0x3c9:
506 s->dac_cache[s->dac_sub_index] = val;
507 if (++s->dac_sub_index == 3) {
508 memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
509 s->dac_sub_index = 0;
510 s->dac_write_index++;
512 break;
513 case 0x3ce:
514 s->gr_index = val & 0x0f;
515 break;
516 case 0x3cf:
517 #ifdef DEBUG_VGA_REG
518 printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
519 #endif
520 s->gr[s->gr_index] = val & gr_mask[s->gr_index];
521 vga_update_memory_access(s);
522 break;
523 case 0x3b4:
524 case 0x3d4:
525 s->cr_index = val;
526 break;
527 case 0x3b5:
528 case 0x3d5:
529 #ifdef DEBUG_VGA_REG
530 printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
531 #endif
532 /* handle CR0-7 protection */
533 if ((s->cr[0x11] & 0x80) && s->cr_index <= 7) {
534 /* can always write bit 4 of CR7 */
535 if (s->cr_index == 7)
536 s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
537 return;
539 s->cr[s->cr_index] = val;
541 switch(s->cr_index) {
542 case 0x00:
543 case 0x04:
544 case 0x05:
545 case 0x06:
546 case 0x07:
547 case 0x11:
548 case 0x17:
549 s->update_retrace_info(s);
550 break;
552 break;
553 case 0x3ba:
554 case 0x3da:
555 s->fcr = val & 0x10;
556 break;
560 #ifdef CONFIG_BOCHS_VBE
561 static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
563 VGACommonState *s = opaque;
564 uint32_t val;
565 val = s->vbe_index;
566 return val;
569 static uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr)
571 VGACommonState *s = opaque;
572 uint32_t val;
574 if (s->vbe_index < VBE_DISPI_INDEX_NB) {
575 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_GETCAPS) {
576 switch(s->vbe_index) {
577 /* XXX: do not hardcode ? */
578 case VBE_DISPI_INDEX_XRES:
579 val = VBE_DISPI_MAX_XRES;
580 break;
581 case VBE_DISPI_INDEX_YRES:
582 val = VBE_DISPI_MAX_YRES;
583 break;
584 case VBE_DISPI_INDEX_BPP:
585 val = VBE_DISPI_MAX_BPP;
586 break;
587 default:
588 val = s->vbe_regs[s->vbe_index];
589 break;
591 } else {
592 val = s->vbe_regs[s->vbe_index];
594 } else if (s->vbe_index == VBE_DISPI_INDEX_VIDEO_MEMORY_64K) {
595 val = s->vram_size / (64 * 1024);
596 } else {
597 val = 0;
599 #ifdef DEBUG_BOCHS_VBE
600 printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val);
601 #endif
602 return val;
605 static void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val)
607 VGACommonState *s = opaque;
608 s->vbe_index = val;
611 static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
613 VGACommonState *s = opaque;
615 if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
616 #ifdef DEBUG_BOCHS_VBE
617 printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val);
618 #endif
619 switch(s->vbe_index) {
620 case VBE_DISPI_INDEX_ID:
621 if (val == VBE_DISPI_ID0 ||
622 val == VBE_DISPI_ID1 ||
623 val == VBE_DISPI_ID2 ||
624 val == VBE_DISPI_ID3 ||
625 val == VBE_DISPI_ID4) {
626 s->vbe_regs[s->vbe_index] = val;
628 break;
629 case VBE_DISPI_INDEX_XRES:
630 if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) {
631 s->vbe_regs[s->vbe_index] = val;
633 break;
634 case VBE_DISPI_INDEX_YRES:
635 if (val <= VBE_DISPI_MAX_YRES) {
636 s->vbe_regs[s->vbe_index] = val;
638 break;
639 case VBE_DISPI_INDEX_BPP:
640 if (val == 0)
641 val = 8;
642 if (val == 4 || val == 8 || val == 15 ||
643 val == 16 || val == 24 || val == 32) {
644 s->vbe_regs[s->vbe_index] = val;
646 break;
647 case VBE_DISPI_INDEX_BANK:
648 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
649 val &= (s->vbe_bank_mask >> 2);
650 } else {
651 val &= s->vbe_bank_mask;
653 s->vbe_regs[s->vbe_index] = val;
654 s->bank_offset = (val << 16);
655 vga_update_memory_access(s);
656 break;
657 case VBE_DISPI_INDEX_ENABLE:
658 if ((val & VBE_DISPI_ENABLED) &&
659 !(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
660 int h, shift_control;
662 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] =
663 s->vbe_regs[VBE_DISPI_INDEX_XRES];
664 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] =
665 s->vbe_regs[VBE_DISPI_INDEX_YRES];
666 s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
667 s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
669 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
670 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1;
671 else
672 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] *
673 ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
674 s->vbe_start_addr = 0;
676 /* clear the screen (should be done in BIOS) */
677 if (!(val & VBE_DISPI_NOCLEARMEM)) {
678 memset(s->vram_ptr, 0,
679 s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
682 /* we initialize the VGA graphic mode (should be done
683 in BIOS) */
684 s->gr[0x06] = (s->gr[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
685 s->cr[0x17] |= 3; /* no CGA modes */
686 s->cr[0x13] = s->vbe_line_offset >> 3;
687 /* width */
688 s->cr[0x01] = (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
689 /* height (only meaningful if < 1024) */
690 h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
691 s->cr[0x12] = h;
692 s->cr[0x07] = (s->cr[0x07] & ~0x42) |
693 ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
694 /* line compare to 1023 */
695 s->cr[0x18] = 0xff;
696 s->cr[0x07] |= 0x10;
697 s->cr[0x09] |= 0x40;
699 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
700 shift_control = 0;
701 s->sr[0x01] &= ~8; /* no double line */
702 } else {
703 shift_control = 2;
704 s->sr[4] |= 0x08; /* set chain 4 mode */
705 s->sr[2] |= 0x0f; /* activate all planes */
707 s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5);
708 s->cr[0x09] &= ~0x9f; /* no double scan */
709 } else {
710 /* XXX: the bios should do that */
711 s->bank_offset = 0;
713 s->dac_8bit = (val & VBE_DISPI_8BIT_DAC) > 0;
714 s->vbe_regs[s->vbe_index] = val;
715 vga_update_memory_access(s);
716 break;
717 case VBE_DISPI_INDEX_VIRT_WIDTH:
719 int w, h, line_offset;
721 if (val < s->vbe_regs[VBE_DISPI_INDEX_XRES])
722 return;
723 w = val;
724 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
725 line_offset = w >> 1;
726 else
727 line_offset = w * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
728 h = s->vram_size / line_offset;
729 /* XXX: support weird bochs semantics ? */
730 if (h < s->vbe_regs[VBE_DISPI_INDEX_YRES])
731 return;
732 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = w;
733 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h;
734 s->vbe_line_offset = line_offset;
736 break;
737 case VBE_DISPI_INDEX_X_OFFSET:
738 case VBE_DISPI_INDEX_Y_OFFSET:
740 int x;
741 s->vbe_regs[s->vbe_index] = val;
742 s->vbe_start_addr = s->vbe_line_offset * s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET];
743 x = s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET];
744 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
745 s->vbe_start_addr += x >> 1;
746 else
747 s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
748 s->vbe_start_addr >>= 2;
750 break;
751 default:
752 break;
756 #endif
758 /* called for accesses between 0xa0000 and 0xc0000 */
759 uint32_t vga_mem_readb(VGACommonState *s, target_phys_addr_t addr)
761 int memory_map_mode, plane;
762 uint32_t ret;
764 /* convert to VGA memory offset */
765 memory_map_mode = (s->gr[6] >> 2) & 3;
766 addr &= 0x1ffff;
767 switch(memory_map_mode) {
768 case 0:
769 break;
770 case 1:
771 if (addr >= 0x10000)
772 return 0xff;
773 addr += s->bank_offset;
774 break;
775 case 2:
776 addr -= 0x10000;
777 if (addr >= 0x8000)
778 return 0xff;
779 break;
780 default:
781 case 3:
782 addr -= 0x18000;
783 if (addr >= 0x8000)
784 return 0xff;
785 break;
788 if (s->sr[4] & 0x08) {
789 /* chain 4 mode : simplest access */
790 ret = s->vram_ptr[addr];
791 } else if (s->gr[5] & 0x10) {
792 /* odd/even mode (aka text mode mapping) */
793 plane = (s->gr[4] & 2) | (addr & 1);
794 ret = s->vram_ptr[((addr & ~1) << 1) | plane];
795 } else {
796 /* standard VGA latched access */
797 s->latch = ((uint32_t *)s->vram_ptr)[addr];
799 if (!(s->gr[5] & 0x08)) {
800 /* read mode 0 */
801 plane = s->gr[4];
802 ret = GET_PLANE(s->latch, plane);
803 } else {
804 /* read mode 1 */
805 ret = (s->latch ^ mask16[s->gr[2]]) & mask16[s->gr[7]];
806 ret |= ret >> 16;
807 ret |= ret >> 8;
808 ret = (~ret) & 0xff;
811 return ret;
814 /* called for accesses between 0xa0000 and 0xc0000 */
815 void vga_mem_writeb(VGACommonState *s, target_phys_addr_t addr, uint32_t val)
817 int memory_map_mode, plane, write_mode, b, func_select, mask;
818 uint32_t write_mask, bit_mask, set_mask;
820 #ifdef DEBUG_VGA_MEM
821 printf("vga: [0x" TARGET_FMT_plx "] = 0x%02x\n", addr, val);
822 #endif
823 /* convert to VGA memory offset */
824 memory_map_mode = (s->gr[6] >> 2) & 3;
825 addr &= 0x1ffff;
826 switch(memory_map_mode) {
827 case 0:
828 break;
829 case 1:
830 if (addr >= 0x10000)
831 return;
832 addr += s->bank_offset;
833 break;
834 case 2:
835 addr -= 0x10000;
836 if (addr >= 0x8000)
837 return;
838 break;
839 default:
840 case 3:
841 addr -= 0x18000;
842 if (addr >= 0x8000)
843 return;
844 break;
847 if (s->sr[4] & 0x08) {
848 /* chain 4 mode : simplest access */
849 plane = addr & 3;
850 mask = (1 << plane);
851 if (s->sr[2] & mask) {
852 s->vram_ptr[addr] = val;
853 #ifdef DEBUG_VGA_MEM
854 printf("vga: chain4: [0x" TARGET_FMT_plx "]\n", addr);
855 #endif
856 s->plane_updated |= mask; /* only used to detect font change */
857 memory_region_set_dirty(&s->vram, addr, 1);
859 } else if (s->gr[5] & 0x10) {
860 /* odd/even mode (aka text mode mapping) */
861 plane = (s->gr[4] & 2) | (addr & 1);
862 mask = (1 << plane);
863 if (s->sr[2] & mask) {
864 addr = ((addr & ~1) << 1) | plane;
865 s->vram_ptr[addr] = val;
866 #ifdef DEBUG_VGA_MEM
867 printf("vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr);
868 #endif
869 s->plane_updated |= mask; /* only used to detect font change */
870 memory_region_set_dirty(&s->vram, addr, 1);
872 } else {
873 /* standard VGA latched access */
874 write_mode = s->gr[5] & 3;
875 switch(write_mode) {
876 default:
877 case 0:
878 /* rotate */
879 b = s->gr[3] & 7;
880 val = ((val >> b) | (val << (8 - b))) & 0xff;
881 val |= val << 8;
882 val |= val << 16;
884 /* apply set/reset mask */
885 set_mask = mask16[s->gr[1]];
886 val = (val & ~set_mask) | (mask16[s->gr[0]] & set_mask);
887 bit_mask = s->gr[8];
888 break;
889 case 1:
890 val = s->latch;
891 goto do_write;
892 case 2:
893 val = mask16[val & 0x0f];
894 bit_mask = s->gr[8];
895 break;
896 case 3:
897 /* rotate */
898 b = s->gr[3] & 7;
899 val = (val >> b) | (val << (8 - b));
901 bit_mask = s->gr[8] & val;
902 val = mask16[s->gr[0]];
903 break;
906 /* apply logical operation */
907 func_select = s->gr[3] >> 3;
908 switch(func_select) {
909 case 0:
910 default:
911 /* nothing to do */
912 break;
913 case 1:
914 /* and */
915 val &= s->latch;
916 break;
917 case 2:
918 /* or */
919 val |= s->latch;
920 break;
921 case 3:
922 /* xor */
923 val ^= s->latch;
924 break;
927 /* apply bit mask */
928 bit_mask |= bit_mask << 8;
929 bit_mask |= bit_mask << 16;
930 val = (val & bit_mask) | (s->latch & ~bit_mask);
932 do_write:
933 /* mask data according to sr[2] */
934 mask = s->sr[2];
935 s->plane_updated |= mask; /* only used to detect font change */
936 write_mask = mask16[mask];
937 ((uint32_t *)s->vram_ptr)[addr] =
938 (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
939 (val & write_mask);
940 #ifdef DEBUG_VGA_MEM
941 printf("vga: latch: [0x" TARGET_FMT_plx "] mask=0x%08x val=0x%08x\n",
942 addr * 4, write_mask, val);
943 #endif
944 memory_region_set_dirty(&s->vram, addr << 2, sizeof(uint32_t));
948 typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
949 const uint8_t *font_ptr, int h,
950 uint32_t fgcol, uint32_t bgcol);
951 typedef void vga_draw_glyph9_func(uint8_t *d, int linesize,
952 const uint8_t *font_ptr, int h,
953 uint32_t fgcol, uint32_t bgcol, int dup9);
954 typedef void vga_draw_line_func(VGACommonState *s1, uint8_t *d,
955 const uint8_t *s, int width);
957 #define DEPTH 8
958 #include "vga_template.h"
960 #define DEPTH 15
961 #include "vga_template.h"
963 #define BGR_FORMAT
964 #define DEPTH 15
965 #include "vga_template.h"
967 #define DEPTH 16
968 #include "vga_template.h"
970 #define BGR_FORMAT
971 #define DEPTH 16
972 #include "vga_template.h"
974 #define DEPTH 32
975 #include "vga_template.h"
977 #define BGR_FORMAT
978 #define DEPTH 32
979 #include "vga_template.h"
981 static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
983 unsigned int col;
984 col = rgb_to_pixel8(r, g, b);
985 col |= col << 8;
986 col |= col << 16;
987 return col;
990 static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b)
992 unsigned int col;
993 col = rgb_to_pixel15(r, g, b);
994 col |= col << 16;
995 return col;
998 static unsigned int rgb_to_pixel15bgr_dup(unsigned int r, unsigned int g,
999 unsigned int b)
1001 unsigned int col;
1002 col = rgb_to_pixel15bgr(r, g, b);
1003 col |= col << 16;
1004 return col;
1007 static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
1009 unsigned int col;
1010 col = rgb_to_pixel16(r, g, b);
1011 col |= col << 16;
1012 return col;
1015 static unsigned int rgb_to_pixel16bgr_dup(unsigned int r, unsigned int g,
1016 unsigned int b)
1018 unsigned int col;
1019 col = rgb_to_pixel16bgr(r, g, b);
1020 col |= col << 16;
1021 return col;
1024 static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
1026 unsigned int col;
1027 col = rgb_to_pixel32(r, g, b);
1028 return col;
1031 static unsigned int rgb_to_pixel32bgr_dup(unsigned int r, unsigned int g, unsigned b)
1033 unsigned int col;
1034 col = rgb_to_pixel32bgr(r, g, b);
1035 return col;
1038 /* return true if the palette was modified */
1039 static int update_palette16(VGACommonState *s)
1041 int full_update, i;
1042 uint32_t v, col, *palette;
1044 full_update = 0;
1045 palette = s->last_palette;
1046 for(i = 0; i < 16; i++) {
1047 v = s->ar[i];
1048 if (s->ar[0x10] & 0x80)
1049 v = ((s->ar[0x14] & 0xf) << 4) | (v & 0xf);
1050 else
1051 v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f);
1052 v = v * 3;
1053 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
1054 c6_to_8(s->palette[v + 1]),
1055 c6_to_8(s->palette[v + 2]));
1056 if (col != palette[i]) {
1057 full_update = 1;
1058 palette[i] = col;
1061 return full_update;
1064 /* return true if the palette was modified */
1065 static int update_palette256(VGACommonState *s)
1067 int full_update, i;
1068 uint32_t v, col, *palette;
1070 full_update = 0;
1071 palette = s->last_palette;
1072 v = 0;
1073 for(i = 0; i < 256; i++) {
1074 if (s->dac_8bit) {
1075 col = s->rgb_to_pixel(s->palette[v],
1076 s->palette[v + 1],
1077 s->palette[v + 2]);
1078 } else {
1079 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
1080 c6_to_8(s->palette[v + 1]),
1081 c6_to_8(s->palette[v + 2]));
1083 if (col != palette[i]) {
1084 full_update = 1;
1085 palette[i] = col;
1087 v += 3;
1089 return full_update;
1092 static void vga_get_offsets(VGACommonState *s,
1093 uint32_t *pline_offset,
1094 uint32_t *pstart_addr,
1095 uint32_t *pline_compare)
1097 uint32_t start_addr, line_offset, line_compare;
1098 #ifdef CONFIG_BOCHS_VBE
1099 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1100 line_offset = s->vbe_line_offset;
1101 start_addr = s->vbe_start_addr;
1102 line_compare = 65535;
1103 } else
1104 #endif
1106 /* compute line_offset in bytes */
1107 line_offset = s->cr[0x13];
1108 line_offset <<= 3;
1110 /* starting address */
1111 start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8);
1113 /* line compare */
1114 line_compare = s->cr[0x18] |
1115 ((s->cr[0x07] & 0x10) << 4) |
1116 ((s->cr[0x09] & 0x40) << 3);
1118 *pline_offset = line_offset;
1119 *pstart_addr = start_addr;
1120 *pline_compare = line_compare;
1123 /* update start_addr and line_offset. Return TRUE if modified */
1124 static int update_basic_params(VGACommonState *s)
1126 int full_update;
1127 uint32_t start_addr, line_offset, line_compare;
1129 full_update = 0;
1131 s->get_offsets(s, &line_offset, &start_addr, &line_compare);
1133 if (line_offset != s->line_offset ||
1134 start_addr != s->start_addr ||
1135 line_compare != s->line_compare) {
1136 s->line_offset = line_offset;
1137 s->start_addr = start_addr;
1138 s->line_compare = line_compare;
1139 full_update = 1;
1141 return full_update;
1144 #define NB_DEPTHS 7
1146 static inline int get_depth_index(DisplayState *s)
1148 switch(ds_get_bits_per_pixel(s)) {
1149 default:
1150 case 8:
1151 return 0;
1152 case 15:
1153 return 1;
1154 case 16:
1155 return 2;
1156 case 32:
1157 if (is_surface_bgr(s->surface))
1158 return 4;
1159 else
1160 return 3;
1164 static vga_draw_glyph8_func * const vga_draw_glyph8_table[NB_DEPTHS] = {
1165 vga_draw_glyph8_8,
1166 vga_draw_glyph8_16,
1167 vga_draw_glyph8_16,
1168 vga_draw_glyph8_32,
1169 vga_draw_glyph8_32,
1170 vga_draw_glyph8_16,
1171 vga_draw_glyph8_16,
1174 static vga_draw_glyph8_func * const vga_draw_glyph16_table[NB_DEPTHS] = {
1175 vga_draw_glyph16_8,
1176 vga_draw_glyph16_16,
1177 vga_draw_glyph16_16,
1178 vga_draw_glyph16_32,
1179 vga_draw_glyph16_32,
1180 vga_draw_glyph16_16,
1181 vga_draw_glyph16_16,
1184 static vga_draw_glyph9_func * const vga_draw_glyph9_table[NB_DEPTHS] = {
1185 vga_draw_glyph9_8,
1186 vga_draw_glyph9_16,
1187 vga_draw_glyph9_16,
1188 vga_draw_glyph9_32,
1189 vga_draw_glyph9_32,
1190 vga_draw_glyph9_16,
1191 vga_draw_glyph9_16,
1194 static const uint8_t cursor_glyph[32 * 4] = {
1195 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1196 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1197 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1198 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1199 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1200 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1201 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1202 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1203 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1204 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1205 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1206 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1207 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1208 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1209 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1210 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1213 static void vga_get_text_resolution(VGACommonState *s, int *pwidth, int *pheight,
1214 int *pcwidth, int *pcheight)
1216 int width, cwidth, height, cheight;
1218 /* total width & height */
1219 cheight = (s->cr[9] & 0x1f) + 1;
1220 cwidth = 8;
1221 if (!(s->sr[1] & 0x01))
1222 cwidth = 9;
1223 if (s->sr[1] & 0x08)
1224 cwidth = 16; /* NOTE: no 18 pixel wide */
1225 width = (s->cr[0x01] + 1);
1226 if (s->cr[0x06] == 100) {
1227 /* ugly hack for CGA 160x100x16 - explain me the logic */
1228 height = 100;
1229 } else {
1230 height = s->cr[0x12] |
1231 ((s->cr[0x07] & 0x02) << 7) |
1232 ((s->cr[0x07] & 0x40) << 3);
1233 height = (height + 1) / cheight;
1236 *pwidth = width;
1237 *pheight = height;
1238 *pcwidth = cwidth;
1239 *pcheight = cheight;
1242 typedef unsigned int rgb_to_pixel_dup_func(unsigned int r, unsigned int g, unsigned b);
1244 static rgb_to_pixel_dup_func * const rgb_to_pixel_dup_table[NB_DEPTHS] = {
1245 rgb_to_pixel8_dup,
1246 rgb_to_pixel15_dup,
1247 rgb_to_pixel16_dup,
1248 rgb_to_pixel32_dup,
1249 rgb_to_pixel32bgr_dup,
1250 rgb_to_pixel15bgr_dup,
1251 rgb_to_pixel16bgr_dup,
1255 * Text mode update
1256 * Missing:
1257 * - double scan
1258 * - double width
1259 * - underline
1260 * - flashing
1262 static void vga_draw_text(VGACommonState *s, int full_update)
1264 int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
1265 int cx_min, cx_max, linesize, x_incr, line, line1;
1266 uint32_t offset, fgcol, bgcol, v, cursor_offset;
1267 uint8_t *d1, *d, *src, *dest, *cursor_ptr;
1268 const uint8_t *font_ptr, *font_base[2];
1269 int dup9, line_offset, depth_index;
1270 uint32_t *palette;
1271 uint32_t *ch_attr_ptr;
1272 vga_draw_glyph8_func *vga_draw_glyph8;
1273 vga_draw_glyph9_func *vga_draw_glyph9;
1275 /* compute font data address (in plane 2) */
1276 v = s->sr[3];
1277 offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
1278 if (offset != s->font_offsets[0]) {
1279 s->font_offsets[0] = offset;
1280 full_update = 1;
1282 font_base[0] = s->vram_ptr + offset;
1284 offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
1285 font_base[1] = s->vram_ptr + offset;
1286 if (offset != s->font_offsets[1]) {
1287 s->font_offsets[1] = offset;
1288 full_update = 1;
1290 if (s->plane_updated & (1 << 2) || s->chain4_alias) {
1291 /* if the plane 2 was modified since the last display, it
1292 indicates the font may have been modified */
1293 s->plane_updated = 0;
1294 full_update = 1;
1296 full_update |= update_basic_params(s);
1298 line_offset = s->line_offset;
1300 vga_get_text_resolution(s, &width, &height, &cw, &cheight);
1301 if ((height * width) > CH_ATTR_SIZE) {
1302 /* better than nothing: exit if transient size is too big */
1303 return;
1306 if (width != s->last_width || height != s->last_height ||
1307 cw != s->last_cw || cheight != s->last_ch || s->last_depth) {
1308 s->last_scr_width = width * cw;
1309 s->last_scr_height = height * cheight;
1310 qemu_console_resize(s->ds, s->last_scr_width, s->last_scr_height);
1311 s->last_depth = 0;
1312 s->last_width = width;
1313 s->last_height = height;
1314 s->last_ch = cheight;
1315 s->last_cw = cw;
1316 full_update = 1;
1318 s->rgb_to_pixel =
1319 rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1320 full_update |= update_palette16(s);
1321 palette = s->last_palette;
1322 x_incr = cw * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
1324 cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
1325 if (cursor_offset != s->cursor_offset ||
1326 s->cr[0xa] != s->cursor_start ||
1327 s->cr[0xb] != s->cursor_end) {
1328 /* if the cursor position changed, we update the old and new
1329 chars */
1330 if (s->cursor_offset < CH_ATTR_SIZE)
1331 s->last_ch_attr[s->cursor_offset] = -1;
1332 if (cursor_offset < CH_ATTR_SIZE)
1333 s->last_ch_attr[cursor_offset] = -1;
1334 s->cursor_offset = cursor_offset;
1335 s->cursor_start = s->cr[0xa];
1336 s->cursor_end = s->cr[0xb];
1338 cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
1340 depth_index = get_depth_index(s->ds);
1341 if (cw == 16)
1342 vga_draw_glyph8 = vga_draw_glyph16_table[depth_index];
1343 else
1344 vga_draw_glyph8 = vga_draw_glyph8_table[depth_index];
1345 vga_draw_glyph9 = vga_draw_glyph9_table[depth_index];
1347 dest = ds_get_data(s->ds);
1348 linesize = ds_get_linesize(s->ds);
1349 ch_attr_ptr = s->last_ch_attr;
1350 line = 0;
1351 offset = s->start_addr * 4;
1352 for(cy = 0; cy < height; cy++) {
1353 d1 = dest;
1354 src = s->vram_ptr + offset;
1355 cx_min = width;
1356 cx_max = -1;
1357 for(cx = 0; cx < width; cx++) {
1358 ch_attr = *(uint16_t *)src;
1359 if (full_update || ch_attr != *ch_attr_ptr) {
1360 if (cx < cx_min)
1361 cx_min = cx;
1362 if (cx > cx_max)
1363 cx_max = cx;
1364 *ch_attr_ptr = ch_attr;
1365 #ifdef HOST_WORDS_BIGENDIAN
1366 ch = ch_attr >> 8;
1367 cattr = ch_attr & 0xff;
1368 #else
1369 ch = ch_attr & 0xff;
1370 cattr = ch_attr >> 8;
1371 #endif
1372 font_ptr = font_base[(cattr >> 3) & 1];
1373 font_ptr += 32 * 4 * ch;
1374 bgcol = palette[cattr >> 4];
1375 fgcol = palette[cattr & 0x0f];
1376 if (cw != 9) {
1377 vga_draw_glyph8(d1, linesize,
1378 font_ptr, cheight, fgcol, bgcol);
1379 } else {
1380 dup9 = 0;
1381 if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))
1382 dup9 = 1;
1383 vga_draw_glyph9(d1, linesize,
1384 font_ptr, cheight, fgcol, bgcol, dup9);
1386 if (src == cursor_ptr &&
1387 !(s->cr[0x0a] & 0x20)) {
1388 int line_start, line_last, h;
1389 /* draw the cursor */
1390 line_start = s->cr[0x0a] & 0x1f;
1391 line_last = s->cr[0x0b] & 0x1f;
1392 /* XXX: check that */
1393 if (line_last > cheight - 1)
1394 line_last = cheight - 1;
1395 if (line_last >= line_start && line_start < cheight) {
1396 h = line_last - line_start + 1;
1397 d = d1 + linesize * line_start;
1398 if (cw != 9) {
1399 vga_draw_glyph8(d, linesize,
1400 cursor_glyph, h, fgcol, bgcol);
1401 } else {
1402 vga_draw_glyph9(d, linesize,
1403 cursor_glyph, h, fgcol, bgcol, 1);
1408 d1 += x_incr;
1409 src += 4;
1410 ch_attr_ptr++;
1412 if (cx_max != -1) {
1413 dpy_update(s->ds, cx_min * cw, cy * cheight,
1414 (cx_max - cx_min + 1) * cw, cheight);
1416 dest += linesize * cheight;
1417 line1 = line + cheight;
1418 offset += line_offset;
1419 if (line < s->line_compare && line1 >= s->line_compare) {
1420 offset = 0;
1422 line = line1;
1426 enum {
1427 VGA_DRAW_LINE2,
1428 VGA_DRAW_LINE2D2,
1429 VGA_DRAW_LINE4,
1430 VGA_DRAW_LINE4D2,
1431 VGA_DRAW_LINE8D2,
1432 VGA_DRAW_LINE8,
1433 VGA_DRAW_LINE15,
1434 VGA_DRAW_LINE16,
1435 VGA_DRAW_LINE24,
1436 VGA_DRAW_LINE32,
1437 VGA_DRAW_LINE_NB,
1440 static vga_draw_line_func * const vga_draw_line_table[NB_DEPTHS * VGA_DRAW_LINE_NB] = {
1441 vga_draw_line2_8,
1442 vga_draw_line2_16,
1443 vga_draw_line2_16,
1444 vga_draw_line2_32,
1445 vga_draw_line2_32,
1446 vga_draw_line2_16,
1447 vga_draw_line2_16,
1449 vga_draw_line2d2_8,
1450 vga_draw_line2d2_16,
1451 vga_draw_line2d2_16,
1452 vga_draw_line2d2_32,
1453 vga_draw_line2d2_32,
1454 vga_draw_line2d2_16,
1455 vga_draw_line2d2_16,
1457 vga_draw_line4_8,
1458 vga_draw_line4_16,
1459 vga_draw_line4_16,
1460 vga_draw_line4_32,
1461 vga_draw_line4_32,
1462 vga_draw_line4_16,
1463 vga_draw_line4_16,
1465 vga_draw_line4d2_8,
1466 vga_draw_line4d2_16,
1467 vga_draw_line4d2_16,
1468 vga_draw_line4d2_32,
1469 vga_draw_line4d2_32,
1470 vga_draw_line4d2_16,
1471 vga_draw_line4d2_16,
1473 vga_draw_line8d2_8,
1474 vga_draw_line8d2_16,
1475 vga_draw_line8d2_16,
1476 vga_draw_line8d2_32,
1477 vga_draw_line8d2_32,
1478 vga_draw_line8d2_16,
1479 vga_draw_line8d2_16,
1481 vga_draw_line8_8,
1482 vga_draw_line8_16,
1483 vga_draw_line8_16,
1484 vga_draw_line8_32,
1485 vga_draw_line8_32,
1486 vga_draw_line8_16,
1487 vga_draw_line8_16,
1489 vga_draw_line15_8,
1490 vga_draw_line15_15,
1491 vga_draw_line15_16,
1492 vga_draw_line15_32,
1493 vga_draw_line15_32bgr,
1494 vga_draw_line15_15bgr,
1495 vga_draw_line15_16bgr,
1497 vga_draw_line16_8,
1498 vga_draw_line16_15,
1499 vga_draw_line16_16,
1500 vga_draw_line16_32,
1501 vga_draw_line16_32bgr,
1502 vga_draw_line16_15bgr,
1503 vga_draw_line16_16bgr,
1505 vga_draw_line24_8,
1506 vga_draw_line24_15,
1507 vga_draw_line24_16,
1508 vga_draw_line24_32,
1509 vga_draw_line24_32bgr,
1510 vga_draw_line24_15bgr,
1511 vga_draw_line24_16bgr,
1513 vga_draw_line32_8,
1514 vga_draw_line32_15,
1515 vga_draw_line32_16,
1516 vga_draw_line32_32,
1517 vga_draw_line32_32bgr,
1518 vga_draw_line32_15bgr,
1519 vga_draw_line32_16bgr,
1522 static int vga_get_bpp(VGACommonState *s)
1524 int ret;
1525 #ifdef CONFIG_BOCHS_VBE
1526 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1527 ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
1528 } else
1529 #endif
1531 ret = 0;
1533 return ret;
1536 static void vga_get_resolution(VGACommonState *s, int *pwidth, int *pheight)
1538 int width, height;
1540 #ifdef CONFIG_BOCHS_VBE
1541 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1542 width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
1543 height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
1544 } else
1545 #endif
1547 width = (s->cr[0x01] + 1) * 8;
1548 height = s->cr[0x12] |
1549 ((s->cr[0x07] & 0x02) << 7) |
1550 ((s->cr[0x07] & 0x40) << 3);
1551 height = (height + 1);
1553 *pwidth = width;
1554 *pheight = height;
1557 void vga_invalidate_scanlines(VGACommonState *s, int y1, int y2)
1559 int y;
1560 if (y1 >= VGA_MAX_HEIGHT)
1561 return;
1562 if (y2 >= VGA_MAX_HEIGHT)
1563 y2 = VGA_MAX_HEIGHT;
1564 for(y = y1; y < y2; y++) {
1565 s->invalidated_y_table[y >> 5] |= 1 << (y & 0x1f);
1569 static void vga_sync_dirty_bitmap(VGACommonState *s)
1571 memory_region_sync_dirty_bitmap(&s->vram);
1574 void vga_dirty_log_start(VGACommonState *s)
1576 memory_region_set_log(&s->vram, true, DIRTY_MEMORY_VGA);
1579 void vga_dirty_log_stop(VGACommonState *s)
1581 memory_region_set_log(&s->vram, false, DIRTY_MEMORY_VGA);
1585 * graphic modes
1587 static void vga_draw_graphic(VGACommonState *s, int full_update)
1589 int y1, y, update, linesize, y_start, double_scan, mask, depth;
1590 int width, height, shift_control, line_offset, bwidth, bits;
1591 ram_addr_t page0, page1, page_min, page_max;
1592 int disp_width, multi_scan, multi_run;
1593 uint8_t *d;
1594 uint32_t v, addr1, addr;
1595 vga_draw_line_func *vga_draw_line;
1597 full_update |= update_basic_params(s);
1599 if (!full_update)
1600 vga_sync_dirty_bitmap(s);
1602 s->get_resolution(s, &width, &height);
1603 disp_width = width;
1605 shift_control = (s->gr[0x05] >> 5) & 3;
1606 double_scan = (s->cr[0x09] >> 7);
1607 if (shift_control != 1) {
1608 multi_scan = (((s->cr[0x09] & 0x1f) + 1) << double_scan) - 1;
1609 } else {
1610 /* in CGA modes, multi_scan is ignored */
1611 /* XXX: is it correct ? */
1612 multi_scan = double_scan;
1614 multi_run = multi_scan;
1615 if (shift_control != s->shift_control ||
1616 double_scan != s->double_scan) {
1617 full_update = 1;
1618 s->shift_control = shift_control;
1619 s->double_scan = double_scan;
1622 if (shift_control == 0) {
1623 if (s->sr[0x01] & 8) {
1624 disp_width <<= 1;
1626 } else if (shift_control == 1) {
1627 if (s->sr[0x01] & 8) {
1628 disp_width <<= 1;
1632 depth = s->get_bpp(s);
1633 if (s->line_offset != s->last_line_offset ||
1634 disp_width != s->last_width ||
1635 height != s->last_height ||
1636 s->last_depth != depth) {
1637 #if defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
1638 if (depth == 16 || depth == 32) {
1639 #else
1640 if (depth == 32) {
1641 #endif
1642 qemu_free_displaysurface(s->ds);
1643 s->ds->surface = qemu_create_displaysurface_from(disp_width, height, depth,
1644 s->line_offset,
1645 s->vram_ptr + (s->start_addr * 4));
1646 #if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
1647 s->ds->surface->pf = qemu_different_endianness_pixelformat(depth);
1648 #endif
1649 dpy_resize(s->ds);
1650 } else {
1651 qemu_console_resize(s->ds, disp_width, height);
1653 s->last_scr_width = disp_width;
1654 s->last_scr_height = height;
1655 s->last_width = disp_width;
1656 s->last_height = height;
1657 s->last_line_offset = s->line_offset;
1658 s->last_depth = depth;
1659 full_update = 1;
1660 } else if (is_buffer_shared(s->ds->surface) &&
1661 (full_update || s->ds->surface->data != s->vram_ptr + (s->start_addr * 4))) {
1662 s->ds->surface->data = s->vram_ptr + (s->start_addr * 4);
1663 dpy_setdata(s->ds);
1666 s->rgb_to_pixel =
1667 rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1669 if (shift_control == 0) {
1670 full_update |= update_palette16(s);
1671 if (s->sr[0x01] & 8) {
1672 v = VGA_DRAW_LINE4D2;
1673 } else {
1674 v = VGA_DRAW_LINE4;
1676 bits = 4;
1677 } else if (shift_control == 1) {
1678 full_update |= update_palette16(s);
1679 if (s->sr[0x01] & 8) {
1680 v = VGA_DRAW_LINE2D2;
1681 } else {
1682 v = VGA_DRAW_LINE2;
1684 bits = 4;
1685 } else {
1686 switch(s->get_bpp(s)) {
1687 default:
1688 case 0:
1689 full_update |= update_palette256(s);
1690 v = VGA_DRAW_LINE8D2;
1691 bits = 4;
1692 break;
1693 case 8:
1694 full_update |= update_palette256(s);
1695 v = VGA_DRAW_LINE8;
1696 bits = 8;
1697 break;
1698 case 15:
1699 v = VGA_DRAW_LINE15;
1700 bits = 16;
1701 break;
1702 case 16:
1703 v = VGA_DRAW_LINE16;
1704 bits = 16;
1705 break;
1706 case 24:
1707 v = VGA_DRAW_LINE24;
1708 bits = 24;
1709 break;
1710 case 32:
1711 v = VGA_DRAW_LINE32;
1712 bits = 32;
1713 break;
1716 vga_draw_line = vga_draw_line_table[v * NB_DEPTHS + get_depth_index(s->ds)];
1718 if (!is_buffer_shared(s->ds->surface) && s->cursor_invalidate)
1719 s->cursor_invalidate(s);
1721 line_offset = s->line_offset;
1722 #if 0
1723 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",
1724 width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]);
1725 #endif
1726 addr1 = (s->start_addr * 4);
1727 bwidth = (width * bits + 7) / 8;
1728 y_start = -1;
1729 page_min = -1;
1730 page_max = 0;
1731 d = ds_get_data(s->ds);
1732 linesize = ds_get_linesize(s->ds);
1733 y1 = 0;
1734 for(y = 0; y < height; y++) {
1735 addr = addr1;
1736 if (!(s->cr[0x17] & 1)) {
1737 int shift;
1738 /* CGA compatibility handling */
1739 shift = 14 + ((s->cr[0x17] >> 6) & 1);
1740 addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
1742 if (!(s->cr[0x17] & 2)) {
1743 addr = (addr & ~0x8000) | ((y1 & 2) << 14);
1745 page0 = addr & TARGET_PAGE_MASK;
1746 page1 = (addr + bwidth - 1) & TARGET_PAGE_MASK;
1747 update = full_update |
1748 memory_region_get_dirty(&s->vram, page0, DIRTY_MEMORY_VGA) |
1749 memory_region_get_dirty(&s->vram, page1, DIRTY_MEMORY_VGA);
1750 if ((page1 - page0) > TARGET_PAGE_SIZE) {
1751 /* if wide line, can use another page */
1752 update |= memory_region_get_dirty(&s->vram,
1753 page0 + TARGET_PAGE_SIZE,
1754 DIRTY_MEMORY_VGA);
1756 /* explicit invalidation for the hardware cursor */
1757 update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
1758 if (update) {
1759 if (y_start < 0)
1760 y_start = y;
1761 if (page0 < page_min)
1762 page_min = page0;
1763 if (page1 > page_max)
1764 page_max = page1;
1765 if (!(is_buffer_shared(s->ds->surface))) {
1766 vga_draw_line(s, d, s->vram_ptr + addr, width);
1767 if (s->cursor_draw_line)
1768 s->cursor_draw_line(s, d, y);
1770 } else {
1771 if (y_start >= 0) {
1772 /* flush to display */
1773 dpy_update(s->ds, 0, y_start,
1774 disp_width, y - y_start);
1775 y_start = -1;
1778 if (!multi_run) {
1779 mask = (s->cr[0x17] & 3) ^ 3;
1780 if ((y1 & mask) == mask)
1781 addr1 += line_offset;
1782 y1++;
1783 multi_run = multi_scan;
1784 } else {
1785 multi_run--;
1787 /* line compare acts on the displayed lines */
1788 if (y == s->line_compare)
1789 addr1 = 0;
1790 d += linesize;
1792 if (y_start >= 0) {
1793 /* flush to display */
1794 dpy_update(s->ds, 0, y_start,
1795 disp_width, y - y_start);
1797 /* reset modified pages */
1798 if (page_max >= page_min) {
1799 memory_region_reset_dirty(&s->vram,
1800 page_min,
1801 page_max + TARGET_PAGE_SIZE - page_min,
1802 DIRTY_MEMORY_VGA);
1804 memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
1807 static void vga_draw_blank(VGACommonState *s, int full_update)
1809 int i, w, val;
1810 uint8_t *d;
1812 if (!full_update)
1813 return;
1814 if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
1815 return;
1817 s->rgb_to_pixel =
1818 rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1819 if (ds_get_bits_per_pixel(s->ds) == 8)
1820 val = s->rgb_to_pixel(0, 0, 0);
1821 else
1822 val = 0;
1823 w = s->last_scr_width * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
1824 d = ds_get_data(s->ds);
1825 for(i = 0; i < s->last_scr_height; i++) {
1826 memset(d, val, w);
1827 d += ds_get_linesize(s->ds);
1829 dpy_update(s->ds, 0, 0,
1830 s->last_scr_width, s->last_scr_height);
1833 #define GMODE_TEXT 0
1834 #define GMODE_GRAPH 1
1835 #define GMODE_BLANK 2
1837 static void vga_update_display(void *opaque)
1839 VGACommonState *s = opaque;
1840 int full_update, graphic_mode;
1842 qemu_flush_coalesced_mmio_buffer();
1844 if (ds_get_bits_per_pixel(s->ds) == 0) {
1845 /* nothing to do */
1846 } else {
1847 full_update = 0;
1848 if (!(s->ar_index & 0x20)) {
1849 graphic_mode = GMODE_BLANK;
1850 } else {
1851 graphic_mode = s->gr[6] & 1;
1853 if (graphic_mode != s->graphic_mode) {
1854 s->graphic_mode = graphic_mode;
1855 full_update = 1;
1857 switch(graphic_mode) {
1858 case GMODE_TEXT:
1859 vga_draw_text(s, full_update);
1860 break;
1861 case GMODE_GRAPH:
1862 vga_draw_graphic(s, full_update);
1863 break;
1864 case GMODE_BLANK:
1865 default:
1866 vga_draw_blank(s, full_update);
1867 break;
1872 /* force a full display refresh */
1873 static void vga_invalidate_display(void *opaque)
1875 VGACommonState *s = opaque;
1877 s->last_width = -1;
1878 s->last_height = -1;
1881 void vga_common_reset(VGACommonState *s)
1883 s->sr_index = 0;
1884 memset(s->sr, '\0', sizeof(s->sr));
1885 s->gr_index = 0;
1886 memset(s->gr, '\0', sizeof(s->gr));
1887 s->ar_index = 0;
1888 memset(s->ar, '\0', sizeof(s->ar));
1889 s->ar_flip_flop = 0;
1890 s->cr_index = 0;
1891 memset(s->cr, '\0', sizeof(s->cr));
1892 s->msr = 0;
1893 s->fcr = 0;
1894 s->st00 = 0;
1895 s->st01 = 0;
1896 s->dac_state = 0;
1897 s->dac_sub_index = 0;
1898 s->dac_read_index = 0;
1899 s->dac_write_index = 0;
1900 memset(s->dac_cache, '\0', sizeof(s->dac_cache));
1901 s->dac_8bit = 0;
1902 memset(s->palette, '\0', sizeof(s->palette));
1903 s->bank_offset = 0;
1904 #ifdef CONFIG_BOCHS_VBE
1905 s->vbe_index = 0;
1906 memset(s->vbe_regs, '\0', sizeof(s->vbe_regs));
1907 s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID5;
1908 s->vbe_start_addr = 0;
1909 s->vbe_line_offset = 0;
1910 s->vbe_bank_mask = (s->vram_size >> 16) - 1;
1911 #endif
1912 memset(s->font_offsets, '\0', sizeof(s->font_offsets));
1913 s->graphic_mode = -1; /* force full update */
1914 s->shift_control = 0;
1915 s->double_scan = 0;
1916 s->line_offset = 0;
1917 s->line_compare = 0;
1918 s->start_addr = 0;
1919 s->plane_updated = 0;
1920 s->last_cw = 0;
1921 s->last_ch = 0;
1922 s->last_width = 0;
1923 s->last_height = 0;
1924 s->last_scr_width = 0;
1925 s->last_scr_height = 0;
1926 s->cursor_start = 0;
1927 s->cursor_end = 0;
1928 s->cursor_offset = 0;
1929 memset(s->invalidated_y_table, '\0', sizeof(s->invalidated_y_table));
1930 memset(s->last_palette, '\0', sizeof(s->last_palette));
1931 memset(s->last_ch_attr, '\0', sizeof(s->last_ch_attr));
1932 switch (vga_retrace_method) {
1933 case VGA_RETRACE_DUMB:
1934 break;
1935 case VGA_RETRACE_PRECISE:
1936 memset(&s->retrace_info, 0, sizeof (s->retrace_info));
1937 break;
1939 vga_update_memory_access(s);
1942 static void vga_reset(void *opaque)
1944 VGACommonState *s = opaque;
1945 vga_common_reset(s);
1948 #define TEXTMODE_X(x) ((x) % width)
1949 #define TEXTMODE_Y(x) ((x) / width)
1950 #define VMEM2CHTYPE(v) ((v & 0xff0007ff) | \
1951 ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1))
1952 /* relay text rendering to the display driver
1953 * instead of doing a full vga_update_display() */
1954 static void vga_update_text(void *opaque, console_ch_t *chardata)
1956 VGACommonState *s = opaque;
1957 int graphic_mode, i, cursor_offset, cursor_visible;
1958 int cw, cheight, width, height, size, c_min, c_max;
1959 uint32_t *src;
1960 console_ch_t *dst, val;
1961 char msg_buffer[80];
1962 int full_update = 0;
1964 qemu_flush_coalesced_mmio_buffer();
1966 if (!(s->ar_index & 0x20)) {
1967 graphic_mode = GMODE_BLANK;
1968 } else {
1969 graphic_mode = s->gr[6] & 1;
1971 if (graphic_mode != s->graphic_mode) {
1972 s->graphic_mode = graphic_mode;
1973 full_update = 1;
1975 if (s->last_width == -1) {
1976 s->last_width = 0;
1977 full_update = 1;
1980 switch (graphic_mode) {
1981 case GMODE_TEXT:
1982 /* TODO: update palette */
1983 full_update |= update_basic_params(s);
1985 /* total width & height */
1986 cheight = (s->cr[9] & 0x1f) + 1;
1987 cw = 8;
1988 if (!(s->sr[1] & 0x01))
1989 cw = 9;
1990 if (s->sr[1] & 0x08)
1991 cw = 16; /* NOTE: no 18 pixel wide */
1992 width = (s->cr[0x01] + 1);
1993 if (s->cr[0x06] == 100) {
1994 /* ugly hack for CGA 160x100x16 - explain me the logic */
1995 height = 100;
1996 } else {
1997 height = s->cr[0x12] |
1998 ((s->cr[0x07] & 0x02) << 7) |
1999 ((s->cr[0x07] & 0x40) << 3);
2000 height = (height + 1) / cheight;
2003 size = (height * width);
2004 if (size > CH_ATTR_SIZE) {
2005 if (!full_update)
2006 return;
2008 snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Text mode",
2009 width, height);
2010 break;
2013 if (width != s->last_width || height != s->last_height ||
2014 cw != s->last_cw || cheight != s->last_ch) {
2015 s->last_scr_width = width * cw;
2016 s->last_scr_height = height * cheight;
2017 s->ds->surface->width = width;
2018 s->ds->surface->height = height;
2019 dpy_resize(s->ds);
2020 s->last_width = width;
2021 s->last_height = height;
2022 s->last_ch = cheight;
2023 s->last_cw = cw;
2024 full_update = 1;
2027 /* Update "hardware" cursor */
2028 cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
2029 if (cursor_offset != s->cursor_offset ||
2030 s->cr[0xa] != s->cursor_start ||
2031 s->cr[0xb] != s->cursor_end || full_update) {
2032 cursor_visible = !(s->cr[0xa] & 0x20);
2033 if (cursor_visible && cursor_offset < size && cursor_offset >= 0)
2034 dpy_cursor(s->ds,
2035 TEXTMODE_X(cursor_offset),
2036 TEXTMODE_Y(cursor_offset));
2037 else
2038 dpy_cursor(s->ds, -1, -1);
2039 s->cursor_offset = cursor_offset;
2040 s->cursor_start = s->cr[0xa];
2041 s->cursor_end = s->cr[0xb];
2044 src = (uint32_t *) s->vram_ptr + s->start_addr;
2045 dst = chardata;
2047 if (full_update) {
2048 for (i = 0; i < size; src ++, dst ++, i ++)
2049 console_write_ch(dst, VMEM2CHTYPE(le32_to_cpu(*src)));
2051 dpy_update(s->ds, 0, 0, width, height);
2052 } else {
2053 c_max = 0;
2055 for (i = 0; i < size; src ++, dst ++, i ++) {
2056 console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
2057 if (*dst != val) {
2058 *dst = val;
2059 c_max = i;
2060 break;
2063 c_min = i;
2064 for (; i < size; src ++, dst ++, i ++) {
2065 console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
2066 if (*dst != val) {
2067 *dst = val;
2068 c_max = i;
2072 if (c_min <= c_max) {
2073 i = TEXTMODE_Y(c_min);
2074 dpy_update(s->ds, 0, i, width, TEXTMODE_Y(c_max) - i + 1);
2078 return;
2079 case GMODE_GRAPH:
2080 if (!full_update)
2081 return;
2083 s->get_resolution(s, &width, &height);
2084 snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Graphic mode",
2085 width, height);
2086 break;
2087 case GMODE_BLANK:
2088 default:
2089 if (!full_update)
2090 return;
2092 snprintf(msg_buffer, sizeof(msg_buffer), "VGA Blank mode");
2093 break;
2096 /* Display a message */
2097 s->last_width = 60;
2098 s->last_height = height = 3;
2099 dpy_cursor(s->ds, -1, -1);
2100 s->ds->surface->width = s->last_width;
2101 s->ds->surface->height = height;
2102 dpy_resize(s->ds);
2104 for (dst = chardata, i = 0; i < s->last_width * height; i ++)
2105 console_write_ch(dst ++, ' ');
2107 size = strlen(msg_buffer);
2108 width = (s->last_width - size) / 2;
2109 dst = chardata + s->last_width + width;
2110 for (i = 0; i < size; i ++)
2111 console_write_ch(dst ++, 0x00200100 | msg_buffer[i]);
2113 dpy_update(s->ds, 0, 0, s->last_width, height);
2116 static uint64_t vga_mem_read(void *opaque, target_phys_addr_t addr,
2117 unsigned size)
2119 VGACommonState *s = opaque;
2121 return vga_mem_readb(s, addr);
2124 static void vga_mem_write(void *opaque, target_phys_addr_t addr,
2125 uint64_t data, unsigned size)
2127 VGACommonState *s = opaque;
2129 return vga_mem_writeb(s, addr, data);
2132 const MemoryRegionOps vga_mem_ops = {
2133 .read = vga_mem_read,
2134 .write = vga_mem_write,
2135 .endianness = DEVICE_LITTLE_ENDIAN,
2136 .impl = {
2137 .min_access_size = 1,
2138 .max_access_size = 1,
2142 static int vga_common_post_load(void *opaque, int version_id)
2144 VGACommonState *s = opaque;
2146 /* force refresh */
2147 s->graphic_mode = -1;
2148 return 0;
2151 const VMStateDescription vmstate_vga_common = {
2152 .name = "vga",
2153 .version_id = 2,
2154 .minimum_version_id = 2,
2155 .minimum_version_id_old = 2,
2156 .post_load = vga_common_post_load,
2157 .fields = (VMStateField []) {
2158 VMSTATE_UINT32(latch, VGACommonState),
2159 VMSTATE_UINT8(sr_index, VGACommonState),
2160 VMSTATE_PARTIAL_BUFFER(sr, VGACommonState, 8),
2161 VMSTATE_UINT8(gr_index, VGACommonState),
2162 VMSTATE_PARTIAL_BUFFER(gr, VGACommonState, 16),
2163 VMSTATE_UINT8(ar_index, VGACommonState),
2164 VMSTATE_BUFFER(ar, VGACommonState),
2165 VMSTATE_INT32(ar_flip_flop, VGACommonState),
2166 VMSTATE_UINT8(cr_index, VGACommonState),
2167 VMSTATE_BUFFER(cr, VGACommonState),
2168 VMSTATE_UINT8(msr, VGACommonState),
2169 VMSTATE_UINT8(fcr, VGACommonState),
2170 VMSTATE_UINT8(st00, VGACommonState),
2171 VMSTATE_UINT8(st01, VGACommonState),
2173 VMSTATE_UINT8(dac_state, VGACommonState),
2174 VMSTATE_UINT8(dac_sub_index, VGACommonState),
2175 VMSTATE_UINT8(dac_read_index, VGACommonState),
2176 VMSTATE_UINT8(dac_write_index, VGACommonState),
2177 VMSTATE_BUFFER(dac_cache, VGACommonState),
2178 VMSTATE_BUFFER(palette, VGACommonState),
2180 VMSTATE_INT32(bank_offset, VGACommonState),
2181 VMSTATE_UINT8_EQUAL(is_vbe_vmstate, VGACommonState),
2182 #ifdef CONFIG_BOCHS_VBE
2183 VMSTATE_UINT16(vbe_index, VGACommonState),
2184 VMSTATE_UINT16_ARRAY(vbe_regs, VGACommonState, VBE_DISPI_INDEX_NB),
2185 VMSTATE_UINT32(vbe_start_addr, VGACommonState),
2186 VMSTATE_UINT32(vbe_line_offset, VGACommonState),
2187 VMSTATE_UINT32(vbe_bank_mask, VGACommonState),
2188 #endif
2189 VMSTATE_END_OF_LIST()
2193 void vga_common_init(VGACommonState *s, int vga_ram_size)
2195 int i, j, v, b;
2197 for(i = 0;i < 256; i++) {
2198 v = 0;
2199 for(j = 0; j < 8; j++) {
2200 v |= ((i >> j) & 1) << (j * 4);
2202 expand4[i] = v;
2204 v = 0;
2205 for(j = 0; j < 4; j++) {
2206 v |= ((i >> (2 * j)) & 3) << (j * 4);
2208 expand2[i] = v;
2210 for(i = 0; i < 16; i++) {
2211 v = 0;
2212 for(j = 0; j < 4; j++) {
2213 b = ((i >> j) & 1);
2214 v |= b << (2 * j);
2215 v |= b << (2 * j + 1);
2217 expand4to8[i] = v;
2220 #ifdef CONFIG_BOCHS_VBE
2221 s->is_vbe_vmstate = 1;
2222 #else
2223 s->is_vbe_vmstate = 0;
2224 #endif
2225 memory_region_init_ram(&s->vram, "vga.vram", vga_ram_size);
2226 vmstate_register_ram_global(&s->vram);
2227 xen_register_framebuffer(&s->vram);
2228 s->vram_ptr = memory_region_get_ram_ptr(&s->vram);
2229 s->vram_size = vga_ram_size;
2230 s->get_bpp = vga_get_bpp;
2231 s->get_offsets = vga_get_offsets;
2232 s->get_resolution = vga_get_resolution;
2233 s->update = vga_update_display;
2234 s->invalidate = vga_invalidate_display;
2235 s->screen_dump = vga_screen_dump;
2236 s->text_update = vga_update_text;
2237 switch (vga_retrace_method) {
2238 case VGA_RETRACE_DUMB:
2239 s->retrace = vga_dumb_retrace;
2240 s->update_retrace_info = vga_dumb_update_retrace_info;
2241 break;
2243 case VGA_RETRACE_PRECISE:
2244 s->retrace = vga_precise_retrace;
2245 s->update_retrace_info = vga_precise_update_retrace_info;
2246 break;
2248 vga_dirty_log_start(s);
2251 static const MemoryRegionPortio vga_portio_list[] = {
2252 { 0x04, 2, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3b4 */
2253 { 0x0a, 1, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3ba */
2254 { 0x10, 16, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3c0 */
2255 { 0x24, 2, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3d4 */
2256 { 0x2a, 1, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3da */
2257 PORTIO_END_OF_LIST(),
2260 #ifdef CONFIG_BOCHS_VBE
2261 static const MemoryRegionPortio vbe_portio_list[] = {
2262 { 0, 1, 2, .read = vbe_ioport_read_index, .write = vbe_ioport_write_index },
2263 # ifdef TARGET_I386
2264 { 1, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data },
2265 # else
2266 { 2, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data },
2267 # endif
2268 PORTIO_END_OF_LIST(),
2270 #endif /* CONFIG_BOCHS_VBE */
2272 /* Used by both ISA and PCI */
2273 MemoryRegion *vga_init_io(VGACommonState *s,
2274 const MemoryRegionPortio **vga_ports,
2275 const MemoryRegionPortio **vbe_ports)
2277 MemoryRegion *vga_mem;
2279 *vga_ports = vga_portio_list;
2280 *vbe_ports = NULL;
2281 #ifdef CONFIG_BOCHS_VBE
2282 *vbe_ports = vbe_portio_list;
2283 #endif
2285 vga_mem = g_malloc(sizeof(*vga_mem));
2286 memory_region_init_io(vga_mem, &vga_mem_ops, s,
2287 "vga-lowmem", 0x20000);
2289 return vga_mem;
2292 void vga_init(VGACommonState *s, MemoryRegion *address_space,
2293 MemoryRegion *address_space_io, bool init_vga_ports)
2295 MemoryRegion *vga_io_memory;
2296 const MemoryRegionPortio *vga_ports, *vbe_ports;
2297 PortioList *vga_port_list = g_new(PortioList, 1);
2298 PortioList *vbe_port_list = g_new(PortioList, 1);
2300 qemu_register_reset(vga_reset, s);
2302 s->bank_offset = 0;
2304 s->legacy_address_space = address_space;
2306 vga_io_memory = vga_init_io(s, &vga_ports, &vbe_ports);
2307 memory_region_add_subregion_overlap(address_space,
2308 isa_mem_base + 0x000a0000,
2309 vga_io_memory,
2311 memory_region_set_coalescing(vga_io_memory);
2312 if (init_vga_ports) {
2313 portio_list_init(vga_port_list, vga_ports, s, "vga");
2314 portio_list_add(vga_port_list, address_space_io, 0x3b0);
2316 if (vbe_ports) {
2317 portio_list_init(vbe_port_list, vbe_ports, s, "vbe");
2318 portio_list_add(vbe_port_list, address_space_io, 0x1ce);
2322 void vga_init_vbe(VGACommonState *s, MemoryRegion *system_memory)
2324 #ifdef CONFIG_BOCHS_VBE
2325 /* XXX: use optimized standard vga accesses */
2326 memory_region_add_subregion(system_memory,
2327 VBE_DISPI_LFB_PHYSICAL_ADDRESS,
2328 &s->vram);
2329 s->vbe_mapped = 1;
2330 #endif
2332 /********************************************************/
2333 /* vga screen dump */
2335 static void vga_save_dpy_update(DisplayState *ds,
2336 int x, int y, int w, int h)
2338 if (screen_dump_filename) {
2339 ppm_save(screen_dump_filename, ds->surface);
2343 static void vga_save_dpy_resize(DisplayState *s)
2347 static void vga_save_dpy_refresh(DisplayState *s)
2351 int ppm_save(const char *filename, struct DisplaySurface *ds)
2353 FILE *f;
2354 uint8_t *d, *d1;
2355 uint32_t v;
2356 int y, x;
2357 uint8_t r, g, b;
2358 int ret;
2359 char *linebuf, *pbuf;
2361 f = fopen(filename, "wb");
2362 if (!f)
2363 return -1;
2364 fprintf(f, "P6\n%d %d\n%d\n",
2365 ds->width, ds->height, 255);
2366 linebuf = g_malloc(ds->width * 3);
2367 d1 = ds->data;
2368 for(y = 0; y < ds->height; y++) {
2369 d = d1;
2370 pbuf = linebuf;
2371 for(x = 0; x < ds->width; x++) {
2372 if (ds->pf.bits_per_pixel == 32)
2373 v = *(uint32_t *)d;
2374 else
2375 v = (uint32_t) (*(uint16_t *)d);
2376 /* Limited to 8 or fewer bits per channel: */
2377 r = ((v >> ds->pf.rshift) & ds->pf.rmax) << (8 - ds->pf.rbits);
2378 g = ((v >> ds->pf.gshift) & ds->pf.gmax) << (8 - ds->pf.gbits);
2379 b = ((v >> ds->pf.bshift) & ds->pf.bmax) << (8 - ds->pf.bbits);
2380 *pbuf++ = r;
2381 *pbuf++ = g;
2382 *pbuf++ = b;
2383 d += ds->pf.bytes_per_pixel;
2385 d1 += ds->linesize;
2386 ret = fwrite(linebuf, 1, pbuf - linebuf, f);
2387 (void)ret;
2389 g_free(linebuf);
2390 fclose(f);
2391 return 0;
2394 static DisplayChangeListener* vga_screen_dump_init(DisplayState *ds)
2396 DisplayChangeListener *dcl;
2398 dcl = g_malloc0(sizeof(DisplayChangeListener));
2399 dcl->dpy_update = vga_save_dpy_update;
2400 dcl->dpy_resize = vga_save_dpy_resize;
2401 dcl->dpy_refresh = vga_save_dpy_refresh;
2402 register_displaychangelistener(ds, dcl);
2403 return dcl;
2406 /* save the vga display in a PPM image even if no display is
2407 available */
2408 static void vga_screen_dump(void *opaque, const char *filename)
2410 VGACommonState *s = opaque;
2412 if (!screen_dump_dcl)
2413 screen_dump_dcl = vga_screen_dump_init(s->ds);
2415 screen_dump_filename = filename;
2416 vga_invalidate_display(s);
2417 vga_hw_update();
2418 screen_dump_filename = NULL;