Merge remote-tracking branch 'qemu/master'
[qemu/ar7.git] / hw / display / vga.c
blob269d01ad57342a9ed9e645cf692ebf396c461745
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/hw.h"
25 #include "vga.h"
26 #include "ui/console.h"
27 #include "hw/i386/pc.h"
28 #include "hw/pci/pci.h"
29 #include "vga_int.h"
30 #include "ui/pixel_ops.h"
31 #include "qemu/timer.h"
32 #include "hw/xen/xen.h"
33 #include "trace.h"
35 //#define DEBUG_VGA
36 //#define DEBUG_VGA_MEM
37 //#define DEBUG_VGA_REG
39 //#define DEBUG_BOCHS_VBE
41 /* 16 state changes per vertical frame @60 Hz */
42 #define VGA_TEXT_CURSOR_PERIOD_MS (1000 * 2 * 16 / 60)
45 * Video Graphics Array (VGA)
47 * Chipset docs for original IBM VGA:
48 * http://www.mcamafia.de/pdf/ibm_vgaxga_trm2.pdf
50 * FreeVGA site:
51 * http://www.osdever.net/FreeVGA/home.htm
53 * Standard VGA features and Bochs VBE extensions are implemented.
56 /* force some bits to zero */
57 const uint8_t sr_mask[8] = {
58 0x03,
59 0x3d,
60 0x0f,
61 0x3f,
62 0x0e,
63 0x00,
64 0x00,
65 0xff,
68 const uint8_t gr_mask[16] = {
69 0x0f, /* 0x00 */
70 0x0f, /* 0x01 */
71 0x0f, /* 0x02 */
72 0x1f, /* 0x03 */
73 0x03, /* 0x04 */
74 0x7b, /* 0x05 */
75 0x0f, /* 0x06 */
76 0x0f, /* 0x07 */
77 0xff, /* 0x08 */
78 0x00, /* 0x09 */
79 0x00, /* 0x0a */
80 0x00, /* 0x0b */
81 0x00, /* 0x0c */
82 0x00, /* 0x0d */
83 0x00, /* 0x0e */
84 0x00, /* 0x0f */
87 #define cbswap_32(__x) \
88 ((uint32_t)( \
89 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
90 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
91 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
92 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
94 #ifdef HOST_WORDS_BIGENDIAN
95 #define PAT(x) cbswap_32(x)
96 #else
97 #define PAT(x) (x)
98 #endif
100 #ifdef HOST_WORDS_BIGENDIAN
101 #define BIG 1
102 #else
103 #define BIG 0
104 #endif
106 #ifdef HOST_WORDS_BIGENDIAN
107 #define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
108 #else
109 #define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
110 #endif
112 static const uint32_t mask16[16] = {
113 PAT(0x00000000),
114 PAT(0x000000ff),
115 PAT(0x0000ff00),
116 PAT(0x0000ffff),
117 PAT(0x00ff0000),
118 PAT(0x00ff00ff),
119 PAT(0x00ffff00),
120 PAT(0x00ffffff),
121 PAT(0xff000000),
122 PAT(0xff0000ff),
123 PAT(0xff00ff00),
124 PAT(0xff00ffff),
125 PAT(0xffff0000),
126 PAT(0xffff00ff),
127 PAT(0xffffff00),
128 PAT(0xffffffff),
131 #undef PAT
133 #ifdef HOST_WORDS_BIGENDIAN
134 #define PAT(x) (x)
135 #else
136 #define PAT(x) cbswap_32(x)
137 #endif
139 static const uint32_t dmask16[16] = {
140 PAT(0x00000000),
141 PAT(0x000000ff),
142 PAT(0x0000ff00),
143 PAT(0x0000ffff),
144 PAT(0x00ff0000),
145 PAT(0x00ff00ff),
146 PAT(0x00ffff00),
147 PAT(0x00ffffff),
148 PAT(0xff000000),
149 PAT(0xff0000ff),
150 PAT(0xff00ff00),
151 PAT(0xff00ffff),
152 PAT(0xffff0000),
153 PAT(0xffff00ff),
154 PAT(0xffffff00),
155 PAT(0xffffffff),
158 static const uint32_t dmask4[4] = {
159 PAT(0x00000000),
160 PAT(0x0000ffff),
161 PAT(0xffff0000),
162 PAT(0xffffffff),
165 static uint32_t expand4[256];
166 static uint16_t expand2[256];
167 static uint8_t expand4to8[16];
169 static void vga_update_memory_access(VGACommonState *s)
171 hwaddr base, offset, size;
173 if (s->legacy_address_space == NULL) {
174 return;
177 if (s->has_chain4_alias) {
178 memory_region_del_subregion(s->legacy_address_space, &s->chain4_alias);
179 object_unparent(OBJECT(&s->chain4_alias));
180 s->has_chain4_alias = false;
181 s->plane_updated = 0xf;
183 if ((s->sr[VGA_SEQ_PLANE_WRITE] & VGA_SR02_ALL_PLANES) ==
184 VGA_SR02_ALL_PLANES && s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
185 offset = 0;
186 switch ((s->gr[VGA_GFX_MISC] >> 2) & 3) {
187 case 0:
188 base = 0xa0000;
189 size = 0x20000;
190 break;
191 case 1:
192 base = 0xa0000;
193 size = 0x10000;
194 offset = s->bank_offset;
195 break;
196 case 2:
197 base = 0xb0000;
198 size = 0x8000;
199 break;
200 case 3:
201 default:
202 base = 0xb8000;
203 size = 0x8000;
204 break;
206 base += isa_mem_base;
207 memory_region_init_alias(&s->chain4_alias, memory_region_owner(&s->vram),
208 "vga.chain4", &s->vram, offset, size);
209 memory_region_add_subregion_overlap(s->legacy_address_space, base,
210 &s->chain4_alias, 2);
211 s->has_chain4_alias = true;
215 static void vga_dumb_update_retrace_info(VGACommonState *s)
217 (void) s;
220 static void vga_precise_update_retrace_info(VGACommonState *s)
222 int htotal_chars;
223 int hretr_start_char;
224 int hretr_skew_chars;
225 int hretr_end_char;
227 int vtotal_lines;
228 int vretr_start_line;
229 int vretr_end_line;
231 int dots;
232 #if 0
233 int div2, sldiv2;
234 #endif
235 int clocking_mode;
236 int clock_sel;
237 const int clk_hz[] = {25175000, 28322000, 25175000, 25175000};
238 int64_t chars_per_sec;
239 struct vga_precise_retrace *r = &s->retrace_info.precise;
241 htotal_chars = s->cr[VGA_CRTC_H_TOTAL] + 5;
242 hretr_start_char = s->cr[VGA_CRTC_H_SYNC_START];
243 hretr_skew_chars = (s->cr[VGA_CRTC_H_SYNC_END] >> 5) & 3;
244 hretr_end_char = s->cr[VGA_CRTC_H_SYNC_END] & 0x1f;
246 vtotal_lines = (s->cr[VGA_CRTC_V_TOTAL] |
247 (((s->cr[VGA_CRTC_OVERFLOW] & 1) |
248 ((s->cr[VGA_CRTC_OVERFLOW] >> 4) & 2)) << 8)) + 2;
249 vretr_start_line = s->cr[VGA_CRTC_V_SYNC_START] |
250 ((((s->cr[VGA_CRTC_OVERFLOW] >> 2) & 1) |
251 ((s->cr[VGA_CRTC_OVERFLOW] >> 6) & 2)) << 8);
252 vretr_end_line = s->cr[VGA_CRTC_V_SYNC_END] & 0xf;
254 clocking_mode = (s->sr[VGA_SEQ_CLOCK_MODE] >> 3) & 1;
255 clock_sel = (s->msr >> 2) & 3;
256 dots = (s->msr & 1) ? 8 : 9;
258 chars_per_sec = clk_hz[clock_sel] / dots;
260 htotal_chars <<= clocking_mode;
262 r->total_chars = vtotal_lines * htotal_chars;
263 if (r->freq) {
264 r->ticks_per_char = get_ticks_per_sec() / (r->total_chars * r->freq);
265 } else {
266 r->ticks_per_char = get_ticks_per_sec() / chars_per_sec;
269 r->vstart = vretr_start_line;
270 r->vend = r->vstart + vretr_end_line + 1;
272 r->hstart = hretr_start_char + hretr_skew_chars;
273 r->hend = r->hstart + hretr_end_char + 1;
274 r->htotal = htotal_chars;
276 #if 0
277 div2 = (s->cr[VGA_CRTC_MODE] >> 2) & 1;
278 sldiv2 = (s->cr[VGA_CRTC_MODE] >> 3) & 1;
279 fprintf(stderr,
280 "hz=%f\n"
281 "htotal = %d\n"
282 "hretr_start = %d\n"
283 "hretr_skew = %d\n"
284 "hretr_end = %d\n"
285 "vtotal = %d\n"
286 "vretr_start = %d\n"
287 "vretr_end = %d\n"
288 "div2 = %d sldiv2 = %d\n"
289 "clocking_mode = %d\n"
290 "clock_sel = %d %d\n"
291 "dots = %d\n"
292 "ticks/char = %" PRId64 "\n"
293 "\n",
294 (double) get_ticks_per_sec() / (r->ticks_per_char * r->total_chars),
295 htotal_chars,
296 hretr_start_char,
297 hretr_skew_chars,
298 hretr_end_char,
299 vtotal_lines,
300 vretr_start_line,
301 vretr_end_line,
302 div2, sldiv2,
303 clocking_mode,
304 clock_sel,
305 clk_hz[clock_sel],
306 dots,
307 r->ticks_per_char
309 #endif
312 static uint8_t vga_precise_retrace(VGACommonState *s)
314 struct vga_precise_retrace *r = &s->retrace_info.precise;
315 uint8_t val = s->st01 & ~(ST01_V_RETRACE | ST01_DISP_ENABLE);
317 if (r->total_chars) {
318 int cur_line, cur_line_char, cur_char;
319 int64_t cur_tick;
321 cur_tick = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
323 cur_char = (cur_tick / r->ticks_per_char) % r->total_chars;
324 cur_line = cur_char / r->htotal;
326 if (cur_line >= r->vstart && cur_line <= r->vend) {
327 val |= ST01_V_RETRACE | ST01_DISP_ENABLE;
328 } else {
329 cur_line_char = cur_char % r->htotal;
330 if (cur_line_char >= r->hstart && cur_line_char <= r->hend) {
331 val |= ST01_DISP_ENABLE;
335 return val;
336 } else {
337 return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
341 static uint8_t vga_dumb_retrace(VGACommonState *s)
343 return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
346 int vga_ioport_invalid(VGACommonState *s, uint32_t addr)
348 if (s->msr & VGA_MIS_COLOR) {
349 /* Color */
350 return (addr >= 0x3b0 && addr <= 0x3bf);
351 } else {
352 /* Monochrome */
353 return (addr >= 0x3d0 && addr <= 0x3df);
357 uint32_t vga_ioport_read(void *opaque, uint32_t addr)
359 VGACommonState *s = opaque;
360 int val, index;
362 if (vga_ioport_invalid(s, addr)) {
363 val = 0xff;
364 } else {
365 switch(addr) {
366 case VGA_ATT_W:
367 if (s->ar_flip_flop == 0) {
368 val = s->ar_index;
369 } else {
370 val = 0;
372 break;
373 case VGA_ATT_R:
374 index = s->ar_index & 0x1f;
375 if (index < VGA_ATT_C) {
376 val = s->ar[index];
377 } else {
378 val = 0;
380 break;
381 case VGA_MIS_W:
382 val = s->st00;
383 break;
384 case VGA_SEQ_I:
385 val = s->sr_index;
386 break;
387 case VGA_SEQ_D:
388 val = s->sr[s->sr_index];
389 #ifdef DEBUG_VGA_REG
390 fprintf(stderr, "vga: read SR%x = 0x%02x\n", s->sr_index, val);
391 #endif
392 break;
393 case VGA_PEL_IR:
394 val = s->dac_state;
395 break;
396 case VGA_PEL_IW:
397 val = s->dac_write_index;
398 break;
399 case VGA_PEL_D:
400 val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
401 if (++s->dac_sub_index == 3) {
402 s->dac_sub_index = 0;
403 s->dac_read_index++;
405 break;
406 case VGA_FTC_R:
407 val = s->fcr;
408 break;
409 case VGA_MIS_R:
410 val = s->msr;
411 break;
412 case VGA_GFX_I:
413 val = s->gr_index;
414 break;
415 case VGA_GFX_D:
416 val = s->gr[s->gr_index];
417 #ifdef DEBUG_VGA_REG
418 fprintf(stderr, "vga: read GR%x = 0x%02x\n", s->gr_index, val);
419 #endif
420 break;
421 case VGA_CRT_IM:
422 case VGA_CRT_IC:
423 val = s->cr_index;
424 break;
425 case VGA_CRT_DM:
426 case VGA_CRT_DC:
427 val = s->cr[s->cr_index];
428 #ifdef DEBUG_VGA_REG
429 fprintf(stderr, "vga: read CR%x = 0x%02x\n", s->cr_index, val);
430 #endif
431 break;
432 case VGA_IS1_RM:
433 case VGA_IS1_RC:
434 /* just toggle to fool polling */
435 val = s->st01 = s->retrace(s);
436 s->ar_flip_flop = 0;
437 break;
438 default:
439 val = 0x00;
440 break;
443 #if defined(DEBUG_VGA)
444 fprintf(stderr, "VGA: read addr=0x%04x data=0x%02x\n", addr, val);
445 #endif
446 return val;
449 void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
451 VGACommonState *s = opaque;
452 int index;
454 /* check port range access depending on color/monochrome mode */
455 if (vga_ioport_invalid(s, addr)) {
456 return;
458 #ifdef DEBUG_VGA
459 fprintf(stderr, "VGA: write addr=0x%04x data=0x%02x\n", addr, val);
460 #endif
462 switch(addr) {
463 case VGA_ATT_W:
464 if (s->ar_flip_flop == 0) {
465 val &= 0x3f;
466 s->ar_index = val;
467 } else {
468 index = s->ar_index & 0x1f;
469 switch(index) {
470 case VGA_ATC_PALETTE0 ... VGA_ATC_PALETTEF:
471 s->ar[index] = val & 0x3f;
472 break;
473 case VGA_ATC_MODE:
474 s->ar[index] = val & ~0x10;
475 break;
476 case VGA_ATC_OVERSCAN:
477 s->ar[index] = val;
478 break;
479 case VGA_ATC_PLANE_ENABLE:
480 s->ar[index] = val & ~0xc0;
481 break;
482 case VGA_ATC_PEL:
483 s->ar[index] = val & ~0xf0;
484 break;
485 case VGA_ATC_COLOR_PAGE:
486 s->ar[index] = val & ~0xf0;
487 break;
488 default:
489 break;
492 s->ar_flip_flop ^= 1;
493 break;
494 case VGA_MIS_W:
495 s->msr = val & ~0x10;
496 s->update_retrace_info(s);
497 break;
498 case VGA_SEQ_I:
499 s->sr_index = val & 7;
500 break;
501 case VGA_SEQ_D:
502 #ifdef DEBUG_VGA_REG
503 fprintf(stderr, "vga: write SR%x = 0x%02x\n", s->sr_index, val);
504 #endif
505 s->sr[s->sr_index] = val & sr_mask[s->sr_index];
506 if (s->sr_index == VGA_SEQ_CLOCK_MODE) {
507 s->update_retrace_info(s);
509 vga_update_memory_access(s);
510 break;
511 case VGA_PEL_IR:
512 s->dac_read_index = val;
513 s->dac_sub_index = 0;
514 s->dac_state = 3;
515 break;
516 case VGA_PEL_IW:
517 s->dac_write_index = val;
518 s->dac_sub_index = 0;
519 s->dac_state = 0;
520 break;
521 case VGA_PEL_D:
522 s->dac_cache[s->dac_sub_index] = val;
523 if (++s->dac_sub_index == 3) {
524 memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
525 s->dac_sub_index = 0;
526 s->dac_write_index++;
528 break;
529 case VGA_GFX_I:
530 s->gr_index = val & 0x0f;
531 break;
532 case VGA_GFX_D:
533 #ifdef DEBUG_VGA_REG
534 fprintf(stderr, "vga: write GR%x = 0x%02x\n", s->gr_index, val);
535 #endif
536 s->gr[s->gr_index] = val & gr_mask[s->gr_index];
537 vga_update_memory_access(s);
538 break;
539 case VGA_CRT_IM:
540 case VGA_CRT_IC:
541 s->cr_index = val;
542 break;
543 case VGA_CRT_DM:
544 case VGA_CRT_DC:
545 #ifdef DEBUG_VGA_REG
546 fprintf(stderr, "vga: write CR%x = 0x%02x\n", s->cr_index, val);
547 #endif
548 /* handle CR0-7 protection */
549 if ((s->cr[VGA_CRTC_V_SYNC_END] & VGA_CR11_LOCK_CR0_CR7) &&
550 s->cr_index <= VGA_CRTC_OVERFLOW) {
551 /* can always write bit 4 of CR7 */
552 if (s->cr_index == VGA_CRTC_OVERFLOW) {
553 s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x10) |
554 (val & 0x10);
556 return;
558 s->cr[s->cr_index] = val;
560 switch(s->cr_index) {
561 case VGA_CRTC_H_TOTAL:
562 case VGA_CRTC_H_SYNC_START:
563 case VGA_CRTC_H_SYNC_END:
564 case VGA_CRTC_V_TOTAL:
565 case VGA_CRTC_OVERFLOW:
566 case VGA_CRTC_V_SYNC_END:
567 case VGA_CRTC_MODE:
568 s->update_retrace_info(s);
569 break;
571 break;
572 case VGA_IS1_RM:
573 case VGA_IS1_RC:
574 s->fcr = val & 0x10;
575 break;
580 * Sanity check vbe register writes.
582 * As we don't have a way to signal errors to the guest in the bochs
583 * dispi interface we'll go adjust the registers to the closest valid
584 * value.
586 static void vbe_fixup_regs(VGACommonState *s)
588 uint16_t *r = s->vbe_regs;
589 uint32_t bits, linelength, maxy, offset;
591 if (!(r[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
592 /* vbe is turned off -- nothing to do */
593 return;
596 /* check depth */
597 switch (r[VBE_DISPI_INDEX_BPP]) {
598 case 4:
599 case 8:
600 case 16:
601 case 24:
602 case 32:
603 bits = r[VBE_DISPI_INDEX_BPP];
604 break;
605 case 15:
606 bits = 16;
607 break;
608 default:
609 bits = r[VBE_DISPI_INDEX_BPP] = 8;
610 break;
613 /* check width */
614 r[VBE_DISPI_INDEX_XRES] &= ~7u;
615 if (r[VBE_DISPI_INDEX_XRES] == 0) {
616 r[VBE_DISPI_INDEX_XRES] = 8;
618 if (r[VBE_DISPI_INDEX_XRES] > VBE_DISPI_MAX_XRES) {
619 r[VBE_DISPI_INDEX_XRES] = VBE_DISPI_MAX_XRES;
621 r[VBE_DISPI_INDEX_VIRT_WIDTH] &= ~7u;
622 if (r[VBE_DISPI_INDEX_VIRT_WIDTH] > VBE_DISPI_MAX_XRES) {
623 r[VBE_DISPI_INDEX_VIRT_WIDTH] = VBE_DISPI_MAX_XRES;
625 if (r[VBE_DISPI_INDEX_VIRT_WIDTH] < r[VBE_DISPI_INDEX_XRES]) {
626 r[VBE_DISPI_INDEX_VIRT_WIDTH] = r[VBE_DISPI_INDEX_XRES];
629 /* check height */
630 linelength = r[VBE_DISPI_INDEX_VIRT_WIDTH] * bits / 8;
631 maxy = s->vbe_size / linelength;
632 if (r[VBE_DISPI_INDEX_YRES] == 0) {
633 r[VBE_DISPI_INDEX_YRES] = 1;
635 if (r[VBE_DISPI_INDEX_YRES] > VBE_DISPI_MAX_YRES) {
636 r[VBE_DISPI_INDEX_YRES] = VBE_DISPI_MAX_YRES;
638 if (r[VBE_DISPI_INDEX_YRES] > maxy) {
639 r[VBE_DISPI_INDEX_YRES] = maxy;
642 /* check offset */
643 if (r[VBE_DISPI_INDEX_X_OFFSET] > VBE_DISPI_MAX_XRES) {
644 r[VBE_DISPI_INDEX_X_OFFSET] = VBE_DISPI_MAX_XRES;
646 if (r[VBE_DISPI_INDEX_Y_OFFSET] > VBE_DISPI_MAX_YRES) {
647 r[VBE_DISPI_INDEX_Y_OFFSET] = VBE_DISPI_MAX_YRES;
649 offset = r[VBE_DISPI_INDEX_X_OFFSET] * bits / 8;
650 offset += r[VBE_DISPI_INDEX_Y_OFFSET] * linelength;
651 if (offset + r[VBE_DISPI_INDEX_YRES] * linelength > s->vbe_size) {
652 r[VBE_DISPI_INDEX_Y_OFFSET] = 0;
653 offset = r[VBE_DISPI_INDEX_X_OFFSET] * bits / 8;
654 if (offset + r[VBE_DISPI_INDEX_YRES] * linelength > s->vbe_size) {
655 r[VBE_DISPI_INDEX_X_OFFSET] = 0;
656 offset = 0;
660 /* update vga state */
661 r[VBE_DISPI_INDEX_VIRT_HEIGHT] = maxy;
662 s->vbe_line_offset = linelength;
663 s->vbe_start_addr = offset / 4;
666 static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
668 VGACommonState *s = opaque;
669 uint32_t val;
670 val = s->vbe_index;
671 return val;
674 uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr)
676 VGACommonState *s = opaque;
677 uint32_t val;
679 if (s->vbe_index < VBE_DISPI_INDEX_NB) {
680 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_GETCAPS) {
681 switch(s->vbe_index) {
682 /* XXX: do not hardcode ? */
683 case VBE_DISPI_INDEX_XRES:
684 val = VBE_DISPI_MAX_XRES;
685 break;
686 case VBE_DISPI_INDEX_YRES:
687 val = VBE_DISPI_MAX_YRES;
688 break;
689 case VBE_DISPI_INDEX_BPP:
690 val = VBE_DISPI_MAX_BPP;
691 break;
692 default:
693 val = s->vbe_regs[s->vbe_index];
694 break;
696 } else {
697 val = s->vbe_regs[s->vbe_index];
699 } else if (s->vbe_index == VBE_DISPI_INDEX_VIDEO_MEMORY_64K) {
700 val = s->vbe_size / (64 * 1024);
701 } else {
702 val = 0;
704 #ifdef DEBUG_BOCHS_VBE
705 fprintf(stderr, "VBE: read index=0x%x val=0x%x\n", s->vbe_index, val);
706 #endif
707 return val;
710 void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val)
712 VGACommonState *s = opaque;
713 s->vbe_index = val;
716 void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
718 VGACommonState *s = opaque;
720 if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
721 #ifdef DEBUG_BOCHS_VBE
722 fprintf(stderr, "VBE: write index=0x%x val=0x%x\n", s->vbe_index, val);
723 #endif
724 switch(s->vbe_index) {
725 case VBE_DISPI_INDEX_ID:
726 if (val == VBE_DISPI_ID0 ||
727 val == VBE_DISPI_ID1 ||
728 val == VBE_DISPI_ID2 ||
729 val == VBE_DISPI_ID3 ||
730 val == VBE_DISPI_ID4) {
731 s->vbe_regs[s->vbe_index] = val;
733 break;
734 case VBE_DISPI_INDEX_XRES:
735 case VBE_DISPI_INDEX_YRES:
736 case VBE_DISPI_INDEX_BPP:
737 case VBE_DISPI_INDEX_VIRT_WIDTH:
738 case VBE_DISPI_INDEX_X_OFFSET:
739 case VBE_DISPI_INDEX_Y_OFFSET:
740 s->vbe_regs[s->vbe_index] = val;
741 vbe_fixup_regs(s);
742 break;
743 case VBE_DISPI_INDEX_BANK:
744 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
745 val &= (s->vbe_bank_mask >> 2);
746 } else {
747 val &= s->vbe_bank_mask;
749 s->vbe_regs[s->vbe_index] = val;
750 s->bank_offset = (val << 16);
751 vga_update_memory_access(s);
752 break;
753 case VBE_DISPI_INDEX_ENABLE:
754 if ((val & VBE_DISPI_ENABLED) &&
755 !(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
756 int h, shift_control;
758 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = 0;
759 s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
760 s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
761 s->vbe_regs[VBE_DISPI_INDEX_ENABLE] |= VBE_DISPI_ENABLED;
762 vbe_fixup_regs(s);
764 /* clear the screen */
765 if (!(val & VBE_DISPI_NOCLEARMEM)) {
766 memset(s->vram_ptr, 0,
767 s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
770 /* we initialize the VGA graphic mode */
771 /* graphic mode + memory map 1 */
772 s->gr[VGA_GFX_MISC] = (s->gr[VGA_GFX_MISC] & ~0x0c) | 0x04 |
773 VGA_GR06_GRAPHICS_MODE;
774 s->cr[VGA_CRTC_MODE] |= 3; /* no CGA modes */
775 s->cr[VGA_CRTC_OFFSET] = s->vbe_line_offset >> 3;
776 /* width */
777 s->cr[VGA_CRTC_H_DISP] =
778 (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
779 /* height (only meaningful if < 1024) */
780 h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
781 s->cr[VGA_CRTC_V_DISP_END] = h;
782 s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x42) |
783 ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
784 /* line compare to 1023 */
785 s->cr[VGA_CRTC_LINE_COMPARE] = 0xff;
786 s->cr[VGA_CRTC_OVERFLOW] |= 0x10;
787 s->cr[VGA_CRTC_MAX_SCAN] |= 0x40;
789 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
790 shift_control = 0;
791 s->sr[VGA_SEQ_CLOCK_MODE] &= ~8; /* no double line */
792 } else {
793 shift_control = 2;
794 /* set chain 4 mode */
795 s->sr[VGA_SEQ_MEMORY_MODE] |= VGA_SR04_CHN_4M;
796 /* activate all planes */
797 s->sr[VGA_SEQ_PLANE_WRITE] |= VGA_SR02_ALL_PLANES;
799 s->gr[VGA_GFX_MODE] = (s->gr[VGA_GFX_MODE] & ~0x60) |
800 (shift_control << 5);
801 s->cr[VGA_CRTC_MAX_SCAN] &= ~0x9f; /* no double scan */
802 } else {
803 s->bank_offset = 0;
805 s->dac_8bit = (val & VBE_DISPI_8BIT_DAC) > 0;
806 s->vbe_regs[s->vbe_index] = val;
807 vga_update_memory_access(s);
808 break;
809 default:
810 break;
815 /* called for accesses between 0xa0000 and 0xc0000 */
816 uint32_t vga_mem_readb(VGACommonState *s, hwaddr addr)
818 int memory_map_mode, plane;
819 uint32_t ret;
821 /* convert to VGA memory offset */
822 memory_map_mode = (s->gr[VGA_GFX_MISC] >> 2) & 3;
823 addr &= 0x1ffff;
824 switch(memory_map_mode) {
825 case 0:
826 break;
827 case 1:
828 if (addr >= 0x10000)
829 return 0xff;
830 addr += s->bank_offset;
831 break;
832 case 2:
833 addr -= 0x10000;
834 if (addr >= 0x8000)
835 return 0xff;
836 break;
837 default:
838 case 3:
839 addr -= 0x18000;
840 if (addr >= 0x8000)
841 return 0xff;
842 break;
845 if (s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
846 /* chain 4 mode : simplest access */
847 ret = s->vram_ptr[addr];
848 } else if (s->gr[VGA_GFX_MODE] & 0x10) {
849 /* odd/even mode (aka text mode mapping) */
850 plane = (s->gr[VGA_GFX_PLANE_READ] & 2) | (addr & 1);
851 ret = s->vram_ptr[((addr & ~1) << 1) | plane];
852 } else {
853 /* standard VGA latched access */
854 s->latch = ((uint32_t *)s->vram_ptr)[addr];
856 if (!(s->gr[VGA_GFX_MODE] & 0x08)) {
857 /* read mode 0 */
858 plane = s->gr[VGA_GFX_PLANE_READ];
859 ret = GET_PLANE(s->latch, plane);
860 } else {
861 /* read mode 1 */
862 ret = (s->latch ^ mask16[s->gr[VGA_GFX_COMPARE_VALUE]]) &
863 mask16[s->gr[VGA_GFX_COMPARE_MASK]];
864 ret |= ret >> 16;
865 ret |= ret >> 8;
866 ret = (~ret) & 0xff;
869 return ret;
872 /* called for accesses between 0xa0000 and 0xc0000 */
873 void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
875 int memory_map_mode, plane, write_mode, b, func_select, mask;
876 uint32_t write_mask, bit_mask, set_mask;
878 #ifdef DEBUG_VGA_MEM
879 fprintf(stderr, "vga: [0x" TARGET_FMT_plx "] = 0x%02x\n", addr, val);
880 #endif
881 /* convert to VGA memory offset */
882 memory_map_mode = (s->gr[VGA_GFX_MISC] >> 2) & 3;
883 addr &= 0x1ffff;
884 switch(memory_map_mode) {
885 case 0:
886 break;
887 case 1:
888 if (addr >= 0x10000)
889 return;
890 addr += s->bank_offset;
891 break;
892 case 2:
893 addr -= 0x10000;
894 if (addr >= 0x8000)
895 return;
896 break;
897 default:
898 case 3:
899 addr -= 0x18000;
900 if (addr >= 0x8000)
901 return;
902 break;
905 if (s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
906 /* chain 4 mode : simplest access */
907 plane = addr & 3;
908 mask = (1 << plane);
909 if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
910 s->vram_ptr[addr] = val;
911 #ifdef DEBUG_VGA_MEM
912 fprintf(stderr, "vga: chain4: [0x" TARGET_FMT_plx "]\n", addr);
913 #endif
914 s->plane_updated |= mask; /* only used to detect font change */
915 memory_region_set_dirty(&s->vram, addr, 1);
917 } else if (s->gr[VGA_GFX_MODE] & 0x10) {
918 /* odd/even mode (aka text mode mapping) */
919 plane = (s->gr[VGA_GFX_PLANE_READ] & 2) | (addr & 1);
920 mask = (1 << plane);
921 if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
922 addr = ((addr & ~1) << 1) | plane;
923 s->vram_ptr[addr] = val;
924 #ifdef DEBUG_VGA_MEM
925 fprintf(stderr, "vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr);
926 #endif
927 s->plane_updated |= mask; /* only used to detect font change */
928 memory_region_set_dirty(&s->vram, addr, 1);
930 } else {
931 /* standard VGA latched access */
932 write_mode = s->gr[VGA_GFX_MODE] & 3;
933 switch(write_mode) {
934 default:
935 case 0:
936 /* rotate */
937 b = s->gr[VGA_GFX_DATA_ROTATE] & 7;
938 val = ((val >> b) | (val << (8 - b))) & 0xff;
939 val |= val << 8;
940 val |= val << 16;
942 /* apply set/reset mask */
943 set_mask = mask16[s->gr[VGA_GFX_SR_ENABLE]];
944 val = (val & ~set_mask) |
945 (mask16[s->gr[VGA_GFX_SR_VALUE]] & set_mask);
946 bit_mask = s->gr[VGA_GFX_BIT_MASK];
947 break;
948 case 1:
949 val = s->latch;
950 goto do_write;
951 case 2:
952 val = mask16[val & 0x0f];
953 bit_mask = s->gr[VGA_GFX_BIT_MASK];
954 break;
955 case 3:
956 /* rotate */
957 b = s->gr[VGA_GFX_DATA_ROTATE] & 7;
958 val = (val >> b) | (val << (8 - b));
960 bit_mask = s->gr[VGA_GFX_BIT_MASK] & val;
961 val = mask16[s->gr[VGA_GFX_SR_VALUE]];
962 break;
965 /* apply logical operation */
966 func_select = s->gr[VGA_GFX_DATA_ROTATE] >> 3;
967 switch(func_select) {
968 case 0:
969 default:
970 /* nothing to do */
971 break;
972 case 1:
973 /* and */
974 val &= s->latch;
975 break;
976 case 2:
977 /* or */
978 val |= s->latch;
979 break;
980 case 3:
981 /* xor */
982 val ^= s->latch;
983 break;
986 /* apply bit mask */
987 bit_mask |= bit_mask << 8;
988 bit_mask |= bit_mask << 16;
989 val = (val & bit_mask) | (s->latch & ~bit_mask);
991 do_write:
992 /* mask data according to sr[2] */
993 mask = s->sr[VGA_SEQ_PLANE_WRITE];
994 s->plane_updated |= mask; /* only used to detect font change */
995 write_mask = mask16[mask];
996 ((uint32_t *)s->vram_ptr)[addr] =
997 (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
998 (val & write_mask);
999 #ifdef DEBUG_VGA_MEM
1000 fprintf(stderr,
1001 "vga: latch: [0x" TARGET_FMT_plx "] mask=0x%08x val=0x%08x\n",
1002 addr * 4, write_mask, val);
1003 #endif
1004 memory_region_set_dirty(&s->vram, addr << 2, sizeof(uint32_t));
1008 typedef void vga_draw_line_func(VGACommonState *s1, uint8_t *d,
1009 const uint8_t *s, int width);
1011 #include "vga-helpers.h"
1013 /* return true if the palette was modified */
1014 static int update_palette16(VGACommonState *s)
1016 int full_update, i;
1017 uint32_t v, col, *palette;
1019 full_update = 0;
1020 palette = s->last_palette;
1021 for(i = 0; i < 16; i++) {
1022 v = s->ar[i];
1023 if (s->ar[VGA_ATC_MODE] & 0x80) {
1024 v = ((s->ar[VGA_ATC_COLOR_PAGE] & 0xf) << 4) | (v & 0xf);
1025 } else {
1026 v = ((s->ar[VGA_ATC_COLOR_PAGE] & 0xc) << 4) | (v & 0x3f);
1028 v = v * 3;
1029 col = rgb_to_pixel32(c6_to_8(s->palette[v]),
1030 c6_to_8(s->palette[v + 1]),
1031 c6_to_8(s->palette[v + 2]));
1032 if (col != palette[i]) {
1033 full_update = 1;
1034 palette[i] = col;
1037 return full_update;
1040 /* return true if the palette was modified */
1041 static int update_palette256(VGACommonState *s)
1043 int full_update, i;
1044 uint32_t v, col, *palette;
1046 full_update = 0;
1047 palette = s->last_palette;
1048 v = 0;
1049 for(i = 0; i < 256; i++) {
1050 if (s->dac_8bit) {
1051 col = rgb_to_pixel32(s->palette[v],
1052 s->palette[v + 1],
1053 s->palette[v + 2]);
1054 } else {
1055 col = rgb_to_pixel32(c6_to_8(s->palette[v]),
1056 c6_to_8(s->palette[v + 1]),
1057 c6_to_8(s->palette[v + 2]));
1059 if (col != palette[i]) {
1060 full_update = 1;
1061 palette[i] = col;
1063 v += 3;
1065 return full_update;
1068 static void vga_get_offsets(VGACommonState *s,
1069 uint32_t *pline_offset,
1070 uint32_t *pstart_addr,
1071 uint32_t *pline_compare)
1073 uint32_t start_addr, line_offset, line_compare;
1075 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1076 line_offset = s->vbe_line_offset;
1077 start_addr = s->vbe_start_addr;
1078 line_compare = 65535;
1079 } else {
1080 /* compute line_offset in bytes */
1081 line_offset = s->cr[VGA_CRTC_OFFSET];
1082 line_offset <<= 3;
1084 /* starting address */
1085 start_addr = s->cr[VGA_CRTC_START_LO] |
1086 (s->cr[VGA_CRTC_START_HI] << 8);
1088 /* line compare */
1089 line_compare = s->cr[VGA_CRTC_LINE_COMPARE] |
1090 ((s->cr[VGA_CRTC_OVERFLOW] & 0x10) << 4) |
1091 ((s->cr[VGA_CRTC_MAX_SCAN] & 0x40) << 3);
1093 *pline_offset = line_offset;
1094 *pstart_addr = start_addr;
1095 *pline_compare = line_compare;
1098 /* update start_addr and line_offset. Return TRUE if modified */
1099 static int update_basic_params(VGACommonState *s)
1101 int full_update;
1102 uint32_t start_addr, line_offset, line_compare;
1104 full_update = 0;
1106 s->get_offsets(s, &line_offset, &start_addr, &line_compare);
1108 if (line_offset != s->line_offset ||
1109 start_addr != s->start_addr ||
1110 line_compare != s->line_compare) {
1111 s->line_offset = line_offset;
1112 s->start_addr = start_addr;
1113 s->line_compare = line_compare;
1114 full_update = 1;
1116 return full_update;
1120 static const uint8_t cursor_glyph[32 * 4] = {
1121 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1122 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1123 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1124 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1125 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1126 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1127 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1128 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1129 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1130 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1131 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1132 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1133 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1134 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1135 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1136 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1139 static void vga_get_text_resolution(VGACommonState *s, int *pwidth, int *pheight,
1140 int *pcwidth, int *pcheight)
1142 int width, cwidth, height, cheight;
1144 /* total width & height */
1145 cheight = (s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1;
1146 cwidth = 8;
1147 if (!(s->sr[VGA_SEQ_CLOCK_MODE] & VGA_SR01_CHAR_CLK_8DOTS)) {
1148 cwidth = 9;
1150 if (s->sr[VGA_SEQ_CLOCK_MODE] & 0x08) {
1151 cwidth = 16; /* NOTE: no 18 pixel wide */
1153 width = (s->cr[VGA_CRTC_H_DISP] + 1);
1154 if (s->cr[VGA_CRTC_V_TOTAL] == 100) {
1155 /* ugly hack for CGA 160x100x16 - explain me the logic */
1156 height = 100;
1157 } else {
1158 height = s->cr[VGA_CRTC_V_DISP_END] |
1159 ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) |
1160 ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3);
1161 height = (height + 1) / cheight;
1164 *pwidth = width;
1165 *pheight = height;
1166 *pcwidth = cwidth;
1167 *pcheight = cheight;
1171 * Text mode update
1172 * Missing:
1173 * - double scan
1174 * - double width
1175 * - underline
1176 * - flashing
1178 static void vga_draw_text(VGACommonState *s, int full_update)
1180 DisplaySurface *surface = qemu_console_surface(s->con);
1181 int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
1182 int cx_min, cx_max, linesize, x_incr, line, line1;
1183 uint32_t offset, fgcol, bgcol, v, cursor_offset;
1184 uint8_t *d1, *d, *src, *dest, *cursor_ptr;
1185 const uint8_t *font_ptr, *font_base[2];
1186 int dup9, line_offset;
1187 uint32_t *palette;
1188 uint32_t *ch_attr_ptr;
1189 int64_t now = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
1191 /* compute font data address (in plane 2) */
1192 v = s->sr[VGA_SEQ_CHARACTER_MAP];
1193 offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
1194 if (offset != s->font_offsets[0]) {
1195 s->font_offsets[0] = offset;
1196 full_update = 1;
1198 font_base[0] = s->vram_ptr + offset;
1200 offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
1201 font_base[1] = s->vram_ptr + offset;
1202 if (offset != s->font_offsets[1]) {
1203 s->font_offsets[1] = offset;
1204 full_update = 1;
1206 if (s->plane_updated & (1 << 2) || s->has_chain4_alias) {
1207 /* if the plane 2 was modified since the last display, it
1208 indicates the font may have been modified */
1209 s->plane_updated = 0;
1210 full_update = 1;
1212 full_update |= update_basic_params(s);
1214 line_offset = s->line_offset;
1216 vga_get_text_resolution(s, &width, &height, &cw, &cheight);
1217 if ((height * width) <= 1) {
1218 /* better than nothing: exit if transient size is too small */
1219 return;
1221 if ((height * width) > CH_ATTR_SIZE) {
1222 /* better than nothing: exit if transient size is too big */
1223 return;
1226 if (width != s->last_width || height != s->last_height ||
1227 cw != s->last_cw || cheight != s->last_ch || s->last_depth) {
1228 s->last_scr_width = width * cw;
1229 s->last_scr_height = height * cheight;
1230 qemu_console_resize(s->con, s->last_scr_width, s->last_scr_height);
1231 surface = qemu_console_surface(s->con);
1232 dpy_text_resize(s->con, width, height);
1233 s->last_depth = 0;
1234 s->last_width = width;
1235 s->last_height = height;
1236 s->last_ch = cheight;
1237 s->last_cw = cw;
1238 full_update = 1;
1240 full_update |= update_palette16(s);
1241 palette = s->last_palette;
1242 x_incr = cw * surface_bytes_per_pixel(surface);
1244 if (full_update) {
1245 s->full_update_text = 1;
1247 if (s->full_update_gfx) {
1248 s->full_update_gfx = 0;
1249 full_update |= 1;
1252 cursor_offset = ((s->cr[VGA_CRTC_CURSOR_HI] << 8) |
1253 s->cr[VGA_CRTC_CURSOR_LO]) - s->start_addr;
1254 if (cursor_offset != s->cursor_offset ||
1255 s->cr[VGA_CRTC_CURSOR_START] != s->cursor_start ||
1256 s->cr[VGA_CRTC_CURSOR_END] != s->cursor_end) {
1257 /* if the cursor position changed, we update the old and new
1258 chars */
1259 if (s->cursor_offset < CH_ATTR_SIZE)
1260 s->last_ch_attr[s->cursor_offset] = -1;
1261 if (cursor_offset < CH_ATTR_SIZE)
1262 s->last_ch_attr[cursor_offset] = -1;
1263 s->cursor_offset = cursor_offset;
1264 s->cursor_start = s->cr[VGA_CRTC_CURSOR_START];
1265 s->cursor_end = s->cr[VGA_CRTC_CURSOR_END];
1267 cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
1268 if (now >= s->cursor_blink_time) {
1269 s->cursor_blink_time = now + VGA_TEXT_CURSOR_PERIOD_MS / 2;
1270 s->cursor_visible_phase = !s->cursor_visible_phase;
1273 dest = surface_data(surface);
1274 linesize = surface_stride(surface);
1275 ch_attr_ptr = s->last_ch_attr;
1276 line = 0;
1277 offset = s->start_addr * 4;
1278 for(cy = 0; cy < height; cy++) {
1279 d1 = dest;
1280 src = s->vram_ptr + offset;
1281 cx_min = width;
1282 cx_max = -1;
1283 for(cx = 0; cx < width; cx++) {
1284 ch_attr = *(uint16_t *)src;
1285 if (full_update || ch_attr != *ch_attr_ptr || src == cursor_ptr) {
1286 if (cx < cx_min)
1287 cx_min = cx;
1288 if (cx > cx_max)
1289 cx_max = cx;
1290 *ch_attr_ptr = ch_attr;
1291 #ifdef HOST_WORDS_BIGENDIAN
1292 ch = ch_attr >> 8;
1293 cattr = ch_attr & 0xff;
1294 #else
1295 ch = ch_attr & 0xff;
1296 cattr = ch_attr >> 8;
1297 #endif
1298 font_ptr = font_base[(cattr >> 3) & 1];
1299 font_ptr += 32 * 4 * ch;
1300 bgcol = palette[cattr >> 4];
1301 fgcol = palette[cattr & 0x0f];
1302 if (cw == 16) {
1303 vga_draw_glyph16(d1, linesize,
1304 font_ptr, cheight, fgcol, bgcol);
1305 } else if (cw != 9) {
1306 vga_draw_glyph8(d1, linesize,
1307 font_ptr, cheight, fgcol, bgcol);
1308 } else {
1309 dup9 = 0;
1310 if (ch >= 0xb0 && ch <= 0xdf &&
1311 (s->ar[VGA_ATC_MODE] & 0x04)) {
1312 dup9 = 1;
1314 vga_draw_glyph9(d1, linesize,
1315 font_ptr, cheight, fgcol, bgcol, dup9);
1317 if (src == cursor_ptr &&
1318 !(s->cr[VGA_CRTC_CURSOR_START] & 0x20) &&
1319 s->cursor_visible_phase) {
1320 int line_start, line_last, h;
1321 /* draw the cursor */
1322 line_start = s->cr[VGA_CRTC_CURSOR_START] & 0x1f;
1323 line_last = s->cr[VGA_CRTC_CURSOR_END] & 0x1f;
1324 /* XXX: check that */
1325 if (line_last > cheight - 1)
1326 line_last = cheight - 1;
1327 if (line_last >= line_start && line_start < cheight) {
1328 h = line_last - line_start + 1;
1329 d = d1 + linesize * line_start;
1330 if (cw == 16) {
1331 vga_draw_glyph16(d, linesize,
1332 cursor_glyph, h, fgcol, bgcol);
1333 } else if (cw != 9) {
1334 vga_draw_glyph8(d, linesize,
1335 cursor_glyph, h, fgcol, bgcol);
1336 } else {
1337 vga_draw_glyph9(d, linesize,
1338 cursor_glyph, h, fgcol, bgcol, 1);
1343 d1 += x_incr;
1344 src += 4;
1345 ch_attr_ptr++;
1347 if (cx_max != -1) {
1348 dpy_gfx_update(s->con, cx_min * cw, cy * cheight,
1349 (cx_max - cx_min + 1) * cw, cheight);
1351 dest += linesize * cheight;
1352 line1 = line + cheight;
1353 offset += line_offset;
1354 if (line < s->line_compare && line1 >= s->line_compare) {
1355 offset = 0;
1357 line = line1;
1361 enum {
1362 VGA_DRAW_LINE2,
1363 VGA_DRAW_LINE2D2,
1364 VGA_DRAW_LINE4,
1365 VGA_DRAW_LINE4D2,
1366 VGA_DRAW_LINE8D2,
1367 VGA_DRAW_LINE8,
1368 VGA_DRAW_LINE15_LE,
1369 VGA_DRAW_LINE16_LE,
1370 VGA_DRAW_LINE24_LE,
1371 VGA_DRAW_LINE32_LE,
1372 VGA_DRAW_LINE15_BE,
1373 VGA_DRAW_LINE16_BE,
1374 VGA_DRAW_LINE24_BE,
1375 VGA_DRAW_LINE32_BE,
1376 VGA_DRAW_LINE_NB,
1379 static vga_draw_line_func * const vga_draw_line_table[VGA_DRAW_LINE_NB] = {
1380 vga_draw_line2,
1381 vga_draw_line2d2,
1382 vga_draw_line4,
1383 vga_draw_line4d2,
1384 vga_draw_line8d2,
1385 vga_draw_line8,
1386 vga_draw_line15_le,
1387 vga_draw_line16_le,
1388 vga_draw_line24_le,
1389 vga_draw_line32_le,
1390 vga_draw_line15_be,
1391 vga_draw_line16_be,
1392 vga_draw_line24_be,
1393 vga_draw_line32_be,
1396 static int vga_get_bpp(VGACommonState *s)
1398 int ret;
1400 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1401 ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
1402 } else {
1403 ret = 0;
1405 return ret;
1408 static void vga_get_resolution(VGACommonState *s, int *pwidth, int *pheight)
1410 int width, height;
1412 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1413 width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
1414 height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
1415 } else {
1416 width = (s->cr[VGA_CRTC_H_DISP] + 1) * 8;
1417 height = s->cr[VGA_CRTC_V_DISP_END] |
1418 ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) |
1419 ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3);
1420 height = (height + 1);
1422 *pwidth = width;
1423 *pheight = height;
1426 void vga_invalidate_scanlines(VGACommonState *s, int y1, int y2)
1428 int y;
1429 if (y1 >= VGA_MAX_HEIGHT)
1430 return;
1431 if (y2 >= VGA_MAX_HEIGHT)
1432 y2 = VGA_MAX_HEIGHT;
1433 for(y = y1; y < y2; y++) {
1434 s->invalidated_y_table[y >> 5] |= 1 << (y & 0x1f);
1438 void vga_sync_dirty_bitmap(VGACommonState *s)
1440 memory_region_sync_dirty_bitmap(&s->vram);
1443 void vga_dirty_log_start(VGACommonState *s)
1445 memory_region_set_log(&s->vram, true, DIRTY_MEMORY_VGA);
1448 void vga_dirty_log_stop(VGACommonState *s)
1450 memory_region_set_log(&s->vram, false, DIRTY_MEMORY_VGA);
1454 * graphic modes
1456 static void vga_draw_graphic(VGACommonState *s, int full_update)
1458 DisplaySurface *surface = qemu_console_surface(s->con);
1459 int y1, y, update, linesize, y_start, double_scan, mask, depth;
1460 int width, height, shift_control, line_offset, bwidth, bits;
1461 ram_addr_t page0, page1, page_min, page_max;
1462 int disp_width, multi_scan, multi_run;
1463 uint8_t *d;
1464 uint32_t v, addr1, addr;
1465 vga_draw_line_func *vga_draw_line = NULL;
1466 #ifdef HOST_WORDS_BIGENDIAN
1467 bool byteswap = !s->big_endian_fb;
1468 #else
1469 bool byteswap = s->big_endian_fb;
1470 #endif
1472 full_update |= update_basic_params(s);
1474 if (!full_update)
1475 vga_sync_dirty_bitmap(s);
1477 s->get_resolution(s, &width, &height);
1478 disp_width = width;
1480 shift_control = (s->gr[VGA_GFX_MODE] >> 5) & 3;
1481 double_scan = (s->cr[VGA_CRTC_MAX_SCAN] >> 7);
1482 if (shift_control != 1) {
1483 multi_scan = (((s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1) << double_scan)
1484 - 1;
1485 } else {
1486 /* in CGA modes, multi_scan is ignored */
1487 /* XXX: is it correct ? */
1488 multi_scan = double_scan;
1490 multi_run = multi_scan;
1491 if (shift_control != s->shift_control ||
1492 double_scan != s->double_scan) {
1493 full_update = 1;
1494 s->shift_control = shift_control;
1495 s->double_scan = double_scan;
1498 if (shift_control == 0) {
1499 if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
1500 disp_width <<= 1;
1502 } else if (shift_control == 1) {
1503 if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
1504 disp_width <<= 1;
1508 depth = s->get_bpp(s);
1509 if (s->line_offset != s->last_line_offset ||
1510 disp_width != s->last_width ||
1511 height != s->last_height ||
1512 s->last_depth != depth ||
1513 s->last_byteswap != byteswap) {
1514 if (depth == 32 || (depth == 16 && !byteswap)) {
1515 pixman_format_code_t format =
1516 qemu_default_pixman_format(depth, !byteswap);
1517 surface = qemu_create_displaysurface_from(disp_width,
1518 height, format, s->line_offset,
1519 s->vram_ptr + (s->start_addr * 4));
1520 dpy_gfx_replace_surface(s->con, surface);
1521 } else {
1522 qemu_console_resize(s->con, disp_width, height);
1523 surface = qemu_console_surface(s->con);
1525 s->last_scr_width = disp_width;
1526 s->last_scr_height = height;
1527 s->last_width = disp_width;
1528 s->last_height = height;
1529 s->last_line_offset = s->line_offset;
1530 s->last_depth = depth;
1531 s->last_byteswap = byteswap;
1532 full_update = 1;
1533 } else if (is_buffer_shared(surface) &&
1534 (full_update || surface_data(surface) != s->vram_ptr
1535 + (s->start_addr * 4))) {
1536 pixman_format_code_t format =
1537 qemu_default_pixman_format(depth, !byteswap);
1538 surface = qemu_create_displaysurface_from(disp_width,
1539 height, format, s->line_offset,
1540 s->vram_ptr + (s->start_addr * 4));
1541 dpy_gfx_replace_surface(s->con, surface);
1544 if (shift_control == 0) {
1545 full_update |= update_palette16(s);
1546 if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
1547 v = VGA_DRAW_LINE4D2;
1548 } else {
1549 v = VGA_DRAW_LINE4;
1551 bits = 4;
1552 } else if (shift_control == 1) {
1553 full_update |= update_palette16(s);
1554 if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
1555 v = VGA_DRAW_LINE2D2;
1556 } else {
1557 v = VGA_DRAW_LINE2;
1559 bits = 4;
1560 } else {
1561 switch(s->get_bpp(s)) {
1562 default:
1563 case 0:
1564 full_update |= update_palette256(s);
1565 v = VGA_DRAW_LINE8D2;
1566 bits = 4;
1567 break;
1568 case 8:
1569 full_update |= update_palette256(s);
1570 v = VGA_DRAW_LINE8;
1571 bits = 8;
1572 break;
1573 case 15:
1574 v = s->big_endian_fb ? VGA_DRAW_LINE15_BE : VGA_DRAW_LINE15_LE;
1575 bits = 16;
1576 break;
1577 case 16:
1578 v = s->big_endian_fb ? VGA_DRAW_LINE16_BE : VGA_DRAW_LINE16_LE;
1579 bits = 16;
1580 break;
1581 case 24:
1582 v = s->big_endian_fb ? VGA_DRAW_LINE24_BE : VGA_DRAW_LINE24_LE;
1583 bits = 24;
1584 break;
1585 case 32:
1586 v = s->big_endian_fb ? VGA_DRAW_LINE32_BE : VGA_DRAW_LINE32_LE;
1587 bits = 32;
1588 break;
1591 vga_draw_line = vga_draw_line_table[v];
1593 if (!is_buffer_shared(surface) && s->cursor_invalidate) {
1594 s->cursor_invalidate(s);
1597 line_offset = s->line_offset;
1598 #if 0
1599 fprintf(stderr,
1600 "w=%d h=%d v=%d line_offset=%d cr[0x09]=0x%02x cr[0x17]=0x%02x "
1601 "linecmp=%d sr[0x01]=0x%02x\n",
1602 width, height, v, line_offset, s->cr[9], s->cr[VGA_CRTC_MODE],
1603 s->line_compare, s->sr[VGA_SEQ_CLOCK_MODE]);
1604 #endif
1605 addr1 = (s->start_addr * 4);
1606 bwidth = (width * bits + 7) / 8;
1607 y_start = -1;
1608 page_min = -1;
1609 page_max = 0;
1610 d = surface_data(surface);
1611 linesize = surface_stride(surface);
1612 y1 = 0;
1613 for(y = 0; y < height; y++) {
1614 addr = addr1;
1615 if (!(s->cr[VGA_CRTC_MODE] & 1)) {
1616 int shift;
1617 /* CGA compatibility handling */
1618 shift = 14 + ((s->cr[VGA_CRTC_MODE] >> 6) & 1);
1619 addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
1621 if (!(s->cr[VGA_CRTC_MODE] & 2)) {
1622 addr = (addr & ~0x8000) | ((y1 & 2) << 14);
1624 update = full_update;
1625 page0 = addr;
1626 page1 = addr + bwidth - 1;
1627 update |= memory_region_get_dirty(&s->vram, page0, page1 - page0,
1628 DIRTY_MEMORY_VGA);
1629 /* explicit invalidation for the hardware cursor */
1630 update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
1631 if (update) {
1632 if (y_start < 0)
1633 y_start = y;
1634 if (page0 < page_min)
1635 page_min = page0;
1636 if (page1 > page_max)
1637 page_max = page1;
1638 if (!(is_buffer_shared(surface))) {
1639 vga_draw_line(s, d, s->vram_ptr + addr, width);
1640 if (s->cursor_draw_line)
1641 s->cursor_draw_line(s, d, y);
1643 } else {
1644 if (y_start >= 0) {
1645 /* flush to display */
1646 dpy_gfx_update(s->con, 0, y_start,
1647 disp_width, y - y_start);
1648 y_start = -1;
1651 if (!multi_run) {
1652 mask = (s->cr[VGA_CRTC_MODE] & 3) ^ 3;
1653 if ((y1 & mask) == mask)
1654 addr1 += line_offset;
1655 y1++;
1656 multi_run = multi_scan;
1657 } else {
1658 multi_run--;
1660 /* line compare acts on the displayed lines */
1661 if (y == s->line_compare)
1662 addr1 = 0;
1663 d += linesize;
1665 if (y_start >= 0) {
1666 /* flush to display */
1667 dpy_gfx_update(s->con, 0, y_start,
1668 disp_width, y - y_start);
1670 /* reset modified pages */
1671 if (page_max >= page_min) {
1672 memory_region_reset_dirty(&s->vram,
1673 page_min,
1674 page_max - page_min,
1675 DIRTY_MEMORY_VGA);
1677 memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
1680 static void vga_draw_blank(VGACommonState *s, int full_update)
1682 DisplaySurface *surface = qemu_console_surface(s->con);
1683 int i, w;
1684 uint8_t *d;
1686 if (!full_update)
1687 return;
1688 if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
1689 return;
1691 w = s->last_scr_width * surface_bytes_per_pixel(surface);
1692 d = surface_data(surface);
1693 for(i = 0; i < s->last_scr_height; i++) {
1694 memset(d, 0, w);
1695 d += surface_stride(surface);
1697 dpy_gfx_update(s->con, 0, 0,
1698 s->last_scr_width, s->last_scr_height);
1701 #define GMODE_TEXT 0
1702 #define GMODE_GRAPH 1
1703 #define GMODE_BLANK 2
1705 static void vga_update_display(void *opaque)
1707 VGACommonState *s = opaque;
1708 DisplaySurface *surface = qemu_console_surface(s->con);
1709 int full_update, graphic_mode;
1711 qemu_flush_coalesced_mmio_buffer();
1713 if (surface_bits_per_pixel(surface) == 0) {
1714 /* nothing to do */
1715 } else {
1716 full_update = 0;
1717 if (!(s->ar_index & 0x20)) {
1718 graphic_mode = GMODE_BLANK;
1719 } else {
1720 graphic_mode = s->gr[VGA_GFX_MISC] & VGA_GR06_GRAPHICS_MODE;
1722 if (graphic_mode != s->graphic_mode) {
1723 s->graphic_mode = graphic_mode;
1724 s->cursor_blink_time = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
1725 full_update = 1;
1727 switch(graphic_mode) {
1728 case GMODE_TEXT:
1729 vga_draw_text(s, full_update);
1730 break;
1731 case GMODE_GRAPH:
1732 vga_draw_graphic(s, full_update);
1733 break;
1734 case GMODE_BLANK:
1735 default:
1736 vga_draw_blank(s, full_update);
1737 break;
1742 /* force a full display refresh */
1743 static void vga_invalidate_display(void *opaque)
1745 VGACommonState *s = opaque;
1747 s->last_width = -1;
1748 s->last_height = -1;
1751 void vga_common_reset(VGACommonState *s)
1753 s->sr_index = 0;
1754 memset(s->sr, '\0', sizeof(s->sr));
1755 s->gr_index = 0;
1756 memset(s->gr, '\0', sizeof(s->gr));
1757 s->ar_index = 0;
1758 memset(s->ar, '\0', sizeof(s->ar));
1759 s->ar_flip_flop = 0;
1760 s->cr_index = 0;
1761 memset(s->cr, '\0', sizeof(s->cr));
1762 s->msr = 0;
1763 s->fcr = 0;
1764 s->st00 = 0;
1765 s->st01 = 0;
1766 s->dac_state = 0;
1767 s->dac_sub_index = 0;
1768 s->dac_read_index = 0;
1769 s->dac_write_index = 0;
1770 memset(s->dac_cache, '\0', sizeof(s->dac_cache));
1771 s->dac_8bit = 0;
1772 memset(s->palette, '\0', sizeof(s->palette));
1773 s->bank_offset = 0;
1774 s->vbe_index = 0;
1775 memset(s->vbe_regs, '\0', sizeof(s->vbe_regs));
1776 s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID5;
1777 s->vbe_start_addr = 0;
1778 s->vbe_line_offset = 0;
1779 s->vbe_bank_mask = (s->vram_size >> 16) - 1;
1780 memset(s->font_offsets, '\0', sizeof(s->font_offsets));
1781 s->graphic_mode = -1; /* force full update */
1782 s->shift_control = 0;
1783 s->double_scan = 0;
1784 s->line_offset = 0;
1785 s->line_compare = 0;
1786 s->start_addr = 0;
1787 s->plane_updated = 0;
1788 s->last_cw = 0;
1789 s->last_ch = 0;
1790 s->last_width = 0;
1791 s->last_height = 0;
1792 s->last_scr_width = 0;
1793 s->last_scr_height = 0;
1794 s->cursor_start = 0;
1795 s->cursor_end = 0;
1796 s->cursor_offset = 0;
1797 s->big_endian_fb = s->default_endian_fb;
1798 memset(s->invalidated_y_table, '\0', sizeof(s->invalidated_y_table));
1799 memset(s->last_palette, '\0', sizeof(s->last_palette));
1800 memset(s->last_ch_attr, '\0', sizeof(s->last_ch_attr));
1801 switch (vga_retrace_method) {
1802 case VGA_RETRACE_DUMB:
1803 break;
1804 case VGA_RETRACE_PRECISE:
1805 memset(&s->retrace_info, 0, sizeof (s->retrace_info));
1806 break;
1808 vga_update_memory_access(s);
1811 static void vga_reset(void *opaque)
1813 VGACommonState *s = opaque;
1814 vga_common_reset(s);
1817 #define TEXTMODE_X(x) ((x) % width)
1818 #define TEXTMODE_Y(x) ((x) / width)
1819 #define VMEM2CHTYPE(v) ((v & 0xff0007ff) | \
1820 ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1))
1821 /* relay text rendering to the display driver
1822 * instead of doing a full vga_update_display() */
1823 static void vga_update_text(void *opaque, console_ch_t *chardata)
1825 VGACommonState *s = opaque;
1826 int graphic_mode, i, cursor_offset, cursor_visible;
1827 int cw, cheight, width, height, size, c_min, c_max;
1828 uint32_t *src;
1829 console_ch_t *dst, val;
1830 char msg_buffer[80];
1831 int full_update = 0;
1833 qemu_flush_coalesced_mmio_buffer();
1835 if (!(s->ar_index & 0x20)) {
1836 graphic_mode = GMODE_BLANK;
1837 } else {
1838 graphic_mode = s->gr[VGA_GFX_MISC] & VGA_GR06_GRAPHICS_MODE;
1840 if (graphic_mode != s->graphic_mode) {
1841 s->graphic_mode = graphic_mode;
1842 full_update = 1;
1844 if (s->last_width == -1) {
1845 s->last_width = 0;
1846 full_update = 1;
1849 switch (graphic_mode) {
1850 case GMODE_TEXT:
1851 /* TODO: update palette */
1852 full_update |= update_basic_params(s);
1854 /* total width & height */
1855 cheight = (s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1;
1856 cw = 8;
1857 if (!(s->sr[VGA_SEQ_CLOCK_MODE] & VGA_SR01_CHAR_CLK_8DOTS)) {
1858 cw = 9;
1860 if (s->sr[VGA_SEQ_CLOCK_MODE] & 0x08) {
1861 cw = 16; /* NOTE: no 18 pixel wide */
1863 width = (s->cr[VGA_CRTC_H_DISP] + 1);
1864 if (s->cr[VGA_CRTC_V_TOTAL] == 100) {
1865 /* ugly hack for CGA 160x100x16 - explain me the logic */
1866 height = 100;
1867 } else {
1868 height = s->cr[VGA_CRTC_V_DISP_END] |
1869 ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) |
1870 ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3);
1871 height = (height + 1) / cheight;
1874 size = (height * width);
1875 if (size > CH_ATTR_SIZE) {
1876 if (!full_update)
1877 return;
1879 snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Text mode",
1880 width, height);
1881 break;
1884 if (width != s->last_width || height != s->last_height ||
1885 cw != s->last_cw || cheight != s->last_ch) {
1886 s->last_scr_width = width * cw;
1887 s->last_scr_height = height * cheight;
1888 qemu_console_resize(s->con, s->last_scr_width, s->last_scr_height);
1889 dpy_text_resize(s->con, width, height);
1890 s->last_depth = 0;
1891 s->last_width = width;
1892 s->last_height = height;
1893 s->last_ch = cheight;
1894 s->last_cw = cw;
1895 full_update = 1;
1898 if (full_update) {
1899 s->full_update_gfx = 1;
1901 if (s->full_update_text) {
1902 s->full_update_text = 0;
1903 full_update |= 1;
1906 /* Update "hardware" cursor */
1907 cursor_offset = ((s->cr[VGA_CRTC_CURSOR_HI] << 8) |
1908 s->cr[VGA_CRTC_CURSOR_LO]) - s->start_addr;
1909 if (cursor_offset != s->cursor_offset ||
1910 s->cr[VGA_CRTC_CURSOR_START] != s->cursor_start ||
1911 s->cr[VGA_CRTC_CURSOR_END] != s->cursor_end || full_update) {
1912 cursor_visible = !(s->cr[VGA_CRTC_CURSOR_START] & 0x20);
1913 if (cursor_visible && cursor_offset < size && cursor_offset >= 0)
1914 dpy_text_cursor(s->con,
1915 TEXTMODE_X(cursor_offset),
1916 TEXTMODE_Y(cursor_offset));
1917 else
1918 dpy_text_cursor(s->con, -1, -1);
1919 s->cursor_offset = cursor_offset;
1920 s->cursor_start = s->cr[VGA_CRTC_CURSOR_START];
1921 s->cursor_end = s->cr[VGA_CRTC_CURSOR_END];
1924 src = (uint32_t *) s->vram_ptr + s->start_addr;
1925 dst = chardata;
1927 if (full_update) {
1928 for (i = 0; i < size; src ++, dst ++, i ++)
1929 console_write_ch(dst, VMEM2CHTYPE(le32_to_cpu(*src)));
1931 dpy_text_update(s->con, 0, 0, width, height);
1932 } else {
1933 c_max = 0;
1935 for (i = 0; i < size; src ++, dst ++, i ++) {
1936 console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
1937 if (*dst != val) {
1938 *dst = val;
1939 c_max = i;
1940 break;
1943 c_min = i;
1944 for (; i < size; src ++, dst ++, i ++) {
1945 console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
1946 if (*dst != val) {
1947 *dst = val;
1948 c_max = i;
1952 if (c_min <= c_max) {
1953 i = TEXTMODE_Y(c_min);
1954 dpy_text_update(s->con, 0, i, width, TEXTMODE_Y(c_max) - i + 1);
1958 return;
1959 case GMODE_GRAPH:
1960 if (!full_update)
1961 return;
1963 s->get_resolution(s, &width, &height);
1964 snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Graphic mode",
1965 width, height);
1966 break;
1967 case GMODE_BLANK:
1968 default:
1969 if (!full_update)
1970 return;
1972 snprintf(msg_buffer, sizeof(msg_buffer), "VGA Blank mode");
1973 break;
1976 /* Display a message */
1977 s->last_width = 60;
1978 s->last_height = height = 3;
1979 dpy_text_cursor(s->con, -1, -1);
1980 dpy_text_resize(s->con, s->last_width, height);
1982 for (dst = chardata, i = 0; i < s->last_width * height; i ++)
1983 console_write_ch(dst ++, ' ');
1985 size = strlen(msg_buffer);
1986 width = (s->last_width - size) / 2;
1987 dst = chardata + s->last_width + width;
1988 for (i = 0; i < size; i ++)
1989 console_write_ch(dst ++, 0x00200100 | msg_buffer[i]);
1991 dpy_text_update(s->con, 0, 0, s->last_width, height);
1994 static uint64_t vga_mem_read(void *opaque, hwaddr addr,
1995 unsigned size)
1997 VGACommonState *s = opaque;
1999 return vga_mem_readb(s, addr);
2002 static void vga_mem_write(void *opaque, hwaddr addr,
2003 uint64_t data, unsigned size)
2005 VGACommonState *s = opaque;
2007 return vga_mem_writeb(s, addr, data);
2010 const MemoryRegionOps vga_mem_ops = {
2011 .read = vga_mem_read,
2012 .write = vga_mem_write,
2013 .endianness = DEVICE_LITTLE_ENDIAN,
2014 .impl = {
2015 .min_access_size = 1,
2016 .max_access_size = 1,
2020 static int vga_common_post_load(void *opaque, int version_id)
2022 VGACommonState *s = opaque;
2024 /* force refresh */
2025 s->graphic_mode = -1;
2026 return 0;
2029 static bool vga_endian_state_needed(void *opaque)
2031 VGACommonState *s = opaque;
2034 * Only send the endian state if it's different from the
2035 * default one, thus ensuring backward compatibility for
2036 * migration of the common case
2038 return s->default_endian_fb != s->big_endian_fb;
2041 const VMStateDescription vmstate_vga_endian = {
2042 .name = "vga.endian",
2043 .version_id = 1,
2044 .minimum_version_id = 1,
2045 .fields = (VMStateField[]) {
2046 VMSTATE_BOOL(big_endian_fb, VGACommonState),
2047 VMSTATE_END_OF_LIST()
2051 const VMStateDescription vmstate_vga_common = {
2052 .name = "vga",
2053 .version_id = 2,
2054 .minimum_version_id = 2,
2055 .post_load = vga_common_post_load,
2056 .fields = (VMStateField[]) {
2057 VMSTATE_UINT32(latch, VGACommonState),
2058 VMSTATE_UINT8(sr_index, VGACommonState),
2059 VMSTATE_PARTIAL_BUFFER(sr, VGACommonState, 8),
2060 VMSTATE_UINT8(gr_index, VGACommonState),
2061 VMSTATE_PARTIAL_BUFFER(gr, VGACommonState, 16),
2062 VMSTATE_UINT8(ar_index, VGACommonState),
2063 VMSTATE_BUFFER(ar, VGACommonState),
2064 VMSTATE_INT32(ar_flip_flop, VGACommonState),
2065 VMSTATE_UINT8(cr_index, VGACommonState),
2066 VMSTATE_BUFFER(cr, VGACommonState),
2067 VMSTATE_UINT8(msr, VGACommonState),
2068 VMSTATE_UINT8(fcr, VGACommonState),
2069 VMSTATE_UINT8(st00, VGACommonState),
2070 VMSTATE_UINT8(st01, VGACommonState),
2072 VMSTATE_UINT8(dac_state, VGACommonState),
2073 VMSTATE_UINT8(dac_sub_index, VGACommonState),
2074 VMSTATE_UINT8(dac_read_index, VGACommonState),
2075 VMSTATE_UINT8(dac_write_index, VGACommonState),
2076 VMSTATE_BUFFER(dac_cache, VGACommonState),
2077 VMSTATE_BUFFER(palette, VGACommonState),
2079 VMSTATE_INT32(bank_offset, VGACommonState),
2080 VMSTATE_UINT8_EQUAL(is_vbe_vmstate, VGACommonState),
2081 VMSTATE_UINT16(vbe_index, VGACommonState),
2082 VMSTATE_UINT16_ARRAY(vbe_regs, VGACommonState, VBE_DISPI_INDEX_NB),
2083 VMSTATE_UINT32(vbe_start_addr, VGACommonState),
2084 VMSTATE_UINT32(vbe_line_offset, VGACommonState),
2085 VMSTATE_UINT32(vbe_bank_mask, VGACommonState),
2086 VMSTATE_END_OF_LIST()
2088 .subsections = (VMStateSubsection []) {
2090 .vmsd = &vmstate_vga_endian,
2091 .needed = vga_endian_state_needed,
2092 }, {
2093 /* empty */
2098 static const GraphicHwOps vga_ops = {
2099 .invalidate = vga_invalidate_display,
2100 .gfx_update = vga_update_display,
2101 .text_update = vga_update_text,
2104 void vga_common_init(VGACommonState *s, Object *obj, bool global_vmstate)
2106 int i, j, v, b;
2108 for(i = 0;i < 256; i++) {
2109 v = 0;
2110 for(j = 0; j < 8; j++) {
2111 v |= ((i >> j) & 1) << (j * 4);
2113 expand4[i] = v;
2115 v = 0;
2116 for(j = 0; j < 4; j++) {
2117 v |= ((i >> (2 * j)) & 3) << (j * 4);
2119 expand2[i] = v;
2121 for(i = 0; i < 16; i++) {
2122 v = 0;
2123 for(j = 0; j < 4; j++) {
2124 b = ((i >> j) & 1);
2125 v |= b << (2 * j);
2126 v |= b << (2 * j + 1);
2128 expand4to8[i] = v;
2131 /* valid range: 1 MB -> 256 MB */
2132 s->vram_size = 1024 * 1024;
2133 while (s->vram_size < (s->vram_size_mb << 20) &&
2134 s->vram_size < (256 << 20)) {
2135 s->vram_size <<= 1;
2137 s->vram_size_mb = s->vram_size >> 20;
2138 if (!s->vbe_size) {
2139 s->vbe_size = s->vram_size;
2142 s->is_vbe_vmstate = 1;
2143 memory_region_init_ram(&s->vram, obj, "vga.vram", s->vram_size,
2144 &error_abort);
2145 vmstate_register_ram(&s->vram, global_vmstate ? NULL : DEVICE(obj));
2146 xen_register_framebuffer(&s->vram);
2147 s->vram_ptr = memory_region_get_ram_ptr(&s->vram);
2148 s->get_bpp = vga_get_bpp;
2149 s->get_offsets = vga_get_offsets;
2150 s->get_resolution = vga_get_resolution;
2151 s->hw_ops = &vga_ops;
2152 switch (vga_retrace_method) {
2153 case VGA_RETRACE_DUMB:
2154 s->retrace = vga_dumb_retrace;
2155 s->update_retrace_info = vga_dumb_update_retrace_info;
2156 break;
2158 case VGA_RETRACE_PRECISE:
2159 s->retrace = vga_precise_retrace;
2160 s->update_retrace_info = vga_precise_update_retrace_info;
2161 break;
2165 * Set default fb endian based on target, could probably be turned
2166 * into a device attribute set by the machine/platform to remove
2167 * all target endian dependencies from this file.
2169 #ifdef TARGET_WORDS_BIGENDIAN
2170 s->default_endian_fb = true;
2171 #else
2172 s->default_endian_fb = false;
2173 #endif
2174 vga_dirty_log_start(s);
2177 static const MemoryRegionPortio vga_portio_list[] = {
2178 { 0x04, 2, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3b4 */
2179 { 0x0a, 1, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3ba */
2180 { 0x10, 16, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3c0 */
2181 { 0x24, 2, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3d4 */
2182 { 0x2a, 1, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3da */
2183 PORTIO_END_OF_LIST(),
2186 static const MemoryRegionPortio vbe_portio_list[] = {
2187 { 0, 1, 2, .read = vbe_ioport_read_index, .write = vbe_ioport_write_index },
2188 # ifdef TARGET_I386
2189 { 1, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data },
2190 # endif
2191 { 2, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data },
2192 PORTIO_END_OF_LIST(),
2195 /* Used by both ISA and PCI */
2196 MemoryRegion *vga_init_io(VGACommonState *s, Object *obj,
2197 const MemoryRegionPortio **vga_ports,
2198 const MemoryRegionPortio **vbe_ports)
2200 MemoryRegion *vga_mem;
2202 *vga_ports = vga_portio_list;
2203 *vbe_ports = vbe_portio_list;
2205 vga_mem = g_malloc(sizeof(*vga_mem));
2206 memory_region_init_io(vga_mem, obj, &vga_mem_ops, s,
2207 "vga-lowmem", 0x20000);
2208 memory_region_set_flush_coalesced(vga_mem);
2210 return vga_mem;
2213 void vga_init(VGACommonState *s, Object *obj, MemoryRegion *address_space,
2214 MemoryRegion *address_space_io, bool init_vga_ports)
2216 MemoryRegion *vga_io_memory;
2217 const MemoryRegionPortio *vga_ports, *vbe_ports;
2219 qemu_register_reset(vga_reset, s);
2221 s->bank_offset = 0;
2223 s->legacy_address_space = address_space;
2225 vga_io_memory = vga_init_io(s, obj, &vga_ports, &vbe_ports);
2226 memory_region_add_subregion_overlap(address_space,
2227 isa_mem_base + 0x000a0000,
2228 vga_io_memory,
2230 memory_region_set_coalescing(vga_io_memory);
2231 if (init_vga_ports) {
2232 portio_list_init(&s->vga_port_list, obj, vga_ports, s, "vga");
2233 portio_list_set_flush_coalesced(&s->vga_port_list);
2234 portio_list_add(&s->vga_port_list, address_space_io, 0x3b0);
2236 if (vbe_ports) {
2237 portio_list_init(&s->vbe_port_list, obj, vbe_ports, s, "vbe");
2238 portio_list_add(&s->vbe_port_list, address_space_io, 0x1ce);
2242 void vga_init_vbe(VGACommonState *s, Object *obj, MemoryRegion *system_memory)
2244 /* With pc-0.12 and below we map both the PCI BAR and the fixed VBE region,
2245 * so use an alias to avoid double-mapping the same region.
2247 memory_region_init_alias(&s->vram_vbe, obj, "vram.vbe",
2248 &s->vram, 0, memory_region_size(&s->vram));
2249 /* XXX: use optimized standard vga accesses */
2250 memory_region_add_subregion(system_memory,
2251 VBE_DISPI_LFB_PHYSICAL_ADDRESS,
2252 &s->vram_vbe);
2253 s->vbe_mapped = 1;