Merge commit 'qemu-svn/trunk'
[kvm-userspace.git] / qemu / hw / vga.c
blob4a081ce28d93686d95888bb43058c672af09ca96
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 "kvm.h"
32 #include "qemu-kvm.h"
34 //#define DEBUG_VGA
35 //#define DEBUG_VGA_MEM
36 //#define DEBUG_VGA_REG
38 //#define DEBUG_BOCHS_VBE
40 #define GMODE_TEXT 0
41 #define GMODE_GRAPH 1
42 #define GMODE_BLANK 2
44 /* force some bits to zero */
45 const uint8_t sr_mask[8] = {
46 0x03,
47 0x3d,
48 0x0f,
49 0x3f,
50 0x0e,
51 0x00,
52 0x00,
53 0xff,
56 const uint8_t gr_mask[16] = {
57 0x0f, /* 0x00 */
58 0x0f, /* 0x01 */
59 0x0f, /* 0x02 */
60 0x1f, /* 0x03 */
61 0x03, /* 0x04 */
62 0x7b, /* 0x05 */
63 0x0f, /* 0x06 */
64 0x0f, /* 0x07 */
65 0xff, /* 0x08 */
66 0x00, /* 0x09 */
67 0x00, /* 0x0a */
68 0x00, /* 0x0b */
69 0x00, /* 0x0c */
70 0x00, /* 0x0d */
71 0x00, /* 0x0e */
72 0x00, /* 0x0f */
75 #define cbswap_32(__x) \
76 ((uint32_t)( \
77 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
78 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
79 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
80 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
82 #ifdef WORDS_BIGENDIAN
83 #define PAT(x) cbswap_32(x)
84 #else
85 #define PAT(x) (x)
86 #endif
88 #ifdef WORDS_BIGENDIAN
89 #define BIG 1
90 #else
91 #define BIG 0
92 #endif
94 #ifdef WORDS_BIGENDIAN
95 #define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
96 #else
97 #define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
98 #endif
100 static const uint32_t mask16[16] = {
101 PAT(0x00000000),
102 PAT(0x000000ff),
103 PAT(0x0000ff00),
104 PAT(0x0000ffff),
105 PAT(0x00ff0000),
106 PAT(0x00ff00ff),
107 PAT(0x00ffff00),
108 PAT(0x00ffffff),
109 PAT(0xff000000),
110 PAT(0xff0000ff),
111 PAT(0xff00ff00),
112 PAT(0xff00ffff),
113 PAT(0xffff0000),
114 PAT(0xffff00ff),
115 PAT(0xffffff00),
116 PAT(0xffffffff),
119 #undef PAT
121 #ifdef WORDS_BIGENDIAN
122 #define PAT(x) (x)
123 #else
124 #define PAT(x) cbswap_32(x)
125 #endif
127 static const uint32_t dmask16[16] = {
128 PAT(0x00000000),
129 PAT(0x000000ff),
130 PAT(0x0000ff00),
131 PAT(0x0000ffff),
132 PAT(0x00ff0000),
133 PAT(0x00ff00ff),
134 PAT(0x00ffff00),
135 PAT(0x00ffffff),
136 PAT(0xff000000),
137 PAT(0xff0000ff),
138 PAT(0xff00ff00),
139 PAT(0xff00ffff),
140 PAT(0xffff0000),
141 PAT(0xffff00ff),
142 PAT(0xffffff00),
143 PAT(0xffffffff),
146 static const uint32_t dmask4[4] = {
147 PAT(0x00000000),
148 PAT(0x0000ffff),
149 PAT(0xffff0000),
150 PAT(0xffffffff),
153 static uint32_t expand4[256];
154 static uint16_t expand2[256];
155 static uint8_t expand4to8[16];
157 static void vga_screen_dump(void *opaque, const char *filename);
159 static void vga_dumb_update_retrace_info(VGAState *s)
161 (void) s;
164 static void vga_precise_update_retrace_info(VGAState *s)
166 int htotal_chars;
167 int hretr_start_char;
168 int hretr_skew_chars;
169 int hretr_end_char;
171 int vtotal_lines;
172 int vretr_start_line;
173 int vretr_end_line;
175 int div2, sldiv2, dots;
176 int clocking_mode;
177 int clock_sel;
178 const int clk_hz[] = {25175000, 28322000, 25175000, 25175000};
179 int64_t chars_per_sec;
180 struct vga_precise_retrace *r = &s->retrace_info.precise;
182 htotal_chars = s->cr[0x00] + 5;
183 hretr_start_char = s->cr[0x04];
184 hretr_skew_chars = (s->cr[0x05] >> 5) & 3;
185 hretr_end_char = s->cr[0x05] & 0x1f;
187 vtotal_lines = (s->cr[0x06]
188 | (((s->cr[0x07] & 1) | ((s->cr[0x07] >> 4) & 2)) << 8)) + 2
190 vretr_start_line = s->cr[0x10]
191 | ((((s->cr[0x07] >> 2) & 1) | ((s->cr[0x07] >> 6) & 2)) << 8)
193 vretr_end_line = s->cr[0x11] & 0xf;
196 div2 = (s->cr[0x17] >> 2) & 1;
197 sldiv2 = (s->cr[0x17] >> 3) & 1;
199 clocking_mode = (s->sr[0x01] >> 3) & 1;
200 clock_sel = (s->msr >> 2) & 3;
201 dots = (s->msr & 1) ? 8 : 9;
203 chars_per_sec = clk_hz[clock_sel] / dots;
205 htotal_chars <<= clocking_mode;
207 r->total_chars = vtotal_lines * htotal_chars;
208 if (r->freq) {
209 r->ticks_per_char = ticks_per_sec / (r->total_chars * r->freq);
210 } else {
211 r->ticks_per_char = ticks_per_sec / chars_per_sec;
214 r->vstart = vretr_start_line;
215 r->vend = r->vstart + vretr_end_line + 1;
217 r->hstart = hretr_start_char + hretr_skew_chars;
218 r->hend = r->hstart + hretr_end_char + 1;
219 r->htotal = htotal_chars;
221 #if 0
222 printf (
223 "hz=%f\n"
224 "htotal = %d\n"
225 "hretr_start = %d\n"
226 "hretr_skew = %d\n"
227 "hretr_end = %d\n"
228 "vtotal = %d\n"
229 "vretr_start = %d\n"
230 "vretr_end = %d\n"
231 "div2 = %d sldiv2 = %d\n"
232 "clocking_mode = %d\n"
233 "clock_sel = %d %d\n"
234 "dots = %d\n"
235 "ticks/char = %lld\n"
236 "\n",
237 (double) ticks_per_sec / (r->ticks_per_char * r->total_chars),
238 htotal_chars,
239 hretr_start_char,
240 hretr_skew_chars,
241 hretr_end_char,
242 vtotal_lines,
243 vretr_start_line,
244 vretr_end_line,
245 div2, sldiv2,
246 clocking_mode,
247 clock_sel,
248 clk_hz[clock_sel],
249 dots,
250 r->ticks_per_char
252 #endif
255 static uint8_t vga_precise_retrace(VGAState *s)
257 struct vga_precise_retrace *r = &s->retrace_info.precise;
258 uint8_t val = s->st01 & ~(ST01_V_RETRACE | ST01_DISP_ENABLE);
260 if (r->total_chars) {
261 int cur_line, cur_line_char, cur_char;
262 int64_t cur_tick;
264 cur_tick = qemu_get_clock(vm_clock);
266 cur_char = (cur_tick / r->ticks_per_char) % r->total_chars;
267 cur_line = cur_char / r->htotal;
269 if (cur_line >= r->vstart && cur_line <= r->vend) {
270 val |= ST01_V_RETRACE | ST01_DISP_ENABLE;
271 } else {
272 cur_line_char = cur_char % r->htotal;
273 if (cur_line_char >= r->hstart && cur_line_char <= r->hend) {
274 val |= ST01_DISP_ENABLE;
278 return val;
279 } else {
280 return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
284 static uint8_t vga_dumb_retrace(VGAState *s)
286 return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
289 static uint32_t vga_ioport_read(void *opaque, uint32_t addr)
291 VGAState *s = opaque;
292 int val, index;
294 /* check port range access depending on color/monochrome mode */
295 if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
296 (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION))) {
297 val = 0xff;
298 } else {
299 switch(addr) {
300 case 0x3c0:
301 if (s->ar_flip_flop == 0) {
302 val = s->ar_index;
303 } else {
304 val = 0;
306 break;
307 case 0x3c1:
308 index = s->ar_index & 0x1f;
309 if (index < 21)
310 val = s->ar[index];
311 else
312 val = 0;
313 break;
314 case 0x3c2:
315 val = s->st00;
316 break;
317 case 0x3c4:
318 val = s->sr_index;
319 break;
320 case 0x3c5:
321 val = s->sr[s->sr_index];
322 #ifdef DEBUG_VGA_REG
323 printf("vga: read SR%x = 0x%02x\n", s->sr_index, val);
324 #endif
325 break;
326 case 0x3c7:
327 val = s->dac_state;
328 break;
329 case 0x3c8:
330 val = s->dac_write_index;
331 break;
332 case 0x3c9:
333 val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
334 if (++s->dac_sub_index == 3) {
335 s->dac_sub_index = 0;
336 s->dac_read_index++;
338 break;
339 case 0x3ca:
340 val = s->fcr;
341 break;
342 case 0x3cc:
343 val = s->msr;
344 break;
345 case 0x3ce:
346 val = s->gr_index;
347 break;
348 case 0x3cf:
349 val = s->gr[s->gr_index];
350 #ifdef DEBUG_VGA_REG
351 printf("vga: read GR%x = 0x%02x\n", s->gr_index, val);
352 #endif
353 break;
354 case 0x3b4:
355 case 0x3d4:
356 val = s->cr_index;
357 break;
358 case 0x3b5:
359 case 0x3d5:
360 val = s->cr[s->cr_index];
361 #ifdef DEBUG_VGA_REG
362 printf("vga: read CR%x = 0x%02x\n", s->cr_index, val);
363 #endif
364 break;
365 case 0x3ba:
366 case 0x3da:
367 /* just toggle to fool polling */
368 val = s->st01 = s->retrace(s);
369 s->ar_flip_flop = 0;
370 break;
371 default:
372 val = 0x00;
373 break;
376 #if defined(DEBUG_VGA)
377 printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
378 #endif
379 return val;
382 static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
384 VGAState *s = opaque;
385 int index;
387 /* check port range access depending on color/monochrome mode */
388 if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
389 (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION)))
390 return;
392 #ifdef DEBUG_VGA
393 printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
394 #endif
396 switch(addr) {
397 case 0x3c0:
398 if (s->ar_flip_flop == 0) {
399 val &= 0x3f;
400 s->ar_index = val;
401 vga_update_resolution(s);
402 } else {
403 index = s->ar_index & 0x1f;
404 switch(index) {
405 case 0x00 ... 0x0f:
406 s->ar[index] = val & 0x3f;
407 break;
408 case 0x10:
409 s->ar[index] = val & ~0x10;
410 break;
411 case 0x11:
412 s->ar[index] = val;
413 break;
414 case 0x12:
415 s->ar[index] = val & ~0xc0;
416 break;
417 case 0x13:
418 s->ar[index] = val & ~0xf0;
419 break;
420 case 0x14:
421 s->ar[index] = val & ~0xf0;
422 break;
423 default:
424 break;
427 s->ar_flip_flop ^= 1;
428 break;
429 case 0x3c2:
430 s->msr = val & ~0x10;
431 s->update_retrace_info(s);
432 break;
433 case 0x3c4:
434 s->sr_index = val & 7;
435 break;
436 case 0x3c5:
437 #ifdef DEBUG_VGA_REG
438 printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
439 #endif
440 s->sr[s->sr_index] = val & sr_mask[s->sr_index];
441 if (s->sr_index == 1) s->update_retrace_info(s);
442 vga_update_resolution(s);
443 break;
444 case 0x3c7:
445 s->dac_read_index = val;
446 s->dac_sub_index = 0;
447 s->dac_state = 3;
448 break;
449 case 0x3c8:
450 s->dac_write_index = val;
451 s->dac_sub_index = 0;
452 s->dac_state = 0;
453 break;
454 case 0x3c9:
455 s->dac_cache[s->dac_sub_index] = val;
456 if (++s->dac_sub_index == 3) {
457 memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
458 s->dac_sub_index = 0;
459 s->dac_write_index++;
461 break;
462 case 0x3ce:
463 s->gr_index = val & 0x0f;
464 break;
465 case 0x3cf:
466 #ifdef DEBUG_VGA_REG
467 printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
468 #endif
469 s->gr[s->gr_index] = val & gr_mask[s->gr_index];
470 vga_update_resolution(s);
471 break;
472 case 0x3b4:
473 case 0x3d4:
474 s->cr_index = val;
475 break;
476 case 0x3b5:
477 case 0x3d5:
478 #ifdef DEBUG_VGA_REG
479 printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
480 #endif
481 /* handle CR0-7 protection */
482 if ((s->cr[0x11] & 0x80) && s->cr_index <= 7) {
483 /* can always write bit 4 of CR7 */
484 if (s->cr_index == 7)
485 s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
486 vga_update_resolution(s);
487 return;
489 switch(s->cr_index) {
490 case 0x01: /* horizontal display end */
491 case 0x07:
492 case 0x09:
493 case 0x0c:
494 case 0x0d:
495 case 0x12: /* vertical display end */
496 s->cr[s->cr_index] = val;
497 break;
498 default:
499 s->cr[s->cr_index] = val;
500 break;
503 switch(s->cr_index) {
504 case 0x00:
505 case 0x04:
506 case 0x05:
507 case 0x06:
508 case 0x07:
509 case 0x11:
510 case 0x17:
511 s->update_retrace_info(s);
512 break;
514 vga_update_resolution(s);
515 break;
516 case 0x3ba:
517 case 0x3da:
518 s->fcr = val & 0x10;
519 break;
523 #ifdef CONFIG_BOCHS_VBE
524 static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
526 VGAState *s = opaque;
527 uint32_t val;
528 val = s->vbe_index;
529 return val;
532 static uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr)
534 VGAState *s = opaque;
535 uint32_t val;
537 if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
538 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_GETCAPS) {
539 switch(s->vbe_index) {
540 /* XXX: do not hardcode ? */
541 case VBE_DISPI_INDEX_XRES:
542 val = VBE_DISPI_MAX_XRES;
543 break;
544 case VBE_DISPI_INDEX_YRES:
545 val = VBE_DISPI_MAX_YRES;
546 break;
547 case VBE_DISPI_INDEX_BPP:
548 val = VBE_DISPI_MAX_BPP;
549 break;
550 default:
551 val = s->vbe_regs[s->vbe_index];
552 break;
554 } else {
555 val = s->vbe_regs[s->vbe_index];
557 } else {
558 val = 0;
560 #ifdef DEBUG_BOCHS_VBE
561 printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val);
562 #endif
563 return val;
566 static void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val)
568 VGAState *s = opaque;
569 s->vbe_index = val;
572 static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
574 VGAState *s = opaque;
576 if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
577 #ifdef DEBUG_BOCHS_VBE
578 printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val);
579 #endif
580 switch(s->vbe_index) {
581 case VBE_DISPI_INDEX_ID:
582 if (val == VBE_DISPI_ID0 ||
583 val == VBE_DISPI_ID1 ||
584 val == VBE_DISPI_ID2 ||
585 val == VBE_DISPI_ID3 ||
586 val == VBE_DISPI_ID4) {
587 s->vbe_regs[s->vbe_index] = val;
589 break;
590 case VBE_DISPI_INDEX_XRES:
591 if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) {
592 s->vbe_regs[s->vbe_index] = val;
594 vga_update_resolution(s);
595 break;
596 case VBE_DISPI_INDEX_YRES:
597 if (val <= VBE_DISPI_MAX_YRES) {
598 s->vbe_regs[s->vbe_index] = val;
600 vga_update_resolution(s);
601 break;
602 case VBE_DISPI_INDEX_BPP:
603 if (val == 0)
604 val = 8;
605 if (val == 4 || val == 8 || val == 15 ||
606 val == 16 || val == 24 || val == 32) {
607 s->vbe_regs[s->vbe_index] = val;
609 vga_update_resolution(s);
610 break;
611 case VBE_DISPI_INDEX_BANK:
612 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
613 val &= (s->vbe_bank_mask >> 2);
614 } else {
615 val &= s->vbe_bank_mask;
617 s->vbe_regs[s->vbe_index] = val;
618 s->bank_offset = (val << 16);
619 break;
620 case VBE_DISPI_INDEX_ENABLE:
621 if ((val & VBE_DISPI_ENABLED) &&
622 !(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
623 int h, shift_control;
625 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] =
626 s->vbe_regs[VBE_DISPI_INDEX_XRES];
627 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] =
628 s->vbe_regs[VBE_DISPI_INDEX_YRES];
629 s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
630 s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
632 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
633 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1;
634 else
635 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] *
636 ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
637 s->vbe_start_addr = 0;
639 /* clear the screen (should be done in BIOS) */
640 if (!(val & VBE_DISPI_NOCLEARMEM)) {
641 memset(s->vram_ptr, 0,
642 s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
645 /* we initialize the VGA graphic mode (should be done
646 in BIOS) */
647 s->gr[0x06] = (s->gr[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
648 s->cr[0x17] |= 3; /* no CGA modes */
649 s->cr[0x13] = s->vbe_line_offset >> 3;
650 /* width */
651 s->cr[0x01] = (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
652 /* height (only meaningful if < 1024) */
653 h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
654 s->cr[0x12] = h;
655 s->cr[0x07] = (s->cr[0x07] & ~0x42) |
656 ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
657 /* line compare to 1023 */
658 s->cr[0x18] = 0xff;
659 s->cr[0x07] |= 0x10;
660 s->cr[0x09] |= 0x40;
662 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
663 shift_control = 0;
664 s->sr[0x01] &= ~8; /* no double line */
665 } else {
666 shift_control = 2;
667 s->sr[4] |= 0x08; /* set chain 4 mode */
668 s->sr[2] |= 0x0f; /* activate all planes */
670 s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5);
671 s->cr[0x09] &= ~0x9f; /* no double scan */
672 } else {
673 /* XXX: the bios should do that */
674 s->bank_offset = 0;
676 s->dac_8bit = (val & VBE_DISPI_8BIT_DAC) > 0;
677 s->vbe_regs[s->vbe_index] = val;
678 vga_update_resolution(s);
679 break;
680 case VBE_DISPI_INDEX_VIRT_WIDTH:
682 int w, h, line_offset;
684 if (val < s->vbe_regs[VBE_DISPI_INDEX_XRES])
685 return;
686 w = val;
687 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
688 line_offset = w >> 1;
689 else
690 line_offset = w * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
691 h = s->vram_size / line_offset;
692 /* XXX: support weird bochs semantics ? */
693 if (h < s->vbe_regs[VBE_DISPI_INDEX_YRES])
694 return;
695 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = w;
696 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h;
697 s->vbe_line_offset = line_offset;
699 vga_update_resolution(s);
700 break;
701 case VBE_DISPI_INDEX_X_OFFSET:
702 case VBE_DISPI_INDEX_Y_OFFSET:
704 int x;
705 s->vbe_regs[s->vbe_index] = val;
706 s->vbe_start_addr = s->vbe_line_offset * s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET];
707 x = s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET];
708 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
709 s->vbe_start_addr += x >> 1;
710 else
711 s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
712 s->vbe_start_addr >>= 2;
714 vga_update_resolution(s);
715 break;
716 default:
717 break;
721 #endif
723 /* called for accesses between 0xa0000 and 0xc0000 */
724 uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr)
726 VGAState *s = opaque;
727 int memory_map_mode, plane;
728 uint32_t ret;
730 /* convert to VGA memory offset */
731 memory_map_mode = (s->gr[6] >> 2) & 3;
732 addr &= 0x1ffff;
733 switch(memory_map_mode) {
734 case 0:
735 break;
736 case 1:
737 if (addr >= 0x10000)
738 return 0xff;
739 addr += s->bank_offset;
740 break;
741 case 2:
742 addr -= 0x10000;
743 if (addr >= 0x8000)
744 return 0xff;
745 break;
746 default:
747 case 3:
748 addr -= 0x18000;
749 if (addr >= 0x8000)
750 return 0xff;
751 break;
754 if (s->sr[4] & 0x08) {
755 /* chain 4 mode : simplest access */
756 ret = s->vram_ptr[addr];
757 } else if (s->gr[5] & 0x10) {
758 /* odd/even mode (aka text mode mapping) */
759 plane = (s->gr[4] & 2) | (addr & 1);
760 ret = s->vram_ptr[((addr & ~1) << 1) | plane];
761 } else {
762 /* standard VGA latched access */
763 s->latch = ((uint32_t *)s->vram_ptr)[addr];
765 if (!(s->gr[5] & 0x08)) {
766 /* read mode 0 */
767 plane = s->gr[4];
768 ret = GET_PLANE(s->latch, plane);
769 } else {
770 /* read mode 1 */
771 ret = (s->latch ^ mask16[s->gr[2]]) & mask16[s->gr[7]];
772 ret |= ret >> 16;
773 ret |= ret >> 8;
774 ret = (~ret) & 0xff;
777 return ret;
780 static uint32_t vga_mem_readw(void *opaque, target_phys_addr_t addr)
782 uint32_t v;
783 #ifdef TARGET_WORDS_BIGENDIAN
784 v = vga_mem_readb(opaque, addr) << 8;
785 v |= vga_mem_readb(opaque, addr + 1);
786 #else
787 v = vga_mem_readb(opaque, addr);
788 v |= vga_mem_readb(opaque, addr + 1) << 8;
789 #endif
790 return v;
793 static uint32_t vga_mem_readl(void *opaque, target_phys_addr_t addr)
795 uint32_t v;
796 #ifdef TARGET_WORDS_BIGENDIAN
797 v = vga_mem_readb(opaque, addr) << 24;
798 v |= vga_mem_readb(opaque, addr + 1) << 16;
799 v |= vga_mem_readb(opaque, addr + 2) << 8;
800 v |= vga_mem_readb(opaque, addr + 3);
801 #else
802 v = vga_mem_readb(opaque, addr);
803 v |= vga_mem_readb(opaque, addr + 1) << 8;
804 v |= vga_mem_readb(opaque, addr + 2) << 16;
805 v |= vga_mem_readb(opaque, addr + 3) << 24;
806 #endif
807 return v;
810 /* called for accesses between 0xa0000 and 0xc0000 */
811 void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
813 VGAState *s = opaque;
814 int memory_map_mode, plane, write_mode, b, func_select, mask;
815 uint32_t write_mask, bit_mask, set_mask;
817 #ifdef DEBUG_VGA_MEM
818 printf("vga: [0x%x] = 0x%02x\n", addr, val);
819 #endif
820 /* convert to VGA memory offset */
821 memory_map_mode = (s->gr[6] >> 2) & 3;
822 addr &= 0x1ffff;
823 switch(memory_map_mode) {
824 case 0:
825 break;
826 case 1:
827 if (addr >= 0x10000)
828 return;
829 addr += s->bank_offset;
830 break;
831 case 2:
832 addr -= 0x10000;
833 if (addr >= 0x8000)
834 return;
835 break;
836 default:
837 case 3:
838 addr -= 0x18000;
839 if (addr >= 0x8000)
840 return;
841 break;
844 if (s->sr[4] & 0x08) {
845 /* chain 4 mode : simplest access */
846 plane = addr & 3;
847 mask = (1 << plane);
848 if (s->sr[2] & mask) {
849 s->vram_ptr[addr] = val;
850 #ifdef DEBUG_VGA_MEM
851 printf("vga: chain4: [0x%x]\n", addr);
852 #endif
853 s->plane_updated |= mask; /* only used to detect font change */
854 cpu_physical_memory_set_dirty(s->vram_offset + addr);
856 } else if (s->gr[5] & 0x10) {
857 /* odd/even mode (aka text mode mapping) */
858 plane = (s->gr[4] & 2) | (addr & 1);
859 mask = (1 << plane);
860 if (s->sr[2] & mask) {
861 addr = ((addr & ~1) << 1) | plane;
862 s->vram_ptr[addr] = val;
863 #ifdef DEBUG_VGA_MEM
864 printf("vga: odd/even: [0x%x]\n", addr);
865 #endif
866 s->plane_updated |= mask; /* only used to detect font change */
867 cpu_physical_memory_set_dirty(s->vram_offset + addr);
869 } else {
870 /* standard VGA latched access */
871 write_mode = s->gr[5] & 3;
872 switch(write_mode) {
873 default:
874 case 0:
875 /* rotate */
876 b = s->gr[3] & 7;
877 val = ((val >> b) | (val << (8 - b))) & 0xff;
878 val |= val << 8;
879 val |= val << 16;
881 /* apply set/reset mask */
882 set_mask = mask16[s->gr[1]];
883 val = (val & ~set_mask) | (mask16[s->gr[0]] & set_mask);
884 bit_mask = s->gr[8];
885 break;
886 case 1:
887 val = s->latch;
888 goto do_write;
889 case 2:
890 val = mask16[val & 0x0f];
891 bit_mask = s->gr[8];
892 break;
893 case 3:
894 /* rotate */
895 b = s->gr[3] & 7;
896 val = (val >> b) | (val << (8 - b));
898 bit_mask = s->gr[8] & val;
899 val = mask16[s->gr[0]];
900 break;
903 /* apply logical operation */
904 func_select = s->gr[3] >> 3;
905 switch(func_select) {
906 case 0:
907 default:
908 /* nothing to do */
909 break;
910 case 1:
911 /* and */
912 val &= s->latch;
913 break;
914 case 2:
915 /* or */
916 val |= s->latch;
917 break;
918 case 3:
919 /* xor */
920 val ^= s->latch;
921 break;
924 /* apply bit mask */
925 bit_mask |= bit_mask << 8;
926 bit_mask |= bit_mask << 16;
927 val = (val & bit_mask) | (s->latch & ~bit_mask);
929 do_write:
930 /* mask data according to sr[2] */
931 mask = s->sr[2];
932 s->plane_updated |= mask; /* only used to detect font change */
933 write_mask = mask16[mask];
934 ((uint32_t *)s->vram_ptr)[addr] =
935 (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
936 (val & write_mask);
937 #ifdef DEBUG_VGA_MEM
938 printf("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n",
939 addr * 4, write_mask, val);
940 #endif
941 cpu_physical_memory_set_dirty(s->vram_offset + (addr << 2));
945 static void vga_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
947 #ifdef TARGET_WORDS_BIGENDIAN
948 vga_mem_writeb(opaque, addr, (val >> 8) & 0xff);
949 vga_mem_writeb(opaque, addr + 1, val & 0xff);
950 #else
951 vga_mem_writeb(opaque, addr, val & 0xff);
952 vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
953 #endif
956 static void vga_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
958 #ifdef TARGET_WORDS_BIGENDIAN
959 vga_mem_writeb(opaque, addr, (val >> 24) & 0xff);
960 vga_mem_writeb(opaque, addr + 1, (val >> 16) & 0xff);
961 vga_mem_writeb(opaque, addr + 2, (val >> 8) & 0xff);
962 vga_mem_writeb(opaque, addr + 3, val & 0xff);
963 #else
964 vga_mem_writeb(opaque, addr, val & 0xff);
965 vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
966 vga_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff);
967 vga_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff);
968 #endif
971 typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
972 const uint8_t *font_ptr, int h,
973 uint32_t fgcol, uint32_t bgcol);
974 typedef void vga_draw_glyph9_func(uint8_t *d, int linesize,
975 const uint8_t *font_ptr, int h,
976 uint32_t fgcol, uint32_t bgcol, int dup9);
977 typedef void vga_draw_line_func(VGAState *s1, uint8_t *d,
978 const uint8_t *s, int width);
980 #define DEPTH 8
981 #include "vga_template.h"
983 #define DEPTH 15
984 #include "vga_template.h"
986 #define BGR_FORMAT
987 #define DEPTH 15
988 #include "vga_template.h"
990 #define DEPTH 16
991 #include "vga_template.h"
993 #define BGR_FORMAT
994 #define DEPTH 16
995 #include "vga_template.h"
997 #define DEPTH 32
998 #include "vga_template.h"
1000 #define BGR_FORMAT
1001 #define DEPTH 32
1002 #include "vga_template.h"
1004 static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
1006 unsigned int col;
1007 col = rgb_to_pixel8(r, g, b);
1008 col |= col << 8;
1009 col |= col << 16;
1010 return col;
1013 static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b)
1015 unsigned int col;
1016 col = rgb_to_pixel15(r, g, b);
1017 col |= col << 16;
1018 return col;
1021 static unsigned int rgb_to_pixel15bgr_dup(unsigned int r, unsigned int g,
1022 unsigned int b)
1024 unsigned int col;
1025 col = rgb_to_pixel15bgr(r, g, b);
1026 col |= col << 16;
1027 return col;
1030 static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
1032 unsigned int col;
1033 col = rgb_to_pixel16(r, g, b);
1034 col |= col << 16;
1035 return col;
1038 static unsigned int rgb_to_pixel16bgr_dup(unsigned int r, unsigned int g,
1039 unsigned int b)
1041 unsigned int col;
1042 col = rgb_to_pixel16bgr(r, g, b);
1043 col |= col << 16;
1044 return col;
1047 static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
1049 unsigned int col;
1050 col = rgb_to_pixel32(r, g, b);
1051 return col;
1054 static unsigned int rgb_to_pixel32bgr_dup(unsigned int r, unsigned int g, unsigned b)
1056 unsigned int col;
1057 col = rgb_to_pixel32bgr(r, g, b);
1058 return col;
1061 /* return true if the palette was modified */
1062 static int update_palette16(VGAState *s)
1064 int full_update, i;
1065 uint32_t v, col, *palette;
1067 full_update = 0;
1068 palette = s->last_palette;
1069 for(i = 0; i < 16; i++) {
1070 v = s->ar[i];
1071 if (s->ar[0x10] & 0x80)
1072 v = ((s->ar[0x14] & 0xf) << 4) | (v & 0xf);
1073 else
1074 v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f);
1075 v = v * 3;
1076 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
1077 c6_to_8(s->palette[v + 1]),
1078 c6_to_8(s->palette[v + 2]));
1079 if (col != palette[i]) {
1080 full_update = 1;
1081 palette[i] = col;
1084 return full_update;
1087 /* return true if the palette was modified */
1088 static int update_palette256(VGAState *s)
1090 int full_update, i;
1091 uint32_t v, col, *palette;
1093 full_update = 0;
1094 palette = s->last_palette;
1095 v = 0;
1096 for(i = 0; i < 256; i++) {
1097 if (s->dac_8bit) {
1098 col = s->rgb_to_pixel(s->palette[v],
1099 s->palette[v + 1],
1100 s->palette[v + 2]);
1101 } else {
1102 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
1103 c6_to_8(s->palette[v + 1]),
1104 c6_to_8(s->palette[v + 2]));
1106 if (col != palette[i]) {
1107 full_update = 1;
1108 palette[i] = col;
1110 v += 3;
1112 return full_update;
1115 static void vga_get_offsets(VGAState *s,
1116 uint32_t *pline_offset,
1117 uint32_t *pstart_addr,
1118 uint32_t *pline_compare)
1120 uint32_t start_addr, line_offset, line_compare;
1121 #ifdef CONFIG_BOCHS_VBE
1122 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1123 line_offset = s->vbe_line_offset;
1124 start_addr = s->vbe_start_addr;
1125 line_compare = 65535;
1126 } else
1127 #endif
1129 /* compute line_offset in bytes */
1130 line_offset = s->cr[0x13];
1131 line_offset <<= 3;
1133 /* starting address */
1134 start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8);
1136 /* line compare */
1137 line_compare = s->cr[0x18] |
1138 ((s->cr[0x07] & 0x10) << 4) |
1139 ((s->cr[0x09] & 0x40) << 3);
1141 *pline_offset = line_offset;
1142 *pstart_addr = start_addr;
1143 *pline_compare = line_compare;
1146 /* update start_addr and line_offset. Return TRUE if modified */
1147 static int update_basic_params(VGAState *s)
1149 int full_update;
1150 uint32_t start_addr, line_offset, line_compare;
1152 full_update = 0;
1154 s->get_offsets(s, &line_offset, &start_addr, &line_compare);
1156 if (line_offset != s->line_offset ||
1157 start_addr != s->start_addr ||
1158 line_compare != s->line_compare) {
1159 s->line_offset = line_offset;
1160 s->start_addr = start_addr;
1161 s->line_compare = line_compare;
1162 full_update = 1;
1164 return full_update;
1167 #define NB_DEPTHS 7
1169 static inline int get_depth_index(DisplayState *s)
1171 switch(ds_get_bits_per_pixel(s)) {
1172 default:
1173 case 8:
1174 return 0;
1175 case 15:
1176 return 1;
1177 case 16:
1178 return 2;
1179 case 32:
1180 if (is_surface_bgr(s->surface))
1181 return 4;
1182 else
1183 return 3;
1187 static vga_draw_glyph8_func *vga_draw_glyph8_table[NB_DEPTHS] = {
1188 vga_draw_glyph8_8,
1189 vga_draw_glyph8_16,
1190 vga_draw_glyph8_16,
1191 vga_draw_glyph8_32,
1192 vga_draw_glyph8_32,
1193 vga_draw_glyph8_16,
1194 vga_draw_glyph8_16,
1197 static vga_draw_glyph8_func *vga_draw_glyph16_table[NB_DEPTHS] = {
1198 vga_draw_glyph16_8,
1199 vga_draw_glyph16_16,
1200 vga_draw_glyph16_16,
1201 vga_draw_glyph16_32,
1202 vga_draw_glyph16_32,
1203 vga_draw_glyph16_16,
1204 vga_draw_glyph16_16,
1207 static vga_draw_glyph9_func *vga_draw_glyph9_table[NB_DEPTHS] = {
1208 vga_draw_glyph9_8,
1209 vga_draw_glyph9_16,
1210 vga_draw_glyph9_16,
1211 vga_draw_glyph9_32,
1212 vga_draw_glyph9_32,
1213 vga_draw_glyph9_16,
1214 vga_draw_glyph9_16,
1217 static const uint8_t cursor_glyph[32 * 4] = {
1218 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1219 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1220 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1221 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1222 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1223 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1224 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1225 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1226 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1227 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1228 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1229 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1230 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1231 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1232 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1233 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1236 static void vga_get_text_resolution(VGAState *s, int *pwidth, int *pheight,
1237 int *pcwidth, int *pcheight)
1239 int width, cwidth, height, cheight;
1241 /* total width & height */
1242 cheight = (s->cr[9] & 0x1f) + 1;
1243 cwidth = 8;
1244 if (!(s->sr[1] & 0x01))
1245 cwidth = 9;
1246 if (s->sr[1] & 0x08)
1247 cwidth = 16; /* NOTE: no 18 pixel wide */
1248 width = (s->cr[0x01] + 1);
1249 if (s->cr[0x06] == 100) {
1250 /* ugly hack for CGA 160x100x16 - explain me the logic */
1251 height = 100;
1252 } else {
1253 height = s->cr[0x12] |
1254 ((s->cr[0x07] & 0x02) << 7) |
1255 ((s->cr[0x07] & 0x40) << 3);
1256 height = (height + 1) / cheight;
1259 *pwidth = width;
1260 *pheight = height;
1261 *pcwidth = cwidth;
1262 *pcheight = cheight;
1265 typedef unsigned int rgb_to_pixel_dup_func(unsigned int r, unsigned int g, unsigned b);
1267 static rgb_to_pixel_dup_func *rgb_to_pixel_dup_table[NB_DEPTHS] = {
1268 rgb_to_pixel8_dup,
1269 rgb_to_pixel15_dup,
1270 rgb_to_pixel16_dup,
1271 rgb_to_pixel32_dup,
1272 rgb_to_pixel32bgr_dup,
1273 rgb_to_pixel15bgr_dup,
1274 rgb_to_pixel16bgr_dup,
1278 * Text mode update
1279 * Missing:
1280 * - double scan
1281 * - double width
1282 * - underline
1283 * - flashing
1285 static void vga_draw_text(VGAState *s, int full_update)
1287 int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
1288 int cx_min, cx_max, linesize, x_incr;
1289 uint32_t offset, fgcol, bgcol, v, cursor_offset;
1290 uint8_t *d1, *d, *src, *s1, *dest, *cursor_ptr;
1291 const uint8_t *font_ptr, *font_base[2];
1292 int dup9, line_offset, depth_index;
1293 uint32_t *palette;
1294 uint32_t *ch_attr_ptr;
1295 vga_draw_glyph8_func *vga_draw_glyph8;
1296 vga_draw_glyph9_func *vga_draw_glyph9;
1298 vga_dirty_log_stop(s);
1300 /* compute font data address (in plane 2) */
1301 v = s->sr[3];
1302 offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
1303 if (offset != s->font_offsets[0]) {
1304 s->font_offsets[0] = offset;
1305 full_update = 1;
1307 font_base[0] = s->vram_ptr + offset;
1309 offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
1310 font_base[1] = s->vram_ptr + offset;
1311 if (offset != s->font_offsets[1]) {
1312 s->font_offsets[1] = offset;
1313 full_update = 1;
1315 if (s->plane_updated & (1 << 2)) {
1316 /* if the plane 2 was modified since the last display, it
1317 indicates the font may have been modified */
1318 s->plane_updated = 0;
1319 full_update = 1;
1322 line_offset = s->line_offset;
1323 s1 = s->vram_ptr + (s->start_addr * 4);
1325 vga_get_text_resolution(s, &width, &height, &cw, &cheight);
1326 x_incr = cw * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
1327 if ((height * width) > CH_ATTR_SIZE) {
1328 /* better than nothing: exit if transient size is too big */
1329 return;
1332 s->rgb_to_pixel =
1333 rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1334 full_update |= update_palette16(s);
1335 palette = s->last_palette;
1336 x_incr = cw * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
1338 cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
1339 if (cursor_offset != s->cursor_offset ||
1340 s->cr[0xa] != s->cursor_start ||
1341 s->cr[0xb] != s->cursor_end) {
1342 /* if the cursor position changed, we update the old and new
1343 chars */
1344 if (s->cursor_offset < CH_ATTR_SIZE)
1345 s->last_ch_attr[s->cursor_offset] = -1;
1346 if (cursor_offset < CH_ATTR_SIZE)
1347 s->last_ch_attr[cursor_offset] = -1;
1348 s->cursor_offset = cursor_offset;
1349 s->cursor_start = s->cr[0xa];
1350 s->cursor_end = s->cr[0xb];
1352 cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
1354 depth_index = get_depth_index(s->ds);
1355 if (cw == 16)
1356 vga_draw_glyph8 = vga_draw_glyph16_table[depth_index];
1357 else
1358 vga_draw_glyph8 = vga_draw_glyph8_table[depth_index];
1359 vga_draw_glyph9 = vga_draw_glyph9_table[depth_index];
1361 dest = ds_get_data(s->ds);
1362 linesize = ds_get_linesize(s->ds);
1363 ch_attr_ptr = s->last_ch_attr;
1364 for(cy = 0; cy < height; cy++) {
1365 d1 = dest;
1366 src = s1;
1367 cx_min = width;
1368 cx_max = -1;
1369 for(cx = 0; cx < width; cx++) {
1370 ch_attr = *(uint16_t *)src;
1371 if (full_update || ch_attr != *ch_attr_ptr) {
1372 if (cx < cx_min)
1373 cx_min = cx;
1374 if (cx > cx_max)
1375 cx_max = cx;
1376 *ch_attr_ptr = ch_attr;
1377 #ifdef WORDS_BIGENDIAN
1378 ch = ch_attr >> 8;
1379 cattr = ch_attr & 0xff;
1380 #else
1381 ch = ch_attr & 0xff;
1382 cattr = ch_attr >> 8;
1383 #endif
1384 font_ptr = font_base[(cattr >> 3) & 1];
1385 font_ptr += 32 * 4 * ch;
1386 bgcol = palette[cattr >> 4];
1387 fgcol = palette[cattr & 0x0f];
1388 if (cw != 9) {
1389 vga_draw_glyph8(d1, linesize,
1390 font_ptr, cheight, fgcol, bgcol);
1391 } else {
1392 dup9 = 0;
1393 if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))
1394 dup9 = 1;
1395 vga_draw_glyph9(d1, linesize,
1396 font_ptr, cheight, fgcol, bgcol, dup9);
1398 if (src == cursor_ptr &&
1399 !(s->cr[0x0a] & 0x20)) {
1400 int line_start, line_last, h;
1401 /* draw the cursor */
1402 line_start = s->cr[0x0a] & 0x1f;
1403 line_last = s->cr[0x0b] & 0x1f;
1404 /* XXX: check that */
1405 if (line_last > cheight - 1)
1406 line_last = cheight - 1;
1407 if (line_last >= line_start && line_start < cheight) {
1408 h = line_last - line_start + 1;
1409 d = d1 + linesize * line_start;
1410 if (cw != 9) {
1411 vga_draw_glyph8(d, linesize,
1412 cursor_glyph, h, fgcol, bgcol);
1413 } else {
1414 vga_draw_glyph9(d, linesize,
1415 cursor_glyph, h, fgcol, bgcol, 1);
1420 d1 += x_incr;
1421 src += 4;
1422 ch_attr_ptr++;
1424 if (cx_max != -1) {
1425 dpy_update(s->ds, cx_min * cw, cy * cheight,
1426 (cx_max - cx_min + 1) * cw, cheight);
1428 dest += linesize * cheight;
1429 s1 += line_offset;
1433 enum {
1434 VGA_DRAW_LINE2,
1435 VGA_DRAW_LINE2D2,
1436 VGA_DRAW_LINE4,
1437 VGA_DRAW_LINE4D2,
1438 VGA_DRAW_LINE8D2,
1439 VGA_DRAW_LINE8,
1440 VGA_DRAW_LINE15,
1441 VGA_DRAW_LINE16,
1442 VGA_DRAW_LINE24,
1443 VGA_DRAW_LINE32,
1444 VGA_DRAW_LINE_NB,
1447 static vga_draw_line_func *vga_draw_line_table[NB_DEPTHS * VGA_DRAW_LINE_NB] = {
1448 vga_draw_line2_8,
1449 vga_draw_line2_16,
1450 vga_draw_line2_16,
1451 vga_draw_line2_32,
1452 vga_draw_line2_32,
1453 vga_draw_line2_16,
1454 vga_draw_line2_16,
1456 vga_draw_line2d2_8,
1457 vga_draw_line2d2_16,
1458 vga_draw_line2d2_16,
1459 vga_draw_line2d2_32,
1460 vga_draw_line2d2_32,
1461 vga_draw_line2d2_16,
1462 vga_draw_line2d2_16,
1464 vga_draw_line4_8,
1465 vga_draw_line4_16,
1466 vga_draw_line4_16,
1467 vga_draw_line4_32,
1468 vga_draw_line4_32,
1469 vga_draw_line4_16,
1470 vga_draw_line4_16,
1472 vga_draw_line4d2_8,
1473 vga_draw_line4d2_16,
1474 vga_draw_line4d2_16,
1475 vga_draw_line4d2_32,
1476 vga_draw_line4d2_32,
1477 vga_draw_line4d2_16,
1478 vga_draw_line4d2_16,
1480 vga_draw_line8d2_8,
1481 vga_draw_line8d2_16,
1482 vga_draw_line8d2_16,
1483 vga_draw_line8d2_32,
1484 vga_draw_line8d2_32,
1485 vga_draw_line8d2_16,
1486 vga_draw_line8d2_16,
1488 vga_draw_line8_8,
1489 vga_draw_line8_16,
1490 vga_draw_line8_16,
1491 vga_draw_line8_32,
1492 vga_draw_line8_32,
1493 vga_draw_line8_16,
1494 vga_draw_line8_16,
1496 vga_draw_line15_8,
1497 vga_draw_line15_15,
1498 vga_draw_line15_16,
1499 vga_draw_line15_32,
1500 vga_draw_line15_32bgr,
1501 vga_draw_line15_15bgr,
1502 vga_draw_line15_16bgr,
1504 vga_draw_line16_8,
1505 vga_draw_line16_15,
1506 vga_draw_line16_16,
1507 vga_draw_line16_32,
1508 vga_draw_line16_32bgr,
1509 vga_draw_line16_15bgr,
1510 vga_draw_line16_16bgr,
1512 vga_draw_line24_8,
1513 vga_draw_line24_15,
1514 vga_draw_line24_16,
1515 vga_draw_line24_32,
1516 vga_draw_line24_32bgr,
1517 vga_draw_line24_15bgr,
1518 vga_draw_line24_16bgr,
1520 vga_draw_line32_8,
1521 vga_draw_line32_15,
1522 vga_draw_line32_16,
1523 vga_draw_line32_32,
1524 vga_draw_line32_32bgr,
1525 vga_draw_line32_15bgr,
1526 vga_draw_line32_16bgr,
1529 static int vga_get_bpp(VGAState *s)
1531 int ret;
1532 #ifdef CONFIG_BOCHS_VBE
1533 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1534 ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
1535 } else
1536 #endif
1538 ret = 0;
1540 return ret;
1543 static void vga_get_resolution(VGAState *s, int *pwidth, int *pheight)
1545 int width, height;
1547 #ifdef CONFIG_BOCHS_VBE
1548 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1549 width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
1550 height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
1551 } else
1552 #endif
1554 width = (s->cr[0x01] + 1) * 8;
1555 height = s->cr[0x12] |
1556 ((s->cr[0x07] & 0x02) << 7) |
1557 ((s->cr[0x07] & 0x40) << 3);
1558 height = (height + 1);
1560 *pwidth = width;
1561 *pheight = height;
1564 void vga_invalidate_scanlines(VGAState *s, int y1, int y2)
1566 int y;
1567 if (y1 >= VGA_MAX_HEIGHT)
1568 return;
1569 if (y2 >= VGA_MAX_HEIGHT)
1570 y2 = VGA_MAX_HEIGHT;
1571 for(y = y1; y < y2; y++) {
1572 s->invalidated_y_table[y >> 5] |= 1 << (y & 0x1f);
1576 static void vga_sync_dirty_bitmap(VGAState *s)
1578 if (s->map_addr)
1579 cpu_physical_sync_dirty_bitmap(s->map_addr, s->map_end);
1581 if (s->lfb_vram_mapped) {
1582 cpu_physical_sync_dirty_bitmap(isa_mem_base + 0xa0000, 0xa8000);
1583 cpu_physical_sync_dirty_bitmap(isa_mem_base + 0xa8000, 0xb0000);
1585 vga_dirty_log_start(s);
1588 static void vga_update_resolution_graphics(VGAState *s)
1590 int depth = s->get_bpp(s);
1591 int width, height, shift_control, double_scan;
1592 int disp_width, multi_scan, multi_run;
1594 s->get_resolution(s, &width, &height);
1595 disp_width = width;
1597 shift_control = (s->gr[0x05] >> 5) & 3;
1598 double_scan = (s->cr[0x09] >> 7);
1600 if (shift_control != s->shift_control ||
1601 double_scan != s->double_scan) {
1602 s->want_full_update = 1;
1603 s->shift_control = shift_control;
1604 s->double_scan = double_scan;
1607 if (shift_control == 0) {
1608 if (s->sr[0x01] & 8) {
1609 disp_width <<= 1;
1611 } else if (shift_control == 1) {
1612 if (s->sr[0x01] & 8) {
1613 disp_width <<= 1;
1616 disp_width = width;
1618 if (shift_control != 1) {
1619 multi_scan = (((s->cr[0x09] & 0x1f) + 1) << double_scan) - 1;
1620 } else {
1621 /* in CGA modes, multi_scan is ignored */
1622 /* XXX: is it correct ? */
1623 multi_scan = double_scan;
1626 multi_run = multi_scan;
1628 if (s->line_offset != s->last_line_offset ||
1629 disp_width != s->last_width ||
1630 height != s->last_height ||
1631 s->last_depth != depth ||
1632 s->multi_run != multi_run ||
1633 s->multi_scan != multi_scan ||
1634 s->want_full_update) {
1635 if (s->ds->surface->pf.depth == 0) {
1636 goto dont_touch_display_surface;
1638 #if defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
1639 if (depth == 16 || depth == 32) {
1640 #else
1641 if (depth == 32) {
1642 #endif
1643 qemu_free_displaysurface(s->ds);
1644 s->ds->surface = qemu_create_displaysurface_from(disp_width, height, depth,
1645 s->line_offset,
1646 s->vram_ptr + (s->start_addr * 4));
1647 #if defined(WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
1648 s->ds->surface->pf = qemu_different_endianness_pixelformat(depth);
1649 #endif
1650 dpy_resize(s->ds);
1651 } else {
1652 qemu_console_resize(s->ds, disp_width, height);
1654 dont_touch_display_surface:
1655 s->last_scr_width = disp_width;
1656 s->last_scr_height = height;
1657 s->last_width = disp_width;
1658 s->last_height = height;
1659 s->last_line_offset = s->line_offset;
1660 s->last_depth = depth;
1661 s->multi_run = multi_run;
1662 s->multi_scan = multi_scan;
1663 s->want_full_update = 1;
1667 static void vga_update_resolution_text(VGAState *s)
1669 int width, height, cw, cheight;
1671 vga_get_text_resolution(s, &width, &height, &cw, &cheight);
1672 if (width != s->last_width || height != s->last_height ||
1673 cw != s->last_cw || cheight != s->last_ch || s->last_depth) {
1674 s->last_scr_width = width * cw;
1675 s->last_scr_height = height * cheight;
1676 if (s->ds->surface->pf.depth != 0) {
1677 qemu_console_resize(s->ds, s->last_scr_width, s->last_scr_height);
1678 } else {
1680 * curses expects width and height to be in character cell
1681 * dimensions, not pixels.
1683 s->ds->surface->width = width;
1684 s->ds->surface->height = height;
1685 dpy_resize(s->ds);
1687 s->last_depth = 0;
1688 s->last_width = width;
1689 s->last_height = height;
1690 s->last_ch = cheight;
1691 s->last_cw = cw;
1692 s->want_full_update = 1;
1696 void vga_update_resolution(VGAState *s)
1698 int graphic_mode;
1700 if (!(s->ar_index & 0x20)) {
1701 graphic_mode = GMODE_BLANK;
1702 } else {
1703 graphic_mode = s->gr[6] & 1;
1705 if (graphic_mode != s->graphic_mode) {
1706 s->graphic_mode = graphic_mode;
1707 s->want_full_update = 1;
1709 s->want_full_update |= update_basic_params(s);
1710 switch (graphic_mode) {
1711 case GMODE_TEXT:
1712 vga_update_resolution_text(s);
1713 break;
1714 case GMODE_GRAPH:
1715 vga_update_resolution_graphics(s);
1716 break;
1721 * graphic modes
1723 static void vga_draw_graphic(VGAState *s, int full_update)
1725 int y1, y, update, linesize, y_start, mask;
1726 int width, height, line_offset, bwidth, bits;
1727 int multi_run;
1728 uint8_t *d;
1729 uint32_t v, addr1, addr;
1730 long page0, page1, page_min, page_max;
1731 vga_draw_line_func *vga_draw_line;
1733 if (!full_update)
1734 vga_sync_dirty_bitmap(s);
1736 s->get_resolution(s, &width, &height);
1737 multi_run = s->multi_run;
1738 if (is_buffer_shared(s->ds->surface) &&
1739 (full_update || s->ds->surface->data != s->vram_ptr + (s->start_addr * 4))) {
1740 s->ds->surface->data = s->vram_ptr + (s->start_addr * 4);
1741 dpy_setdata(s->ds);
1744 s->rgb_to_pixel =
1745 rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1747 if (s->shift_control == 0) {
1748 full_update |= update_palette16(s);
1749 if (s->sr[0x01] & 8) {
1750 v = VGA_DRAW_LINE4D2;
1751 } else {
1752 v = VGA_DRAW_LINE4;
1754 bits = 4;
1755 } else if (s->shift_control == 1) {
1756 full_update |= update_palette16(s);
1757 if (s->sr[0x01] & 8) {
1758 v = VGA_DRAW_LINE2D2;
1759 } else {
1760 v = VGA_DRAW_LINE2;
1762 bits = 4;
1763 } else {
1764 switch(s->get_bpp(s)) {
1765 default:
1766 case 0:
1767 full_update |= update_palette256(s);
1768 v = VGA_DRAW_LINE8D2;
1769 bits = 4;
1770 break;
1771 case 8:
1772 full_update |= update_palette256(s);
1773 v = VGA_DRAW_LINE8;
1774 bits = 8;
1775 break;
1776 case 15:
1777 v = VGA_DRAW_LINE15;
1778 bits = 16;
1779 break;
1780 case 16:
1781 v = VGA_DRAW_LINE16;
1782 bits = 16;
1783 break;
1784 case 24:
1785 v = VGA_DRAW_LINE24;
1786 bits = 24;
1787 break;
1788 case 32:
1789 v = VGA_DRAW_LINE32;
1790 bits = 32;
1791 break;
1794 vga_draw_line = vga_draw_line_table[v * NB_DEPTHS + get_depth_index(s->ds)];
1796 if (!is_buffer_shared(s->ds->surface) && s->cursor_invalidate)
1797 s->cursor_invalidate(s);
1799 line_offset = s->line_offset;
1800 #if 0
1801 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",
1802 width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]);
1803 #endif
1804 addr1 = (s->start_addr * 4);
1805 bwidth = (width * bits + 7) / 8;
1806 y_start = -1;
1807 page_min = 0x7fffffff;
1808 page_max = -1;
1809 d = ds_get_data(s->ds);
1810 linesize = ds_get_linesize(s->ds);
1811 y1 = 0;
1812 for(y = 0; y < height; y++) {
1813 addr = addr1;
1814 if (!(s->cr[0x17] & 1)) {
1815 int shift;
1816 /* CGA compatibility handling */
1817 shift = 14 + ((s->cr[0x17] >> 6) & 1);
1818 addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
1820 if (!(s->cr[0x17] & 2)) {
1821 addr = (addr & ~0x8000) | ((y1 & 2) << 14);
1823 page0 = s->vram_offset + (addr & TARGET_PAGE_MASK);
1824 page1 = s->vram_offset + ((addr + bwidth - 1) & TARGET_PAGE_MASK);
1825 update = full_update |
1826 cpu_physical_memory_get_dirty(page0, VGA_DIRTY_FLAG) |
1827 cpu_physical_memory_get_dirty(page1, VGA_DIRTY_FLAG);
1828 if ((page1 - page0) > TARGET_PAGE_SIZE) {
1829 /* if wide line, can use another page */
1830 update |= cpu_physical_memory_get_dirty(page0 + TARGET_PAGE_SIZE,
1831 VGA_DIRTY_FLAG);
1833 /* explicit invalidation for the hardware cursor */
1834 update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
1835 if (update) {
1836 if (y_start < 0)
1837 y_start = y;
1838 if (page0 < page_min)
1839 page_min = page0;
1840 if (page1 > page_max)
1841 page_max = page1;
1842 if (!(is_buffer_shared(s->ds->surface))) {
1843 vga_draw_line(s, d, s->vram_ptr + addr, width);
1844 if (s->cursor_draw_line)
1845 s->cursor_draw_line(s, d, y);
1847 } else {
1848 if (y_start >= 0) {
1849 /* flush to display */
1850 dpy_update(s->ds, 0, y_start,
1851 s->last_width, y - y_start);
1852 y_start = -1;
1855 if (!multi_run) {
1856 mask = (s->cr[0x17] & 3) ^ 3;
1857 if ((y1 & mask) == mask)
1858 addr1 += line_offset;
1859 y1++;
1860 multi_run = s->multi_scan;
1861 } else {
1862 multi_run--;
1864 /* line compare acts on the displayed lines */
1865 if (y == s->line_compare)
1866 addr1 = 0;
1867 d += linesize;
1869 if (y_start >= 0) {
1870 /* flush to display */
1871 dpy_update(s->ds, 0, y_start,
1872 s->last_width, y - y_start);
1874 /* reset modified pages */
1875 if (page_max != -1) {
1876 cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
1877 VGA_DIRTY_FLAG);
1879 memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
1882 static void vga_draw_blank(VGAState *s, int full_update)
1884 int i, w, val;
1885 uint8_t *d;
1887 if (!full_update)
1888 return;
1889 if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
1890 return;
1891 vga_dirty_log_stop(s);
1893 s->rgb_to_pixel =
1894 rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1895 if (ds_get_bits_per_pixel(s->ds) == 8)
1896 val = s->rgb_to_pixel(0, 0, 0);
1897 else
1898 val = 0;
1899 w = s->last_scr_width * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
1900 d = ds_get_data(s->ds);
1901 for(i = 0; i < s->last_scr_height; i++) {
1902 memset(d, val, w);
1903 d += ds_get_linesize(s->ds);
1905 dpy_update(s->ds, 0, 0,
1906 s->last_scr_width, s->last_scr_height);
1909 static void vga_update_display(void *opaque)
1911 VGAState *s = (VGAState *)opaque;
1912 int full_update;
1914 if (ds_get_bits_per_pixel(s->ds) == 0) {
1915 /* nothing to do */
1916 } else {
1917 full_update = s->want_full_update;
1918 s->want_full_update = 0;
1919 switch(s->graphic_mode) {
1920 case GMODE_TEXT:
1921 vga_draw_text(s, full_update);
1922 break;
1923 case GMODE_GRAPH:
1924 #ifdef TARGET_IA64
1925 full_update = 1;
1926 #endif
1927 vga_draw_graphic(s, full_update);
1928 break;
1929 case GMODE_BLANK:
1930 default:
1931 vga_draw_blank(s, full_update);
1932 break;
1937 /* force a full display refresh */
1938 static void vga_invalidate_display(void *opaque)
1940 VGAState *s = (VGAState *)opaque;
1942 vga_update_resolution(s);
1943 s->want_full_update = 1;
1946 void vga_reset(void *opaque)
1948 VGAState *s = (VGAState *) opaque;
1950 s->lfb_addr = 0;
1951 s->lfb_end = 0;
1952 s->map_addr = 0;
1953 s->map_end = 0;
1954 s->lfb_vram_mapped = 0;
1955 s->bios_offset = 0;
1956 s->bios_size = 0;
1957 s->sr_index = 0;
1958 memset(s->sr, '\0', sizeof(s->sr));
1959 s->gr_index = 0;
1960 memset(s->gr, '\0', sizeof(s->gr));
1961 s->ar_index = 0;
1962 memset(s->ar, '\0', sizeof(s->ar));
1963 s->ar_flip_flop = 0;
1964 s->cr_index = 0;
1965 memset(s->cr, '\0', sizeof(s->cr));
1966 s->msr = 0;
1967 s->fcr = 0;
1968 s->st00 = 0;
1969 s->st01 = 0;
1970 s->dac_state = 0;
1971 s->dac_sub_index = 0;
1972 s->dac_read_index = 0;
1973 s->dac_write_index = 0;
1974 memset(s->dac_cache, '\0', sizeof(s->dac_cache));
1975 s->dac_8bit = 0;
1976 memset(s->palette, '\0', sizeof(s->palette));
1977 s->bank_offset = 0;
1978 #ifdef CONFIG_BOCHS_VBE
1979 s->vbe_index = 0;
1980 memset(s->vbe_regs, '\0', sizeof(s->vbe_regs));
1981 s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0;
1982 s->vbe_start_addr = 0;
1983 s->vbe_line_offset = 0;
1984 s->vbe_bank_mask = (s->vram_size >> 16) - 1;
1985 #endif
1986 memset(s->font_offsets, '\0', sizeof(s->font_offsets));
1987 s->shift_control = 0;
1988 s->double_scan = 0;
1989 s->line_offset = 0;
1990 s->line_compare = 0;
1991 s->start_addr = 0;
1992 s->plane_updated = 0;
1993 s->last_cw = 0;
1994 s->last_ch = 0;
1995 s->last_width = 0;
1996 s->last_height = 0;
1997 s->last_scr_width = 0;
1998 s->last_scr_height = 0;
1999 s->cursor_start = 0;
2000 s->cursor_end = 0;
2001 s->cursor_offset = 0;
2002 memset(s->invalidated_y_table, '\0', sizeof(s->invalidated_y_table));
2003 memset(s->last_palette, '\0', sizeof(s->last_palette));
2004 memset(s->last_ch_attr, '\0', sizeof(s->last_ch_attr));
2005 switch (vga_retrace_method) {
2006 case VGA_RETRACE_DUMB:
2007 break;
2008 case VGA_RETRACE_PRECISE:
2009 memset(&s->retrace_info, 0, sizeof (s->retrace_info));
2010 break;
2012 vga_update_resolution(s);
2015 #define TEXTMODE_X(x) ((x) % width)
2016 #define TEXTMODE_Y(x) ((x) / width)
2017 #define VMEM2CHTYPE(v) ((v & 0xff0007ff) | \
2018 ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1))
2019 /* relay text rendering to the display driver
2020 * instead of doing a full vga_update_display() */
2021 static void vga_update_text(void *opaque, console_ch_t *chardata)
2023 VGAState *s = (VGAState *) opaque;
2024 int i, cursor_offset, cursor_visible;
2025 int cw, cheight, width, height, size, c_min, c_max;
2026 uint32_t *src;
2027 console_ch_t *dst, val;
2028 char msg_buffer[80];
2029 int full_update = s->want_full_update;
2031 s->want_full_update = 0;
2032 switch (s->graphic_mode) {
2033 case GMODE_TEXT:
2034 /* TODO: update palette */
2036 vga_get_text_resolution(s, &width, &height, &cw, &cheight);
2038 if (s->ds->surface->width != width
2039 || s->ds->surface->height != height) {
2040 s->ds->surface->width = width;
2041 s->ds->surface->height = height;
2042 dpy_resize(s->ds);
2045 /* total width & height */
2046 size = (height * width);
2047 if (size > CH_ATTR_SIZE) {
2048 if (!full_update)
2049 return;
2051 snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Text mode",
2052 width, height);
2053 break;
2056 /* Update "hardware" cursor */
2057 cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
2058 if (cursor_offset != s->cursor_offset ||
2059 s->cr[0xa] != s->cursor_start ||
2060 s->cr[0xb] != s->cursor_end || full_update) {
2061 cursor_visible = !(s->cr[0xa] & 0x20);
2062 if (cursor_visible && cursor_offset < size && cursor_offset >= 0)
2063 dpy_cursor(s->ds,
2064 TEXTMODE_X(cursor_offset),
2065 TEXTMODE_Y(cursor_offset));
2066 else
2067 dpy_cursor(s->ds, -1, -1);
2068 s->cursor_offset = cursor_offset;
2069 s->cursor_start = s->cr[0xa];
2070 s->cursor_end = s->cr[0xb];
2073 src = (uint32_t *) s->vram_ptr + s->start_addr;
2074 dst = chardata;
2076 if (full_update) {
2077 for (i = 0; i < size; src ++, dst ++, i ++)
2078 console_write_ch(dst, VMEM2CHTYPE(*src));
2080 dpy_update(s->ds, 0, 0, width, height);
2081 } else {
2082 c_max = 0;
2084 for (i = 0; i < size; src ++, dst ++, i ++) {
2085 console_write_ch(&val, VMEM2CHTYPE(*src));
2086 if (*dst != val) {
2087 *dst = val;
2088 c_max = i;
2089 break;
2092 c_min = i;
2093 for (; i < size; src ++, dst ++, i ++) {
2094 console_write_ch(&val, VMEM2CHTYPE(*src));
2095 if (*dst != val) {
2096 *dst = val;
2097 c_max = i;
2101 if (c_min <= c_max) {
2102 i = TEXTMODE_Y(c_min);
2103 dpy_update(s->ds, 0, i, width, TEXTMODE_Y(c_max) - i + 1);
2107 return;
2108 case GMODE_GRAPH:
2109 if (!full_update)
2110 return;
2112 s->get_resolution(s, &width, &height);
2113 snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Graphic mode",
2114 width, height);
2115 break;
2116 case GMODE_BLANK:
2117 default:
2118 if (!full_update)
2119 return;
2121 snprintf(msg_buffer, sizeof(msg_buffer), "VGA Blank mode");
2122 break;
2125 /* Display a message */
2126 s->last_width = 60;
2127 s->last_height = height = 3;
2128 dpy_cursor(s->ds, -1, -1);
2129 s->ds->surface->width = s->last_width;
2130 s->ds->surface->height = height;
2131 dpy_resize(s->ds);
2133 for (dst = chardata, i = 0; i < s->last_width * height; i ++)
2134 console_write_ch(dst ++, ' ');
2136 size = strlen(msg_buffer);
2137 width = (s->last_width - size) / 2;
2138 dst = chardata + s->last_width + width;
2139 for (i = 0; i < size; i ++)
2140 console_write_ch(dst ++, 0x00200100 | msg_buffer[i]);
2142 dpy_update(s->ds, 0, 0, s->last_width, height);
2145 static CPUReadMemoryFunc *vga_mem_read[3] = {
2146 vga_mem_readb,
2147 vga_mem_readw,
2148 vga_mem_readl,
2151 static CPUWriteMemoryFunc *vga_mem_write[3] = {
2152 vga_mem_writeb,
2153 vga_mem_writew,
2154 vga_mem_writel,
2157 static void vga_save(QEMUFile *f, void *opaque)
2159 VGAState *s = opaque;
2160 int i;
2162 if (s->pci_dev)
2163 pci_device_save(s->pci_dev, f);
2165 qemu_put_be32s(f, &s->latch);
2166 qemu_put_8s(f, &s->sr_index);
2167 qemu_put_buffer(f, s->sr, 8);
2168 qemu_put_8s(f, &s->gr_index);
2169 qemu_put_buffer(f, s->gr, 16);
2170 qemu_put_8s(f, &s->ar_index);
2171 qemu_put_buffer(f, s->ar, 21);
2172 qemu_put_be32(f, s->ar_flip_flop);
2173 qemu_put_8s(f, &s->cr_index);
2174 qemu_put_buffer(f, s->cr, 256);
2175 qemu_put_8s(f, &s->msr);
2176 qemu_put_8s(f, &s->fcr);
2177 qemu_put_byte(f, s->st00);
2178 qemu_put_8s(f, &s->st01);
2180 qemu_put_8s(f, &s->dac_state);
2181 qemu_put_8s(f, &s->dac_sub_index);
2182 qemu_put_8s(f, &s->dac_read_index);
2183 qemu_put_8s(f, &s->dac_write_index);
2184 qemu_put_buffer(f, s->dac_cache, 3);
2185 qemu_put_buffer(f, s->palette, 768);
2187 qemu_put_be32(f, s->bank_offset);
2188 #ifdef CONFIG_BOCHS_VBE
2189 qemu_put_byte(f, 1);
2190 qemu_put_be16s(f, &s->vbe_index);
2191 for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
2192 qemu_put_be16s(f, &s->vbe_regs[i]);
2193 qemu_put_be32s(f, &s->vbe_start_addr);
2194 qemu_put_be32s(f, &s->vbe_line_offset);
2195 qemu_put_be32s(f, &s->vbe_bank_mask);
2196 #else
2197 qemu_put_byte(f, 0);
2198 #endif
2201 static int vga_load(QEMUFile *f, void *opaque, int version_id)
2203 VGAState *s = opaque;
2204 int is_vbe, i, ret;
2206 if (version_id > 2)
2207 return -EINVAL;
2209 if (s->pci_dev && version_id >= 2) {
2210 ret = pci_device_load(s->pci_dev, f);
2211 if (ret < 0)
2212 return ret;
2215 qemu_get_be32s(f, &s->latch);
2216 qemu_get_8s(f, &s->sr_index);
2217 qemu_get_buffer(f, s->sr, 8);
2218 qemu_get_8s(f, &s->gr_index);
2219 qemu_get_buffer(f, s->gr, 16);
2220 qemu_get_8s(f, &s->ar_index);
2221 qemu_get_buffer(f, s->ar, 21);
2222 s->ar_flip_flop=qemu_get_be32(f);
2223 qemu_get_8s(f, &s->cr_index);
2224 qemu_get_buffer(f, s->cr, 256);
2225 qemu_get_8s(f, &s->msr);
2226 qemu_get_8s(f, &s->fcr);
2227 qemu_get_8s(f, &s->st00);
2228 qemu_get_8s(f, &s->st01);
2230 qemu_get_8s(f, &s->dac_state);
2231 qemu_get_8s(f, &s->dac_sub_index);
2232 qemu_get_8s(f, &s->dac_read_index);
2233 qemu_get_8s(f, &s->dac_write_index);
2234 qemu_get_buffer(f, s->dac_cache, 3);
2235 qemu_get_buffer(f, s->palette, 768);
2237 s->bank_offset=qemu_get_be32(f);
2238 is_vbe = qemu_get_byte(f);
2239 #ifdef CONFIG_BOCHS_VBE
2240 if (!is_vbe)
2241 return -EINVAL;
2242 qemu_get_be16s(f, &s->vbe_index);
2243 for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
2244 qemu_get_be16s(f, &s->vbe_regs[i]);
2245 qemu_get_be32s(f, &s->vbe_start_addr);
2246 qemu_get_be32s(f, &s->vbe_line_offset);
2247 qemu_get_be32s(f, &s->vbe_bank_mask);
2248 #else
2249 if (is_vbe)
2250 return -EINVAL;
2251 #endif
2253 /* force refresh */
2254 vga_update_resolution(s);
2255 s->want_full_update = 1;
2256 return 0;
2259 typedef struct PCIVGAState {
2260 PCIDevice dev;
2261 VGAState vga_state;
2262 } PCIVGAState;
2264 static int s1, s2;
2266 static void mark_dirty(target_phys_addr_t start, target_phys_addr_t len)
2268 target_phys_addr_t end = start + len;
2270 while (start < end) {
2271 cpu_physical_memory_set_dirty(cpu_get_physical_page_desc(start));
2272 start += TARGET_PAGE_SIZE;
2276 void vga_dirty_log_start(VGAState *s)
2278 if (kvm_enabled() && s->map_addr)
2279 if (!s1) {
2280 kvm_log_start(s->map_addr, s->map_end - s->map_addr);
2281 mark_dirty(s->map_addr, s->map_end - s->map_addr);
2282 s1 = 1;
2284 if (kvm_enabled() && s->lfb_vram_mapped) {
2285 if (!s2) {
2286 kvm_log_start(isa_mem_base + 0xa0000, 0x8000);
2287 kvm_log_start(isa_mem_base + 0xa8000, 0x8000);
2288 mark_dirty(isa_mem_base + 0xa0000, 0x10000);
2290 s2 = 1;
2294 void vga_dirty_log_stop(VGAState *s)
2296 if (kvm_enabled() && s->map_addr && s1)
2297 kvm_log_stop(s->map_addr, s->map_end - s->map_addr);
2299 if (kvm_enabled() && s->lfb_vram_mapped && s2) {
2300 kvm_log_stop(isa_mem_base + 0xa0000, 0x8000);
2301 kvm_log_stop(isa_mem_base + 0xa8000, 0x8000);
2303 s1 = s2 = 0;
2306 static void vga_map(PCIDevice *pci_dev, int region_num,
2307 uint32_t addr, uint32_t size, int type)
2309 PCIVGAState *d = (PCIVGAState *)pci_dev;
2310 VGAState *s = &d->vga_state;
2311 if (region_num == PCI_ROM_SLOT) {
2312 cpu_register_physical_memory(addr, s->bios_size, s->bios_offset);
2313 } else {
2314 cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
2317 s->map_addr = addr;
2318 s->map_end = addr + VGA_RAM_SIZE;
2320 vga_dirty_log_start(s);
2323 #ifdef TARGET_IA64
2324 /* do the same job as vgabios before vgabios get ready - yeah */
2325 void vga_bios_init(VGAState *s)
2327 uint8_t palette_model[192] = {
2328 0, 0, 0, 0, 0, 170, 0, 170,
2329 0, 0, 170, 170, 170, 0, 0, 170,
2330 0, 170, 170, 85, 0, 170, 170, 170,
2331 85, 85, 85, 85, 85, 255, 85, 255,
2332 85, 85, 255, 255, 255, 85, 85, 255,
2333 85, 255, 255, 255, 85, 255, 255, 255,
2334 0, 21, 0, 0, 21, 42, 0, 63,
2335 0, 0, 63, 42, 42, 21, 0, 42,
2336 21, 42, 42, 63, 0, 42, 63, 42,
2337 0, 21, 21, 0, 21, 63, 0, 63,
2338 21, 0, 63, 63, 42, 21, 21, 42,
2339 21, 63, 42, 63, 21, 42, 63, 63,
2340 21, 0, 0, 21, 0, 42, 21, 42,
2341 0, 21, 42, 42, 63, 0, 0, 63,
2342 0, 42, 63, 42, 0, 63, 42, 42,
2343 21, 0, 21, 21, 0, 63, 21, 42,
2344 21, 21, 42, 63, 63, 0, 21, 63,
2345 0, 63, 63, 42, 21, 63, 42, 63,
2346 21, 21, 0, 21, 21, 42, 21, 63,
2347 0, 21, 63, 42, 63, 21, 0, 63,
2348 21, 42, 63, 63, 0, 63, 63, 42,
2349 21, 21, 21, 21, 21, 63, 21, 63,
2350 21, 21, 63, 63, 63, 21, 21, 63,
2351 21, 63, 63, 63, 21, 63, 63, 63
2354 s->latch = 0;
2356 s->sr_index = 3;
2357 s->sr[0] = 3;
2358 s->sr[1] = 0;
2359 s->sr[2] = 3;
2360 s->sr[3] = 0;
2361 s->sr[4] = 2;
2362 s->sr[5] = 0;
2363 s->sr[6] = 0;
2364 s->sr[7] = 0;
2366 s->gr_index = 5;
2367 s->gr[0] = 0;
2368 s->gr[1] = 0;
2369 s->gr[2] = 0;
2370 s->gr[3] = 0;
2371 s->gr[4] = 0;
2372 s->gr[5] = 16;
2373 s->gr[6] = 14;
2374 s->gr[7] = 15;
2375 s->gr[8] = 255;
2377 /* changed by out 0x03c0 */
2378 s->ar_index = 32;
2379 s->ar[0] = 0;
2380 s->ar[1] = 1;
2381 s->ar[2] = 2;
2382 s->ar[3] = 3;
2383 s->ar[4] = 4;
2384 s->ar[5] = 5;
2385 s->ar[6] = 6;
2386 s->ar[7] = 7;
2387 s->ar[8] = 8;
2388 s->ar[9] = 9;
2389 s->ar[10] = 10;
2390 s->ar[11] = 11;
2391 s->ar[12] = 12;
2392 s->ar[13] = 13;
2393 s->ar[14] = 14;
2394 s->ar[15] = 15;
2395 s->ar[16] = 12;
2396 s->ar[17] = 0;
2397 s->ar[18] = 15;
2398 s->ar[19] = 8;
2399 s->ar[20] = 0;
2401 s->ar_flip_flop = 1;
2403 s->cr_index = 15;
2404 s->cr[0] = 95;
2405 s->cr[1] = 79;
2406 s->cr[2] = 80;
2407 s->cr[3] = 130;
2408 s->cr[4] = 85;
2409 s->cr[5] = 129;
2410 s->cr[6] = 191;
2411 s->cr[7] = 31;
2412 s->cr[8] = 0;
2413 s->cr[9] = 79;
2414 s->cr[10] = 14;
2415 s->cr[11] = 15;
2416 s->cr[12] = 0;
2417 s->cr[13] = 0;
2418 s->cr[14] = 5;
2419 s->cr[15] = 160;
2420 s->cr[16] = 156;
2421 s->cr[17] = 142;
2422 s->cr[18] = 143;
2423 s->cr[19] = 40;
2424 s->cr[20] = 31;
2425 s->cr[21] = 150;
2426 s->cr[22] = 185;
2427 s->cr[23] = 163;
2428 s->cr[24] = 255;
2430 s->msr = 103;
2431 s->fcr = 0;
2432 s->st00 = 0;
2433 s->st01 = 0;
2435 /* dac_* & palette will be initialized by os through out 0x03c8 &
2436 * out 0c03c9(1:3) */
2437 s->dac_state = 0;
2438 s->dac_sub_index = 0;
2439 s->dac_read_index = 0;
2440 s->dac_write_index = 16;
2441 s->dac_cache[0] = 255;
2442 s->dac_cache[1] = 255;
2443 s->dac_cache[2] = 255;
2445 /* palette */
2446 memcpy(s->palette, palette_model, 192);
2448 s->bank_offset = 0;
2449 s->graphic_mode = -1;
2451 vga_update_resolution(s);
2453 /* TODO: add vbe support if enabled */
2455 #endif
2457 void vga_common_init(VGAState *s, uint8_t *vga_ram_base,
2458 ram_addr_t vga_ram_offset, int vga_ram_size)
2460 int i, j, v, b;
2462 for(i = 0;i < 256; i++) {
2463 v = 0;
2464 for(j = 0; j < 8; j++) {
2465 v |= ((i >> j) & 1) << (j * 4);
2467 expand4[i] = v;
2469 v = 0;
2470 for(j = 0; j < 4; j++) {
2471 v |= ((i >> (2 * j)) & 3) << (j * 4);
2473 expand2[i] = v;
2475 for(i = 0; i < 16; i++) {
2476 v = 0;
2477 for(j = 0; j < 4; j++) {
2478 b = ((i >> j) & 1);
2479 v |= b << (2 * j);
2480 v |= b << (2 * j + 1);
2482 expand4to8[i] = v;
2485 s->vram_ptr = vga_ram_base;
2486 s->vram_offset = vga_ram_offset;
2487 s->vram_size = vga_ram_size;
2488 s->get_bpp = vga_get_bpp;
2489 s->get_offsets = vga_get_offsets;
2490 s->get_resolution = vga_get_resolution;
2491 s->update = vga_update_display;
2492 s->invalidate = vga_invalidate_display;
2493 s->screen_dump = vga_screen_dump;
2494 s->text_update = vga_update_text;
2495 switch (vga_retrace_method) {
2496 case VGA_RETRACE_DUMB:
2497 s->retrace = vga_dumb_retrace;
2498 s->update_retrace_info = vga_dumb_update_retrace_info;
2499 break;
2501 case VGA_RETRACE_PRECISE:
2502 s->retrace = vga_precise_retrace;
2503 s->update_retrace_info = vga_precise_update_retrace_info;
2504 break;
2506 vga_reset(s);
2507 #ifdef TARGET_IA64
2508 vga_bios_init(s);
2509 #endif
2512 /* used by both ISA and PCI */
2513 void vga_init(VGAState *s)
2515 int vga_io_memory;
2517 qemu_register_reset(vga_reset, s);
2518 register_savevm("vga", 0, 2, vga_save, vga_load, s);
2520 register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
2522 register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
2523 register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);
2524 register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);
2525 register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);
2527 register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
2529 register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);
2530 register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);
2531 register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
2532 register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
2533 s->bank_offset = 0;
2535 #ifdef CONFIG_BOCHS_VBE
2536 #if defined (TARGET_I386)
2537 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
2538 register_ioport_read(0x1cf, 1, 2, vbe_ioport_read_data, s);
2540 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
2541 register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data, s);
2543 /* old Bochs IO ports */
2544 register_ioport_read(0xff80, 1, 2, vbe_ioport_read_index, s);
2545 register_ioport_read(0xff81, 1, 2, vbe_ioport_read_data, s);
2547 register_ioport_write(0xff80, 1, 2, vbe_ioport_write_index, s);
2548 register_ioport_write(0xff81, 1, 2, vbe_ioport_write_data, s);
2549 #else
2550 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
2551 register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data, s);
2553 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
2554 register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data, s);
2555 #endif
2556 #endif /* CONFIG_BOCHS_VBE */
2558 vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s);
2559 cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
2560 vga_io_memory);
2561 qemu_register_coalesced_mmio(isa_mem_base + 0x000a0000, 0x20000);
2564 /* Memory mapped interface */
2565 static uint32_t vga_mm_readb (void *opaque, target_phys_addr_t addr)
2567 VGAState *s = opaque;
2569 return vga_ioport_read(s, addr >> s->it_shift) & 0xff;
2572 static void vga_mm_writeb (void *opaque,
2573 target_phys_addr_t addr, uint32_t value)
2575 VGAState *s = opaque;
2577 vga_ioport_write(s, addr >> s->it_shift, value & 0xff);
2580 static uint32_t vga_mm_readw (void *opaque, target_phys_addr_t addr)
2582 VGAState *s = opaque;
2584 return vga_ioport_read(s, addr >> s->it_shift) & 0xffff;
2587 static void vga_mm_writew (void *opaque,
2588 target_phys_addr_t addr, uint32_t value)
2590 VGAState *s = opaque;
2592 vga_ioport_write(s, addr >> s->it_shift, value & 0xffff);
2595 static uint32_t vga_mm_readl (void *opaque, target_phys_addr_t addr)
2597 VGAState *s = opaque;
2599 return vga_ioport_read(s, addr >> s->it_shift);
2602 static void vga_mm_writel (void *opaque,
2603 target_phys_addr_t addr, uint32_t value)
2605 VGAState *s = opaque;
2607 vga_ioport_write(s, addr >> s->it_shift, value);
2610 static CPUReadMemoryFunc *vga_mm_read_ctrl[] = {
2611 &vga_mm_readb,
2612 &vga_mm_readw,
2613 &vga_mm_readl,
2616 static CPUWriteMemoryFunc *vga_mm_write_ctrl[] = {
2617 &vga_mm_writeb,
2618 &vga_mm_writew,
2619 &vga_mm_writel,
2622 static void vga_mm_init(VGAState *s, target_phys_addr_t vram_base,
2623 target_phys_addr_t ctrl_base, int it_shift)
2625 int s_ioport_ctrl, vga_io_memory;
2627 s->it_shift = it_shift;
2628 s_ioport_ctrl = cpu_register_io_memory(0, vga_mm_read_ctrl, vga_mm_write_ctrl, s);
2629 vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s);
2631 register_savevm("vga", 0, 2, vga_save, vga_load, s);
2633 cpu_register_physical_memory(ctrl_base, 0x100000, s_ioport_ctrl);
2634 s->bank_offset = 0;
2635 cpu_register_physical_memory(vram_base + 0x000a0000, 0x20000, vga_io_memory);
2636 qemu_register_coalesced_mmio(vram_base + 0x000a0000, 0x20000);
2639 int isa_vga_init(uint8_t *vga_ram_base,
2640 unsigned long vga_ram_offset, int vga_ram_size)
2642 VGAState *s;
2644 s = qemu_mallocz(sizeof(VGAState));
2646 vga_common_init(s, vga_ram_base, vga_ram_offset, vga_ram_size);
2647 vga_init(s);
2649 s->ds = graphic_console_init(s->update, s->invalidate,
2650 s->screen_dump, s->text_update, s);
2652 #ifdef CONFIG_BOCHS_VBE
2653 /* XXX: use optimized standard vga accesses */
2654 cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
2655 vga_ram_size, vga_ram_offset);
2656 #endif
2657 return 0;
2660 int isa_vga_mm_init(uint8_t *vga_ram_base,
2661 unsigned long vga_ram_offset, int vga_ram_size,
2662 target_phys_addr_t vram_base, target_phys_addr_t ctrl_base,
2663 int it_shift)
2665 VGAState *s;
2667 s = qemu_mallocz(sizeof(VGAState));
2669 vga_common_init(s, vga_ram_base, vga_ram_offset, vga_ram_size);
2670 vga_mm_init(s, vram_base, ctrl_base, it_shift);
2672 s->ds = graphic_console_init(s->update, s->invalidate,
2673 s->screen_dump, s->text_update, s);
2675 #ifdef CONFIG_BOCHS_VBE
2676 /* XXX: use optimized standard vga accesses */
2677 cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
2678 vga_ram_size, vga_ram_offset);
2679 #endif
2680 return 0;
2683 static void pci_vga_write_config(PCIDevice *d,
2684 uint32_t address, uint32_t val, int len)
2686 PCIVGAState *pvs = container_of(d, PCIVGAState, dev);
2687 VGAState *s = &pvs->vga_state;
2689 vga_dirty_log_stop(s);
2690 pci_default_write_config(d, address, val, len);
2691 if (s->map_addr && pvs->dev.io_regions[0].addr == -1)
2692 s->map_addr = 0;
2693 vga_dirty_log_start(s);
2696 int pci_vga_init(PCIBus *bus, uint8_t *vga_ram_base,
2697 unsigned long vga_ram_offset, int vga_ram_size,
2698 unsigned long vga_bios_offset, int vga_bios_size)
2700 PCIVGAState *d;
2701 VGAState *s;
2702 uint8_t *pci_conf;
2704 d = (PCIVGAState *)pci_register_device(bus, "VGA",
2705 sizeof(PCIVGAState),
2706 -1, NULL, pci_vga_write_config);
2707 if (!d)
2708 return -1;
2709 s = &d->vga_state;
2711 vga_common_init(s, vga_ram_base, vga_ram_offset, vga_ram_size);
2712 vga_init(s);
2714 s->ds = graphic_console_init(s->update, s->invalidate,
2715 s->screen_dump, s->text_update, s);
2717 s->pci_dev = &d->dev;
2719 pci_conf = d->dev.config;
2720 // dummy VGA (same as Bochs ID)
2721 pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_QEMU);
2722 pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_QEMU_VGA);
2723 pci_config_set_class(pci_conf, PCI_CLASS_DISPLAY_VGA);
2724 pci_conf[0x0e] = 0x00; // header_type
2726 /* XXX: vga_ram_size must be a power of two */
2727 pci_register_io_region(&d->dev, 0, vga_ram_size,
2728 PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
2729 if (vga_bios_size != 0) {
2730 unsigned int bios_total_size;
2731 s->bios_offset = vga_bios_offset;
2732 s->bios_size = vga_bios_size;
2733 /* must be a power of two */
2734 bios_total_size = 1;
2735 while (bios_total_size < vga_bios_size)
2736 bios_total_size <<= 1;
2737 pci_register_io_region(&d->dev, PCI_ROM_SLOT, bios_total_size,
2738 PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
2740 return 0;
2743 /********************************************************/
2744 /* vga screen dump */
2746 static void vga_save_dpy_update(DisplayState *s,
2747 int x, int y, int w, int h)
2751 static void vga_save_dpy_resize(DisplayState *s)
2755 static void vga_save_dpy_refresh(DisplayState *s)
2759 int ppm_save(const char *filename, struct DisplaySurface *ds)
2761 FILE *f;
2762 uint8_t *d, *d1;
2763 uint32_t v;
2764 int y, x;
2765 uint8_t r, g, b;
2767 f = fopen(filename, "wb");
2768 if (!f)
2769 return -1;
2770 fprintf(f, "P6\n%d %d\n%d\n",
2771 ds->width, ds->height, 255);
2772 d1 = ds->data;
2773 for(y = 0; y < ds->height; y++) {
2774 d = d1;
2775 for(x = 0; x < ds->width; x++) {
2776 if (ds->pf.bits_per_pixel == 32)
2777 v = *(uint32_t *)d;
2778 else
2779 v = (uint32_t) (*(uint16_t *)d);
2780 r = ((v >> ds->pf.rshift) & ds->pf.rmax) * 256 /
2781 (ds->pf.rmax + 1);
2782 g = ((v >> ds->pf.gshift) & ds->pf.gmax) * 256 /
2783 (ds->pf.gmax + 1);
2784 b = ((v >> ds->pf.bshift) & ds->pf.bmax) * 256 /
2785 (ds->pf.bmax + 1);
2786 fputc(r, f);
2787 fputc(g, f);
2788 fputc(b, f);
2789 d += ds->pf.bytes_per_pixel;
2791 d1 += ds->linesize;
2793 fclose(f);
2794 return 0;
2797 static void vga_screen_dump_blank(VGAState *s, const char *filename)
2799 FILE *f;
2800 unsigned int y, x, w, h;
2802 w = s->last_scr_width * sizeof(uint32_t);
2803 h = s->last_scr_height;
2805 f = fopen(filename, "wb");
2806 if (!f)
2807 return;
2808 fprintf(f, "P6\n%d %d\n%d\n", w, h, 255);
2809 for (y = 0; y < h; y++) {
2810 for (x = 0; x < w; x++) {
2811 fputc(0, f);
2814 fclose(f);
2817 static void vga_screen_dump_common(VGAState *s, const char *filename,
2818 int w, int h)
2820 DisplayState *saved_ds, ds1, *ds = &ds1;
2821 DisplayChangeListener dcl;
2823 /* XXX: this is a little hackish */
2824 vga_invalidate_display(s);
2825 saved_ds = s->ds;
2827 memset(ds, 0, sizeof(DisplayState));
2828 memset(&dcl, 0, sizeof(DisplayChangeListener));
2829 dcl.dpy_update = vga_save_dpy_update;
2830 dcl.dpy_resize = vga_save_dpy_resize;
2831 dcl.dpy_refresh = vga_save_dpy_refresh;
2832 register_displaychangelistener(ds, &dcl);
2833 ds->allocator = &default_allocator;
2834 ds->surface = qemu_create_displaysurface(ds, w, h);
2836 s->ds = ds;
2837 vga_update_resolution(s);
2838 s->want_full_update = 1;
2839 vga_update_display(s);
2841 ppm_save(filename, ds->surface);
2843 qemu_free_displaysurface(ds);
2844 s->ds = saved_ds;
2847 static void vga_screen_dump_graphic(VGAState *s, const char *filename)
2849 int w, h;
2851 s->get_resolution(s, &w, &h);
2852 vga_screen_dump_common(s, filename, w, h);
2855 static void vga_screen_dump_text(VGAState *s, const char *filename)
2857 int w, h, cwidth, cheight;
2859 vga_get_text_resolution(s, &w, &h, &cwidth, &cheight);
2860 vga_screen_dump_common(s, filename, w * cwidth, h * cheight);
2863 /* save the vga display in a PPM image even if no display is
2864 available */
2865 static void vga_screen_dump(void *opaque, const char *filename)
2867 VGAState *s = (VGAState *)opaque;
2869 switch (s->graphic_mode) {
2870 case GMODE_TEXT:
2871 vga_screen_dump_text(s, filename);
2872 break;
2873 case GMODE_GRAPH:
2874 vga_screen_dump_graphic(s, filename);
2875 break;
2876 case GMODE_BLANK:
2877 default:
2878 vga_screen_dump_blank(s, filename);
2879 break;