qemu-iotests: 149: Use "/usr/bin/env python"
[qemu/ar7.git] / hw / display / vga.c
blob657e9f196d8d1eeee8731261abd69312b504ed09
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 "qemu/osdep.h"
25 #include "qapi/error.h"
26 #include "hw/hw.h"
27 #include "vga.h"
28 #include "ui/console.h"
29 #include "hw/i386/pc.h"
30 #include "hw/pci/pci.h"
31 #include "vga_int.h"
32 #include "ui/pixel_ops.h"
33 #include "qemu/timer.h"
34 #include "hw/xen/xen.h"
35 #include "trace.h"
37 //#define DEBUG_VGA
38 //#define DEBUG_VGA_MEM
39 //#define DEBUG_VGA_REG
41 //#define DEBUG_BOCHS_VBE
43 /* 16 state changes per vertical frame @60 Hz */
44 #define VGA_TEXT_CURSOR_PERIOD_MS (1000 * 2 * 16 / 60)
47 * Video Graphics Array (VGA)
49 * Chipset docs for original IBM VGA:
50 * http://www.mcamafia.de/pdf/ibm_vgaxga_trm2.pdf
52 * FreeVGA site:
53 * http://www.osdever.net/FreeVGA/home.htm
55 * Standard VGA features and Bochs VBE extensions are implemented.
58 /* force some bits to zero */
59 const uint8_t sr_mask[8] = {
60 0x03,
61 0x3d,
62 0x0f,
63 0x3f,
64 0x0e,
65 0x00,
66 0x00,
67 0xff,
70 const uint8_t gr_mask[16] = {
71 0x0f, /* 0x00 */
72 0x0f, /* 0x01 */
73 0x0f, /* 0x02 */
74 0x1f, /* 0x03 */
75 0x03, /* 0x04 */
76 0x7b, /* 0x05 */
77 0x0f, /* 0x06 */
78 0x0f, /* 0x07 */
79 0xff, /* 0x08 */
80 0x00, /* 0x09 */
81 0x00, /* 0x0a */
82 0x00, /* 0x0b */
83 0x00, /* 0x0c */
84 0x00, /* 0x0d */
85 0x00, /* 0x0e */
86 0x00, /* 0x0f */
89 #define cbswap_32(__x) \
90 ((uint32_t)( \
91 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
92 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
93 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
94 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
96 #ifdef HOST_WORDS_BIGENDIAN
97 #define PAT(x) cbswap_32(x)
98 #else
99 #define PAT(x) (x)
100 #endif
102 #ifdef HOST_WORDS_BIGENDIAN
103 #define BIG 1
104 #else
105 #define BIG 0
106 #endif
108 #ifdef HOST_WORDS_BIGENDIAN
109 #define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
110 #else
111 #define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
112 #endif
114 static const uint32_t mask16[16] = {
115 PAT(0x00000000),
116 PAT(0x000000ff),
117 PAT(0x0000ff00),
118 PAT(0x0000ffff),
119 PAT(0x00ff0000),
120 PAT(0x00ff00ff),
121 PAT(0x00ffff00),
122 PAT(0x00ffffff),
123 PAT(0xff000000),
124 PAT(0xff0000ff),
125 PAT(0xff00ff00),
126 PAT(0xff00ffff),
127 PAT(0xffff0000),
128 PAT(0xffff00ff),
129 PAT(0xffffff00),
130 PAT(0xffffffff),
133 #undef PAT
135 #ifdef HOST_WORDS_BIGENDIAN
136 #define PAT(x) (x)
137 #else
138 #define PAT(x) cbswap_32(x)
139 #endif
141 static uint32_t expand4[256];
142 static uint16_t expand2[256];
143 static uint8_t expand4to8[16];
145 static void vga_update_memory_access(VGACommonState *s)
147 hwaddr base, offset, size;
149 if (s->legacy_address_space == NULL) {
150 return;
153 if (s->has_chain4_alias) {
154 memory_region_del_subregion(s->legacy_address_space, &s->chain4_alias);
155 object_unparent(OBJECT(&s->chain4_alias));
156 s->has_chain4_alias = false;
157 s->plane_updated = 0xf;
159 if ((s->sr[VGA_SEQ_PLANE_WRITE] & VGA_SR02_ALL_PLANES) ==
160 VGA_SR02_ALL_PLANES && s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
161 offset = 0;
162 switch ((s->gr[VGA_GFX_MISC] >> 2) & 3) {
163 case 0:
164 base = 0xa0000;
165 size = 0x20000;
166 break;
167 case 1:
168 base = 0xa0000;
169 size = 0x10000;
170 offset = s->bank_offset;
171 break;
172 case 2:
173 base = 0xb0000;
174 size = 0x8000;
175 break;
176 case 3:
177 default:
178 base = 0xb8000;
179 size = 0x8000;
180 break;
182 memory_region_init_alias(&s->chain4_alias, memory_region_owner(&s->vram),
183 "vga.chain4", &s->vram, offset, size);
184 memory_region_add_subregion_overlap(s->legacy_address_space, base,
185 &s->chain4_alias, 2);
186 s->has_chain4_alias = true;
190 static void vga_dumb_update_retrace_info(VGACommonState *s)
192 (void) s;
195 static void vga_precise_update_retrace_info(VGACommonState *s)
197 int htotal_chars;
198 int hretr_start_char;
199 int hretr_skew_chars;
200 int hretr_end_char;
202 int vtotal_lines;
203 int vretr_start_line;
204 int vretr_end_line;
206 int dots;
207 #if 0
208 int div2, sldiv2;
209 #endif
210 int clocking_mode;
211 int clock_sel;
212 const int clk_hz[] = {25175000, 28322000, 25175000, 25175000};
213 int64_t chars_per_sec;
214 struct vga_precise_retrace *r = &s->retrace_info.precise;
216 htotal_chars = s->cr[VGA_CRTC_H_TOTAL] + 5;
217 hretr_start_char = s->cr[VGA_CRTC_H_SYNC_START];
218 hretr_skew_chars = (s->cr[VGA_CRTC_H_SYNC_END] >> 5) & 3;
219 hretr_end_char = s->cr[VGA_CRTC_H_SYNC_END] & 0x1f;
221 vtotal_lines = (s->cr[VGA_CRTC_V_TOTAL] |
222 (((s->cr[VGA_CRTC_OVERFLOW] & 1) |
223 ((s->cr[VGA_CRTC_OVERFLOW] >> 4) & 2)) << 8)) + 2;
224 vretr_start_line = s->cr[VGA_CRTC_V_SYNC_START] |
225 ((((s->cr[VGA_CRTC_OVERFLOW] >> 2) & 1) |
226 ((s->cr[VGA_CRTC_OVERFLOW] >> 6) & 2)) << 8);
227 vretr_end_line = s->cr[VGA_CRTC_V_SYNC_END] & 0xf;
229 clocking_mode = (s->sr[VGA_SEQ_CLOCK_MODE] >> 3) & 1;
230 clock_sel = (s->msr >> 2) & 3;
231 dots = (s->msr & 1) ? 8 : 9;
233 chars_per_sec = clk_hz[clock_sel] / dots;
235 htotal_chars <<= clocking_mode;
237 r->total_chars = vtotal_lines * htotal_chars;
238 if (r->freq) {
239 r->ticks_per_char = NANOSECONDS_PER_SECOND / (r->total_chars * r->freq);
240 } else {
241 r->ticks_per_char = NANOSECONDS_PER_SECOND / chars_per_sec;
244 r->vstart = vretr_start_line;
245 r->vend = r->vstart + vretr_end_line + 1;
247 r->hstart = hretr_start_char + hretr_skew_chars;
248 r->hend = r->hstart + hretr_end_char + 1;
249 r->htotal = htotal_chars;
251 #if 0
252 div2 = (s->cr[VGA_CRTC_MODE] >> 2) & 1;
253 sldiv2 = (s->cr[VGA_CRTC_MODE] >> 3) & 1;
254 printf (
255 "hz=%f\n"
256 "htotal = %d\n"
257 "hretr_start = %d\n"
258 "hretr_skew = %d\n"
259 "hretr_end = %d\n"
260 "vtotal = %d\n"
261 "vretr_start = %d\n"
262 "vretr_end = %d\n"
263 "div2 = %d sldiv2 = %d\n"
264 "clocking_mode = %d\n"
265 "clock_sel = %d %d\n"
266 "dots = %d\n"
267 "ticks/char = %" PRId64 "\n"
268 "\n",
269 (double) NANOSECONDS_PER_SECOND / (r->ticks_per_char * r->total_chars),
270 htotal_chars,
271 hretr_start_char,
272 hretr_skew_chars,
273 hretr_end_char,
274 vtotal_lines,
275 vretr_start_line,
276 vretr_end_line,
277 div2, sldiv2,
278 clocking_mode,
279 clock_sel,
280 clk_hz[clock_sel],
281 dots,
282 r->ticks_per_char
284 #endif
287 static uint8_t vga_precise_retrace(VGACommonState *s)
289 struct vga_precise_retrace *r = &s->retrace_info.precise;
290 uint8_t val = s->st01 & ~(ST01_V_RETRACE | ST01_DISP_ENABLE);
292 if (r->total_chars) {
293 int cur_line, cur_line_char, cur_char;
294 int64_t cur_tick;
296 cur_tick = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
298 cur_char = (cur_tick / r->ticks_per_char) % r->total_chars;
299 cur_line = cur_char / r->htotal;
301 if (cur_line >= r->vstart && cur_line <= r->vend) {
302 val |= ST01_V_RETRACE | ST01_DISP_ENABLE;
303 } else {
304 cur_line_char = cur_char % r->htotal;
305 if (cur_line_char >= r->hstart && cur_line_char <= r->hend) {
306 val |= ST01_DISP_ENABLE;
310 return val;
311 } else {
312 return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
316 static uint8_t vga_dumb_retrace(VGACommonState *s)
318 return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
321 int vga_ioport_invalid(VGACommonState *s, uint32_t addr)
323 if (s->msr & VGA_MIS_COLOR) {
324 /* Color */
325 return (addr >= 0x3b0 && addr <= 0x3bf);
326 } else {
327 /* Monochrome */
328 return (addr >= 0x3d0 && addr <= 0x3df);
332 uint32_t vga_ioport_read(void *opaque, uint32_t addr)
334 VGACommonState *s = opaque;
335 int val, index;
337 if (vga_ioport_invalid(s, addr)) {
338 val = 0xff;
339 } else {
340 switch(addr) {
341 case VGA_ATT_W:
342 if (s->ar_flip_flop == 0) {
343 val = s->ar_index;
344 } else {
345 val = 0;
347 break;
348 case VGA_ATT_R:
349 index = s->ar_index & 0x1f;
350 if (index < VGA_ATT_C) {
351 val = s->ar[index];
352 } else {
353 val = 0;
355 break;
356 case VGA_MIS_W:
357 val = s->st00;
358 break;
359 case VGA_SEQ_I:
360 val = s->sr_index;
361 break;
362 case VGA_SEQ_D:
363 val = s->sr[s->sr_index];
364 #ifdef DEBUG_VGA_REG
365 printf("vga: read SR%x = 0x%02x\n", s->sr_index, val);
366 #endif
367 break;
368 case VGA_PEL_IR:
369 val = s->dac_state;
370 break;
371 case VGA_PEL_IW:
372 val = s->dac_write_index;
373 break;
374 case VGA_PEL_D:
375 val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
376 if (++s->dac_sub_index == 3) {
377 s->dac_sub_index = 0;
378 s->dac_read_index++;
380 break;
381 case VGA_FTC_R:
382 val = s->fcr;
383 break;
384 case VGA_MIS_R:
385 val = s->msr;
386 break;
387 case VGA_GFX_I:
388 val = s->gr_index;
389 break;
390 case VGA_GFX_D:
391 val = s->gr[s->gr_index];
392 #ifdef DEBUG_VGA_REG
393 printf("vga: read GR%x = 0x%02x\n", s->gr_index, val);
394 #endif
395 break;
396 case VGA_CRT_IM:
397 case VGA_CRT_IC:
398 val = s->cr_index;
399 break;
400 case VGA_CRT_DM:
401 case VGA_CRT_DC:
402 val = s->cr[s->cr_index];
403 #ifdef DEBUG_VGA_REG
404 printf("vga: read CR%x = 0x%02x\n", s->cr_index, val);
405 #endif
406 break;
407 case VGA_IS1_RM:
408 case VGA_IS1_RC:
409 /* just toggle to fool polling */
410 val = s->st01 = s->retrace(s);
411 s->ar_flip_flop = 0;
412 break;
413 default:
414 val = 0x00;
415 break;
418 #if defined(DEBUG_VGA)
419 printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
420 #endif
421 return val;
424 void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
426 VGACommonState *s = opaque;
427 int index;
429 /* check port range access depending on color/monochrome mode */
430 if (vga_ioport_invalid(s, addr)) {
431 return;
433 #ifdef DEBUG_VGA
434 printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
435 #endif
437 switch(addr) {
438 case VGA_ATT_W:
439 if (s->ar_flip_flop == 0) {
440 val &= 0x3f;
441 s->ar_index = val;
442 } else {
443 index = s->ar_index & 0x1f;
444 switch(index) {
445 case VGA_ATC_PALETTE0 ... VGA_ATC_PALETTEF:
446 s->ar[index] = val & 0x3f;
447 break;
448 case VGA_ATC_MODE:
449 s->ar[index] = val & ~0x10;
450 break;
451 case VGA_ATC_OVERSCAN:
452 s->ar[index] = val;
453 break;
454 case VGA_ATC_PLANE_ENABLE:
455 s->ar[index] = val & ~0xc0;
456 break;
457 case VGA_ATC_PEL:
458 s->ar[index] = val & ~0xf0;
459 break;
460 case VGA_ATC_COLOR_PAGE:
461 s->ar[index] = val & ~0xf0;
462 break;
463 default:
464 break;
467 s->ar_flip_flop ^= 1;
468 break;
469 case VGA_MIS_W:
470 s->msr = val & ~0x10;
471 s->update_retrace_info(s);
472 break;
473 case VGA_SEQ_I:
474 s->sr_index = val & 7;
475 break;
476 case VGA_SEQ_D:
477 #ifdef DEBUG_VGA_REG
478 printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
479 #endif
480 s->sr[s->sr_index] = val & sr_mask[s->sr_index];
481 if (s->sr_index == VGA_SEQ_CLOCK_MODE) {
482 s->update_retrace_info(s);
484 vga_update_memory_access(s);
485 break;
486 case VGA_PEL_IR:
487 s->dac_read_index = val;
488 s->dac_sub_index = 0;
489 s->dac_state = 3;
490 break;
491 case VGA_PEL_IW:
492 s->dac_write_index = val;
493 s->dac_sub_index = 0;
494 s->dac_state = 0;
495 break;
496 case VGA_PEL_D:
497 s->dac_cache[s->dac_sub_index] = val;
498 if (++s->dac_sub_index == 3) {
499 memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
500 s->dac_sub_index = 0;
501 s->dac_write_index++;
503 break;
504 case VGA_GFX_I:
505 s->gr_index = val & 0x0f;
506 break;
507 case VGA_GFX_D:
508 #ifdef DEBUG_VGA_REG
509 printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
510 #endif
511 s->gr[s->gr_index] = val & gr_mask[s->gr_index];
512 vga_update_memory_access(s);
513 break;
514 case VGA_CRT_IM:
515 case VGA_CRT_IC:
516 s->cr_index = val;
517 break;
518 case VGA_CRT_DM:
519 case VGA_CRT_DC:
520 #ifdef DEBUG_VGA_REG
521 printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
522 #endif
523 /* handle CR0-7 protection */
524 if ((s->cr[VGA_CRTC_V_SYNC_END] & VGA_CR11_LOCK_CR0_CR7) &&
525 s->cr_index <= VGA_CRTC_OVERFLOW) {
526 /* can always write bit 4 of CR7 */
527 if (s->cr_index == VGA_CRTC_OVERFLOW) {
528 s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x10) |
529 (val & 0x10);
531 return;
533 s->cr[s->cr_index] = val;
535 switch(s->cr_index) {
536 case VGA_CRTC_H_TOTAL:
537 case VGA_CRTC_H_SYNC_START:
538 case VGA_CRTC_H_SYNC_END:
539 case VGA_CRTC_V_TOTAL:
540 case VGA_CRTC_OVERFLOW:
541 case VGA_CRTC_V_SYNC_END:
542 case VGA_CRTC_MODE:
543 s->update_retrace_info(s);
544 break;
546 break;
547 case VGA_IS1_RM:
548 case VGA_IS1_RC:
549 s->fcr = val & 0x10;
550 break;
555 * Sanity check vbe register writes.
557 * As we don't have a way to signal errors to the guest in the bochs
558 * dispi interface we'll go adjust the registers to the closest valid
559 * value.
561 static void vbe_fixup_regs(VGACommonState *s)
563 uint16_t *r = s->vbe_regs;
564 uint32_t bits, linelength, maxy, offset;
566 if (!(r[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
567 /* vbe is turned off -- nothing to do */
568 return;
571 /* check depth */
572 switch (r[VBE_DISPI_INDEX_BPP]) {
573 case 4:
574 case 8:
575 case 16:
576 case 24:
577 case 32:
578 bits = r[VBE_DISPI_INDEX_BPP];
579 break;
580 case 15:
581 bits = 16;
582 break;
583 default:
584 bits = r[VBE_DISPI_INDEX_BPP] = 8;
585 break;
588 /* check width */
589 r[VBE_DISPI_INDEX_XRES] &= ~7u;
590 if (r[VBE_DISPI_INDEX_XRES] == 0) {
591 r[VBE_DISPI_INDEX_XRES] = 8;
593 if (r[VBE_DISPI_INDEX_XRES] > VBE_DISPI_MAX_XRES) {
594 r[VBE_DISPI_INDEX_XRES] = VBE_DISPI_MAX_XRES;
596 r[VBE_DISPI_INDEX_VIRT_WIDTH] &= ~7u;
597 if (r[VBE_DISPI_INDEX_VIRT_WIDTH] > VBE_DISPI_MAX_XRES) {
598 r[VBE_DISPI_INDEX_VIRT_WIDTH] = VBE_DISPI_MAX_XRES;
600 if (r[VBE_DISPI_INDEX_VIRT_WIDTH] < r[VBE_DISPI_INDEX_XRES]) {
601 r[VBE_DISPI_INDEX_VIRT_WIDTH] = r[VBE_DISPI_INDEX_XRES];
604 /* check height */
605 linelength = r[VBE_DISPI_INDEX_VIRT_WIDTH] * bits / 8;
606 maxy = s->vbe_size / linelength;
607 if (r[VBE_DISPI_INDEX_YRES] == 0) {
608 r[VBE_DISPI_INDEX_YRES] = 1;
610 if (r[VBE_DISPI_INDEX_YRES] > VBE_DISPI_MAX_YRES) {
611 r[VBE_DISPI_INDEX_YRES] = VBE_DISPI_MAX_YRES;
613 if (r[VBE_DISPI_INDEX_YRES] > maxy) {
614 r[VBE_DISPI_INDEX_YRES] = maxy;
617 /* check offset */
618 if (r[VBE_DISPI_INDEX_X_OFFSET] > VBE_DISPI_MAX_XRES) {
619 r[VBE_DISPI_INDEX_X_OFFSET] = VBE_DISPI_MAX_XRES;
621 if (r[VBE_DISPI_INDEX_Y_OFFSET] > VBE_DISPI_MAX_YRES) {
622 r[VBE_DISPI_INDEX_Y_OFFSET] = VBE_DISPI_MAX_YRES;
624 offset = r[VBE_DISPI_INDEX_X_OFFSET] * bits / 8;
625 offset += r[VBE_DISPI_INDEX_Y_OFFSET] * linelength;
626 if (offset + r[VBE_DISPI_INDEX_YRES] * linelength > s->vbe_size) {
627 r[VBE_DISPI_INDEX_Y_OFFSET] = 0;
628 offset = r[VBE_DISPI_INDEX_X_OFFSET] * bits / 8;
629 if (offset + r[VBE_DISPI_INDEX_YRES] * linelength > s->vbe_size) {
630 r[VBE_DISPI_INDEX_X_OFFSET] = 0;
631 offset = 0;
635 /* update vga state */
636 r[VBE_DISPI_INDEX_VIRT_HEIGHT] = maxy;
637 s->vbe_line_offset = linelength;
638 s->vbe_start_addr = offset / 4;
641 static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
643 VGACommonState *s = opaque;
644 uint32_t val;
645 val = s->vbe_index;
646 return val;
649 uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr)
651 VGACommonState *s = opaque;
652 uint32_t val;
654 if (s->vbe_index < VBE_DISPI_INDEX_NB) {
655 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_GETCAPS) {
656 switch(s->vbe_index) {
657 /* XXX: do not hardcode ? */
658 case VBE_DISPI_INDEX_XRES:
659 val = VBE_DISPI_MAX_XRES;
660 break;
661 case VBE_DISPI_INDEX_YRES:
662 val = VBE_DISPI_MAX_YRES;
663 break;
664 case VBE_DISPI_INDEX_BPP:
665 val = VBE_DISPI_MAX_BPP;
666 break;
667 default:
668 val = s->vbe_regs[s->vbe_index];
669 break;
671 } else {
672 val = s->vbe_regs[s->vbe_index];
674 } else if (s->vbe_index == VBE_DISPI_INDEX_VIDEO_MEMORY_64K) {
675 val = s->vbe_size / (64 * 1024);
676 } else {
677 val = 0;
679 #ifdef DEBUG_BOCHS_VBE
680 printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val);
681 #endif
682 return val;
685 void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val)
687 VGACommonState *s = opaque;
688 s->vbe_index = val;
691 void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
693 VGACommonState *s = opaque;
695 if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
696 #ifdef DEBUG_BOCHS_VBE
697 printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val);
698 #endif
699 switch(s->vbe_index) {
700 case VBE_DISPI_INDEX_ID:
701 if (val == VBE_DISPI_ID0 ||
702 val == VBE_DISPI_ID1 ||
703 val == VBE_DISPI_ID2 ||
704 val == VBE_DISPI_ID3 ||
705 val == VBE_DISPI_ID4) {
706 s->vbe_regs[s->vbe_index] = val;
708 break;
709 case VBE_DISPI_INDEX_XRES:
710 case VBE_DISPI_INDEX_YRES:
711 case VBE_DISPI_INDEX_BPP:
712 case VBE_DISPI_INDEX_VIRT_WIDTH:
713 case VBE_DISPI_INDEX_X_OFFSET:
714 case VBE_DISPI_INDEX_Y_OFFSET:
715 s->vbe_regs[s->vbe_index] = val;
716 vbe_fixup_regs(s);
717 break;
718 case VBE_DISPI_INDEX_BANK:
719 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
720 val &= (s->vbe_bank_mask >> 2);
721 } else {
722 val &= s->vbe_bank_mask;
724 s->vbe_regs[s->vbe_index] = val;
725 s->bank_offset = (val << 16);
726 vga_update_memory_access(s);
727 break;
728 case VBE_DISPI_INDEX_ENABLE:
729 if ((val & VBE_DISPI_ENABLED) &&
730 !(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
731 int h, shift_control;
733 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = 0;
734 s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
735 s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
736 s->vbe_regs[VBE_DISPI_INDEX_ENABLE] |= VBE_DISPI_ENABLED;
737 vbe_fixup_regs(s);
739 /* clear the screen */
740 if (!(val & VBE_DISPI_NOCLEARMEM)) {
741 memset(s->vram_ptr, 0,
742 s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
745 /* we initialize the VGA graphic mode */
746 /* graphic mode + memory map 1 */
747 s->gr[VGA_GFX_MISC] = (s->gr[VGA_GFX_MISC] & ~0x0c) | 0x04 |
748 VGA_GR06_GRAPHICS_MODE;
749 s->cr[VGA_CRTC_MODE] |= 3; /* no CGA modes */
750 s->cr[VGA_CRTC_OFFSET] = s->vbe_line_offset >> 3;
751 /* width */
752 s->cr[VGA_CRTC_H_DISP] =
753 (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
754 /* height (only meaningful if < 1024) */
755 h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
756 s->cr[VGA_CRTC_V_DISP_END] = h;
757 s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x42) |
758 ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
759 /* line compare to 1023 */
760 s->cr[VGA_CRTC_LINE_COMPARE] = 0xff;
761 s->cr[VGA_CRTC_OVERFLOW] |= 0x10;
762 s->cr[VGA_CRTC_MAX_SCAN] |= 0x40;
764 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
765 shift_control = 0;
766 s->sr[VGA_SEQ_CLOCK_MODE] &= ~8; /* no double line */
767 } else {
768 shift_control = 2;
769 /* set chain 4 mode */
770 s->sr[VGA_SEQ_MEMORY_MODE] |= VGA_SR04_CHN_4M;
771 /* activate all planes */
772 s->sr[VGA_SEQ_PLANE_WRITE] |= VGA_SR02_ALL_PLANES;
774 s->gr[VGA_GFX_MODE] = (s->gr[VGA_GFX_MODE] & ~0x60) |
775 (shift_control << 5);
776 s->cr[VGA_CRTC_MAX_SCAN] &= ~0x9f; /* no double scan */
777 } else {
778 s->bank_offset = 0;
780 s->dac_8bit = (val & VBE_DISPI_8BIT_DAC) > 0;
781 s->vbe_regs[s->vbe_index] = val;
782 vga_update_memory_access(s);
783 break;
784 default:
785 break;
790 /* called for accesses between 0xa0000 and 0xc0000 */
791 uint32_t vga_mem_readb(VGACommonState *s, hwaddr addr)
793 int memory_map_mode, plane;
794 uint32_t ret;
796 /* convert to VGA memory offset */
797 memory_map_mode = (s->gr[VGA_GFX_MISC] >> 2) & 3;
798 addr &= 0x1ffff;
799 switch(memory_map_mode) {
800 case 0:
801 break;
802 case 1:
803 if (addr >= 0x10000)
804 return 0xff;
805 addr += s->bank_offset;
806 break;
807 case 2:
808 addr -= 0x10000;
809 if (addr >= 0x8000)
810 return 0xff;
811 break;
812 default:
813 case 3:
814 addr -= 0x18000;
815 if (addr >= 0x8000)
816 return 0xff;
817 break;
820 if (s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
821 /* chain 4 mode : simplest access */
822 ret = s->vram_ptr[addr];
823 } else if (s->gr[VGA_GFX_MODE] & 0x10) {
824 /* odd/even mode (aka text mode mapping) */
825 plane = (s->gr[VGA_GFX_PLANE_READ] & 2) | (addr & 1);
826 ret = s->vram_ptr[((addr & ~1) << 1) | plane];
827 } else {
828 /* standard VGA latched access */
829 s->latch = ((uint32_t *)s->vram_ptr)[addr];
831 if (!(s->gr[VGA_GFX_MODE] & 0x08)) {
832 /* read mode 0 */
833 plane = s->gr[VGA_GFX_PLANE_READ];
834 ret = GET_PLANE(s->latch, plane);
835 } else {
836 /* read mode 1 */
837 ret = (s->latch ^ mask16[s->gr[VGA_GFX_COMPARE_VALUE]]) &
838 mask16[s->gr[VGA_GFX_COMPARE_MASK]];
839 ret |= ret >> 16;
840 ret |= ret >> 8;
841 ret = (~ret) & 0xff;
844 return ret;
847 /* called for accesses between 0xa0000 and 0xc0000 */
848 void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
850 int memory_map_mode, plane, write_mode, b, func_select, mask;
851 uint32_t write_mask, bit_mask, set_mask;
853 #ifdef DEBUG_VGA_MEM
854 printf("vga: [0x" TARGET_FMT_plx "] = 0x%02x\n", addr, val);
855 #endif
856 /* convert to VGA memory offset */
857 memory_map_mode = (s->gr[VGA_GFX_MISC] >> 2) & 3;
858 addr &= 0x1ffff;
859 switch(memory_map_mode) {
860 case 0:
861 break;
862 case 1:
863 if (addr >= 0x10000)
864 return;
865 addr += s->bank_offset;
866 break;
867 case 2:
868 addr -= 0x10000;
869 if (addr >= 0x8000)
870 return;
871 break;
872 default:
873 case 3:
874 addr -= 0x18000;
875 if (addr >= 0x8000)
876 return;
877 break;
880 if (s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
881 /* chain 4 mode : simplest access */
882 plane = addr & 3;
883 mask = (1 << plane);
884 if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
885 s->vram_ptr[addr] = val;
886 #ifdef DEBUG_VGA_MEM
887 printf("vga: chain4: [0x" TARGET_FMT_plx "]\n", addr);
888 #endif
889 s->plane_updated |= mask; /* only used to detect font change */
890 memory_region_set_dirty(&s->vram, addr, 1);
892 } else if (s->gr[VGA_GFX_MODE] & 0x10) {
893 /* odd/even mode (aka text mode mapping) */
894 plane = (s->gr[VGA_GFX_PLANE_READ] & 2) | (addr & 1);
895 mask = (1 << plane);
896 if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
897 addr = ((addr & ~1) << 1) | plane;
898 s->vram_ptr[addr] = val;
899 #ifdef DEBUG_VGA_MEM
900 printf("vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr);
901 #endif
902 s->plane_updated |= mask; /* only used to detect font change */
903 memory_region_set_dirty(&s->vram, addr, 1);
905 } else {
906 /* standard VGA latched access */
907 write_mode = s->gr[VGA_GFX_MODE] & 3;
908 switch(write_mode) {
909 default:
910 case 0:
911 /* rotate */
912 b = s->gr[VGA_GFX_DATA_ROTATE] & 7;
913 val = ((val >> b) | (val << (8 - b))) & 0xff;
914 val |= val << 8;
915 val |= val << 16;
917 /* apply set/reset mask */
918 set_mask = mask16[s->gr[VGA_GFX_SR_ENABLE]];
919 val = (val & ~set_mask) |
920 (mask16[s->gr[VGA_GFX_SR_VALUE]] & set_mask);
921 bit_mask = s->gr[VGA_GFX_BIT_MASK];
922 break;
923 case 1:
924 val = s->latch;
925 goto do_write;
926 case 2:
927 val = mask16[val & 0x0f];
928 bit_mask = s->gr[VGA_GFX_BIT_MASK];
929 break;
930 case 3:
931 /* rotate */
932 b = s->gr[VGA_GFX_DATA_ROTATE] & 7;
933 val = (val >> b) | (val << (8 - b));
935 bit_mask = s->gr[VGA_GFX_BIT_MASK] & val;
936 val = mask16[s->gr[VGA_GFX_SR_VALUE]];
937 break;
940 /* apply logical operation */
941 func_select = s->gr[VGA_GFX_DATA_ROTATE] >> 3;
942 switch(func_select) {
943 case 0:
944 default:
945 /* nothing to do */
946 break;
947 case 1:
948 /* and */
949 val &= s->latch;
950 break;
951 case 2:
952 /* or */
953 val |= s->latch;
954 break;
955 case 3:
956 /* xor */
957 val ^= s->latch;
958 break;
961 /* apply bit mask */
962 bit_mask |= bit_mask << 8;
963 bit_mask |= bit_mask << 16;
964 val = (val & bit_mask) | (s->latch & ~bit_mask);
966 do_write:
967 /* mask data according to sr[2] */
968 mask = s->sr[VGA_SEQ_PLANE_WRITE];
969 s->plane_updated |= mask; /* only used to detect font change */
970 write_mask = mask16[mask];
971 ((uint32_t *)s->vram_ptr)[addr] =
972 (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
973 (val & write_mask);
974 #ifdef DEBUG_VGA_MEM
975 printf("vga: latch: [0x" TARGET_FMT_plx "] mask=0x%08x val=0x%08x\n",
976 addr * 4, write_mask, val);
977 #endif
978 memory_region_set_dirty(&s->vram, addr << 2, sizeof(uint32_t));
982 typedef void vga_draw_line_func(VGACommonState *s1, uint8_t *d,
983 const uint8_t *s, int width);
985 #include "vga-helpers.h"
987 /* return true if the palette was modified */
988 static int update_palette16(VGACommonState *s)
990 int full_update, i;
991 uint32_t v, col, *palette;
993 full_update = 0;
994 palette = s->last_palette;
995 for(i = 0; i < 16; i++) {
996 v = s->ar[i];
997 if (s->ar[VGA_ATC_MODE] & 0x80) {
998 v = ((s->ar[VGA_ATC_COLOR_PAGE] & 0xf) << 4) | (v & 0xf);
999 } else {
1000 v = ((s->ar[VGA_ATC_COLOR_PAGE] & 0xc) << 4) | (v & 0x3f);
1002 v = v * 3;
1003 col = rgb_to_pixel32(c6_to_8(s->palette[v]),
1004 c6_to_8(s->palette[v + 1]),
1005 c6_to_8(s->palette[v + 2]));
1006 if (col != palette[i]) {
1007 full_update = 1;
1008 palette[i] = col;
1011 return full_update;
1014 /* return true if the palette was modified */
1015 static int update_palette256(VGACommonState *s)
1017 int full_update, i;
1018 uint32_t v, col, *palette;
1020 full_update = 0;
1021 palette = s->last_palette;
1022 v = 0;
1023 for(i = 0; i < 256; i++) {
1024 if (s->dac_8bit) {
1025 col = rgb_to_pixel32(s->palette[v],
1026 s->palette[v + 1],
1027 s->palette[v + 2]);
1028 } else {
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]));
1033 if (col != palette[i]) {
1034 full_update = 1;
1035 palette[i] = col;
1037 v += 3;
1039 return full_update;
1042 static void vga_get_offsets(VGACommonState *s,
1043 uint32_t *pline_offset,
1044 uint32_t *pstart_addr,
1045 uint32_t *pline_compare)
1047 uint32_t start_addr, line_offset, line_compare;
1049 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1050 line_offset = s->vbe_line_offset;
1051 start_addr = s->vbe_start_addr;
1052 line_compare = 65535;
1053 } else {
1054 /* compute line_offset in bytes */
1055 line_offset = s->cr[VGA_CRTC_OFFSET];
1056 line_offset <<= 3;
1058 /* starting address */
1059 start_addr = s->cr[VGA_CRTC_START_LO] |
1060 (s->cr[VGA_CRTC_START_HI] << 8);
1062 /* line compare */
1063 line_compare = s->cr[VGA_CRTC_LINE_COMPARE] |
1064 ((s->cr[VGA_CRTC_OVERFLOW] & 0x10) << 4) |
1065 ((s->cr[VGA_CRTC_MAX_SCAN] & 0x40) << 3);
1067 *pline_offset = line_offset;
1068 *pstart_addr = start_addr;
1069 *pline_compare = line_compare;
1072 /* update start_addr and line_offset. Return TRUE if modified */
1073 static int update_basic_params(VGACommonState *s)
1075 int full_update;
1076 uint32_t start_addr, line_offset, line_compare;
1078 full_update = 0;
1080 s->get_offsets(s, &line_offset, &start_addr, &line_compare);
1082 if (line_offset != s->line_offset ||
1083 start_addr != s->start_addr ||
1084 line_compare != s->line_compare) {
1085 s->line_offset = line_offset;
1086 s->start_addr = start_addr;
1087 s->line_compare = line_compare;
1088 full_update = 1;
1090 return full_update;
1094 static const uint8_t cursor_glyph[32 * 4] = {
1095 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1096 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1097 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1098 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1099 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1100 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1101 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1102 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1103 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1104 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1105 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1106 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1107 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1108 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1109 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1110 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1113 static void vga_get_text_resolution(VGACommonState *s, int *pwidth, int *pheight,
1114 int *pcwidth, int *pcheight)
1116 int width, cwidth, height, cheight;
1118 /* total width & height */
1119 cheight = (s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1;
1120 cwidth = 8;
1121 if (!(s->sr[VGA_SEQ_CLOCK_MODE] & VGA_SR01_CHAR_CLK_8DOTS)) {
1122 cwidth = 9;
1124 if (s->sr[VGA_SEQ_CLOCK_MODE] & 0x08) {
1125 cwidth = 16; /* NOTE: no 18 pixel wide */
1127 width = (s->cr[VGA_CRTC_H_DISP] + 1);
1128 if (s->cr[VGA_CRTC_V_TOTAL] == 100) {
1129 /* ugly hack for CGA 160x100x16 - explain me the logic */
1130 height = 100;
1131 } else {
1132 height = s->cr[VGA_CRTC_V_DISP_END] |
1133 ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) |
1134 ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3);
1135 height = (height + 1) / cheight;
1138 *pwidth = width;
1139 *pheight = height;
1140 *pcwidth = cwidth;
1141 *pcheight = cheight;
1145 * Text mode update
1146 * Missing:
1147 * - double scan
1148 * - double width
1149 * - underline
1150 * - flashing
1152 static void vga_draw_text(VGACommonState *s, int full_update)
1154 DisplaySurface *surface = qemu_console_surface(s->con);
1155 int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
1156 int cx_min, cx_max, linesize, x_incr, line, line1;
1157 uint32_t offset, fgcol, bgcol, v, cursor_offset;
1158 uint8_t *d1, *d, *src, *dest, *cursor_ptr;
1159 const uint8_t *font_ptr, *font_base[2];
1160 int dup9, line_offset;
1161 uint32_t *palette;
1162 uint32_t *ch_attr_ptr;
1163 int64_t now = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
1165 /* compute font data address (in plane 2) */
1166 v = s->sr[VGA_SEQ_CHARACTER_MAP];
1167 offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
1168 if (offset != s->font_offsets[0]) {
1169 s->font_offsets[0] = offset;
1170 full_update = 1;
1172 font_base[0] = s->vram_ptr + offset;
1174 offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
1175 font_base[1] = s->vram_ptr + offset;
1176 if (offset != s->font_offsets[1]) {
1177 s->font_offsets[1] = offset;
1178 full_update = 1;
1180 if (s->plane_updated & (1 << 2) || s->has_chain4_alias) {
1181 /* if the plane 2 was modified since the last display, it
1182 indicates the font may have been modified */
1183 s->plane_updated = 0;
1184 full_update = 1;
1186 full_update |= update_basic_params(s);
1188 line_offset = s->line_offset;
1190 vga_get_text_resolution(s, &width, &height, &cw, &cheight);
1191 if ((height * width) <= 1) {
1192 /* better than nothing: exit if transient size is too small */
1193 return;
1195 if ((height * width) > CH_ATTR_SIZE) {
1196 /* better than nothing: exit if transient size is too big */
1197 return;
1200 if (width != s->last_width || height != s->last_height ||
1201 cw != s->last_cw || cheight != s->last_ch || s->last_depth) {
1202 s->last_scr_width = width * cw;
1203 s->last_scr_height = height * cheight;
1204 qemu_console_resize(s->con, s->last_scr_width, s->last_scr_height);
1205 surface = qemu_console_surface(s->con);
1206 dpy_text_resize(s->con, width, height);
1207 s->last_depth = 0;
1208 s->last_width = width;
1209 s->last_height = height;
1210 s->last_ch = cheight;
1211 s->last_cw = cw;
1212 full_update = 1;
1214 full_update |= update_palette16(s);
1215 palette = s->last_palette;
1216 x_incr = cw * surface_bytes_per_pixel(surface);
1218 if (full_update) {
1219 s->full_update_text = 1;
1221 if (s->full_update_gfx) {
1222 s->full_update_gfx = 0;
1223 full_update |= 1;
1226 cursor_offset = ((s->cr[VGA_CRTC_CURSOR_HI] << 8) |
1227 s->cr[VGA_CRTC_CURSOR_LO]) - s->start_addr;
1228 if (cursor_offset != s->cursor_offset ||
1229 s->cr[VGA_CRTC_CURSOR_START] != s->cursor_start ||
1230 s->cr[VGA_CRTC_CURSOR_END] != s->cursor_end) {
1231 /* if the cursor position changed, we update the old and new
1232 chars */
1233 if (s->cursor_offset < CH_ATTR_SIZE)
1234 s->last_ch_attr[s->cursor_offset] = -1;
1235 if (cursor_offset < CH_ATTR_SIZE)
1236 s->last_ch_attr[cursor_offset] = -1;
1237 s->cursor_offset = cursor_offset;
1238 s->cursor_start = s->cr[VGA_CRTC_CURSOR_START];
1239 s->cursor_end = s->cr[VGA_CRTC_CURSOR_END];
1241 cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
1242 if (now >= s->cursor_blink_time) {
1243 s->cursor_blink_time = now + VGA_TEXT_CURSOR_PERIOD_MS / 2;
1244 s->cursor_visible_phase = !s->cursor_visible_phase;
1247 dest = surface_data(surface);
1248 linesize = surface_stride(surface);
1249 ch_attr_ptr = s->last_ch_attr;
1250 line = 0;
1251 offset = s->start_addr * 4;
1252 for(cy = 0; cy < height; cy++) {
1253 d1 = dest;
1254 src = s->vram_ptr + offset;
1255 cx_min = width;
1256 cx_max = -1;
1257 for(cx = 0; cx < width; cx++) {
1258 ch_attr = *(uint16_t *)src;
1259 if (full_update || ch_attr != *ch_attr_ptr || src == cursor_ptr) {
1260 if (cx < cx_min)
1261 cx_min = cx;
1262 if (cx > cx_max)
1263 cx_max = cx;
1264 *ch_attr_ptr = ch_attr;
1265 #ifdef HOST_WORDS_BIGENDIAN
1266 ch = ch_attr >> 8;
1267 cattr = ch_attr & 0xff;
1268 #else
1269 ch = ch_attr & 0xff;
1270 cattr = ch_attr >> 8;
1271 #endif
1272 font_ptr = font_base[(cattr >> 3) & 1];
1273 font_ptr += 32 * 4 * ch;
1274 bgcol = palette[cattr >> 4];
1275 fgcol = palette[cattr & 0x0f];
1276 if (cw == 16) {
1277 vga_draw_glyph16(d1, linesize,
1278 font_ptr, cheight, fgcol, bgcol);
1279 } else if (cw != 9) {
1280 vga_draw_glyph8(d1, linesize,
1281 font_ptr, cheight, fgcol, bgcol);
1282 } else {
1283 dup9 = 0;
1284 if (ch >= 0xb0 && ch <= 0xdf &&
1285 (s->ar[VGA_ATC_MODE] & 0x04)) {
1286 dup9 = 1;
1288 vga_draw_glyph9(d1, linesize,
1289 font_ptr, cheight, fgcol, bgcol, dup9);
1291 if (src == cursor_ptr &&
1292 !(s->cr[VGA_CRTC_CURSOR_START] & 0x20) &&
1293 s->cursor_visible_phase) {
1294 int line_start, line_last, h;
1295 /* draw the cursor */
1296 line_start = s->cr[VGA_CRTC_CURSOR_START] & 0x1f;
1297 line_last = s->cr[VGA_CRTC_CURSOR_END] & 0x1f;
1298 /* XXX: check that */
1299 if (line_last > cheight - 1)
1300 line_last = cheight - 1;
1301 if (line_last >= line_start && line_start < cheight) {
1302 h = line_last - line_start + 1;
1303 d = d1 + linesize * line_start;
1304 if (cw == 16) {
1305 vga_draw_glyph16(d, linesize,
1306 cursor_glyph, h, fgcol, bgcol);
1307 } else if (cw != 9) {
1308 vga_draw_glyph8(d, linesize,
1309 cursor_glyph, h, fgcol, bgcol);
1310 } else {
1311 vga_draw_glyph9(d, linesize,
1312 cursor_glyph, h, fgcol, bgcol, 1);
1317 d1 += x_incr;
1318 src += 4;
1319 ch_attr_ptr++;
1321 if (cx_max != -1) {
1322 dpy_gfx_update(s->con, cx_min * cw, cy * cheight,
1323 (cx_max - cx_min + 1) * cw, cheight);
1325 dest += linesize * cheight;
1326 line1 = line + cheight;
1327 offset += line_offset;
1328 if (line < s->line_compare && line1 >= s->line_compare) {
1329 offset = 0;
1331 line = line1;
1335 enum {
1336 VGA_DRAW_LINE2,
1337 VGA_DRAW_LINE2D2,
1338 VGA_DRAW_LINE4,
1339 VGA_DRAW_LINE4D2,
1340 VGA_DRAW_LINE8D2,
1341 VGA_DRAW_LINE8,
1342 VGA_DRAW_LINE15_LE,
1343 VGA_DRAW_LINE16_LE,
1344 VGA_DRAW_LINE24_LE,
1345 VGA_DRAW_LINE32_LE,
1346 VGA_DRAW_LINE15_BE,
1347 VGA_DRAW_LINE16_BE,
1348 VGA_DRAW_LINE24_BE,
1349 VGA_DRAW_LINE32_BE,
1350 VGA_DRAW_LINE_NB,
1353 static vga_draw_line_func * const vga_draw_line_table[VGA_DRAW_LINE_NB] = {
1354 vga_draw_line2,
1355 vga_draw_line2d2,
1356 vga_draw_line4,
1357 vga_draw_line4d2,
1358 vga_draw_line8d2,
1359 vga_draw_line8,
1360 vga_draw_line15_le,
1361 vga_draw_line16_le,
1362 vga_draw_line24_le,
1363 vga_draw_line32_le,
1364 vga_draw_line15_be,
1365 vga_draw_line16_be,
1366 vga_draw_line24_be,
1367 vga_draw_line32_be,
1370 static int vga_get_bpp(VGACommonState *s)
1372 int ret;
1374 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1375 ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
1376 } else {
1377 ret = 0;
1379 return ret;
1382 static void vga_get_resolution(VGACommonState *s, int *pwidth, int *pheight)
1384 int width, height;
1386 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1387 width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
1388 height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
1389 } else {
1390 width = (s->cr[VGA_CRTC_H_DISP] + 1) * 8;
1391 height = s->cr[VGA_CRTC_V_DISP_END] |
1392 ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) |
1393 ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3);
1394 height = (height + 1);
1396 *pwidth = width;
1397 *pheight = height;
1400 void vga_invalidate_scanlines(VGACommonState *s, int y1, int y2)
1402 int y;
1403 if (y1 >= VGA_MAX_HEIGHT)
1404 return;
1405 if (y2 >= VGA_MAX_HEIGHT)
1406 y2 = VGA_MAX_HEIGHT;
1407 for(y = y1; y < y2; y++) {
1408 s->invalidated_y_table[y >> 5] |= 1 << (y & 0x1f);
1412 void vga_sync_dirty_bitmap(VGACommonState *s)
1414 memory_region_sync_dirty_bitmap(&s->vram);
1417 void vga_dirty_log_start(VGACommonState *s)
1419 memory_region_set_log(&s->vram, true, DIRTY_MEMORY_VGA);
1422 void vga_dirty_log_stop(VGACommonState *s)
1424 memory_region_set_log(&s->vram, false, DIRTY_MEMORY_VGA);
1428 * graphic modes
1430 static void vga_draw_graphic(VGACommonState *s, int full_update)
1432 DisplaySurface *surface = qemu_console_surface(s->con);
1433 int y1, y, update, linesize, y_start, double_scan, mask, depth;
1434 int width, height, shift_control, line_offset, bwidth, bits;
1435 ram_addr_t page0, page1, page_min, page_max;
1436 int disp_width, multi_scan, multi_run;
1437 uint8_t *d;
1438 uint32_t v, addr1, addr;
1439 vga_draw_line_func *vga_draw_line = NULL;
1440 bool share_surface;
1441 pixman_format_code_t format;
1442 #ifdef HOST_WORDS_BIGENDIAN
1443 bool byteswap = !s->big_endian_fb;
1444 #else
1445 bool byteswap = s->big_endian_fb;
1446 #endif
1448 full_update |= update_basic_params(s);
1450 if (!full_update)
1451 vga_sync_dirty_bitmap(s);
1453 s->get_resolution(s, &width, &height);
1454 disp_width = width;
1456 shift_control = (s->gr[VGA_GFX_MODE] >> 5) & 3;
1457 double_scan = (s->cr[VGA_CRTC_MAX_SCAN] >> 7);
1458 if (shift_control != 1) {
1459 multi_scan = (((s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1) << double_scan)
1460 - 1;
1461 } else {
1462 /* in CGA modes, multi_scan is ignored */
1463 /* XXX: is it correct ? */
1464 multi_scan = double_scan;
1466 multi_run = multi_scan;
1467 if (shift_control != s->shift_control ||
1468 double_scan != s->double_scan) {
1469 full_update = 1;
1470 s->shift_control = shift_control;
1471 s->double_scan = double_scan;
1474 if (shift_control == 0) {
1475 if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
1476 disp_width <<= 1;
1478 } else if (shift_control == 1) {
1479 if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
1480 disp_width <<= 1;
1484 depth = s->get_bpp(s);
1487 * Check whether we can share the surface with the backend
1488 * or whether we need a shadow surface. We share native
1489 * endian surfaces for 15bpp and above and byteswapped
1490 * surfaces for 24bpp and above.
1492 format = qemu_default_pixman_format(depth, !byteswap);
1493 if (format) {
1494 share_surface = dpy_gfx_check_format(s->con, format)
1495 && !s->force_shadow;
1496 } else {
1497 share_surface = false;
1499 if (s->line_offset != s->last_line_offset ||
1500 disp_width != s->last_width ||
1501 height != s->last_height ||
1502 s->last_depth != depth ||
1503 s->last_byteswap != byteswap ||
1504 share_surface != is_buffer_shared(surface)) {
1505 if (share_surface) {
1506 surface = qemu_create_displaysurface_from(disp_width,
1507 height, format, s->line_offset,
1508 s->vram_ptr + (s->start_addr * 4));
1509 dpy_gfx_replace_surface(s->con, surface);
1510 #ifdef DEBUG_VGA
1511 printf("VGA: Using shared surface for depth=%d swap=%d\n",
1512 depth, byteswap);
1513 #endif
1514 } else {
1515 qemu_console_resize(s->con, disp_width, height);
1516 surface = qemu_console_surface(s->con);
1517 #ifdef DEBUG_VGA
1518 printf("VGA: Using shadow surface for depth=%d swap=%d\n",
1519 depth, byteswap);
1520 #endif
1522 s->last_scr_width = disp_width;
1523 s->last_scr_height = height;
1524 s->last_width = disp_width;
1525 s->last_height = height;
1526 s->last_line_offset = s->line_offset;
1527 s->last_depth = depth;
1528 s->last_byteswap = byteswap;
1529 full_update = 1;
1530 } else if (is_buffer_shared(surface) &&
1531 (full_update || surface_data(surface) != s->vram_ptr
1532 + (s->start_addr * 4))) {
1533 pixman_format_code_t format =
1534 qemu_default_pixman_format(depth, !byteswap);
1535 surface = qemu_create_displaysurface_from(disp_width,
1536 height, format, s->line_offset,
1537 s->vram_ptr + (s->start_addr * 4));
1538 dpy_gfx_replace_surface(s->con, surface);
1541 if (shift_control == 0) {
1542 full_update |= update_palette16(s);
1543 if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
1544 v = VGA_DRAW_LINE4D2;
1545 } else {
1546 v = VGA_DRAW_LINE4;
1548 bits = 4;
1549 } else if (shift_control == 1) {
1550 full_update |= update_palette16(s);
1551 if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
1552 v = VGA_DRAW_LINE2D2;
1553 } else {
1554 v = VGA_DRAW_LINE2;
1556 bits = 4;
1557 } else {
1558 switch(s->get_bpp(s)) {
1559 default:
1560 case 0:
1561 full_update |= update_palette256(s);
1562 v = VGA_DRAW_LINE8D2;
1563 bits = 4;
1564 break;
1565 case 8:
1566 full_update |= update_palette256(s);
1567 v = VGA_DRAW_LINE8;
1568 bits = 8;
1569 break;
1570 case 15:
1571 v = s->big_endian_fb ? VGA_DRAW_LINE15_BE : VGA_DRAW_LINE15_LE;
1572 bits = 16;
1573 break;
1574 case 16:
1575 v = s->big_endian_fb ? VGA_DRAW_LINE16_BE : VGA_DRAW_LINE16_LE;
1576 bits = 16;
1577 break;
1578 case 24:
1579 v = s->big_endian_fb ? VGA_DRAW_LINE24_BE : VGA_DRAW_LINE24_LE;
1580 bits = 24;
1581 break;
1582 case 32:
1583 v = s->big_endian_fb ? VGA_DRAW_LINE32_BE : VGA_DRAW_LINE32_LE;
1584 bits = 32;
1585 break;
1588 vga_draw_line = vga_draw_line_table[v];
1590 if (!is_buffer_shared(surface) && s->cursor_invalidate) {
1591 s->cursor_invalidate(s);
1594 line_offset = s->line_offset;
1595 #if 0
1596 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",
1597 width, height, v, line_offset, s->cr[9], s->cr[VGA_CRTC_MODE],
1598 s->line_compare, s->sr[VGA_SEQ_CLOCK_MODE]);
1599 #endif
1600 addr1 = (s->start_addr * 4);
1601 bwidth = (width * bits + 7) / 8;
1602 y_start = -1;
1603 page_min = -1;
1604 page_max = 0;
1605 d = surface_data(surface);
1606 linesize = surface_stride(surface);
1607 y1 = 0;
1608 for(y = 0; y < height; y++) {
1609 addr = addr1;
1610 if (!(s->cr[VGA_CRTC_MODE] & 1)) {
1611 int shift;
1612 /* CGA compatibility handling */
1613 shift = 14 + ((s->cr[VGA_CRTC_MODE] >> 6) & 1);
1614 addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
1616 if (!(s->cr[VGA_CRTC_MODE] & 2)) {
1617 addr = (addr & ~0x8000) | ((y1 & 2) << 14);
1619 update = full_update;
1620 page0 = addr;
1621 page1 = addr + bwidth - 1;
1622 update |= memory_region_get_dirty(&s->vram, page0, page1 - page0,
1623 DIRTY_MEMORY_VGA);
1624 /* explicit invalidation for the hardware cursor */
1625 update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
1626 if (update) {
1627 if (y_start < 0)
1628 y_start = y;
1629 if (page0 < page_min)
1630 page_min = page0;
1631 if (page1 > page_max)
1632 page_max = page1;
1633 if (!(is_buffer_shared(surface))) {
1634 vga_draw_line(s, d, s->vram_ptr + addr, width);
1635 if (s->cursor_draw_line)
1636 s->cursor_draw_line(s, d, y);
1638 } else {
1639 if (y_start >= 0) {
1640 /* flush to display */
1641 dpy_gfx_update(s->con, 0, y_start,
1642 disp_width, y - y_start);
1643 y_start = -1;
1646 if (!multi_run) {
1647 mask = (s->cr[VGA_CRTC_MODE] & 3) ^ 3;
1648 if ((y1 & mask) == mask)
1649 addr1 += line_offset;
1650 y1++;
1651 multi_run = multi_scan;
1652 } else {
1653 multi_run--;
1655 /* line compare acts on the displayed lines */
1656 if (y == s->line_compare)
1657 addr1 = 0;
1658 d += linesize;
1660 if (y_start >= 0) {
1661 /* flush to display */
1662 dpy_gfx_update(s->con, 0, y_start,
1663 disp_width, y - y_start);
1665 /* reset modified pages */
1666 if (page_max >= page_min) {
1667 memory_region_reset_dirty(&s->vram,
1668 page_min,
1669 page_max - page_min,
1670 DIRTY_MEMORY_VGA);
1672 memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
1675 static void vga_draw_blank(VGACommonState *s, int full_update)
1677 DisplaySurface *surface = qemu_console_surface(s->con);
1678 int i, w;
1679 uint8_t *d;
1681 if (!full_update)
1682 return;
1683 if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
1684 return;
1686 w = s->last_scr_width * surface_bytes_per_pixel(surface);
1687 d = surface_data(surface);
1688 for(i = 0; i < s->last_scr_height; i++) {
1689 memset(d, 0, w);
1690 d += surface_stride(surface);
1692 dpy_gfx_update(s->con, 0, 0,
1693 s->last_scr_width, s->last_scr_height);
1696 #define GMODE_TEXT 0
1697 #define GMODE_GRAPH 1
1698 #define GMODE_BLANK 2
1700 static void vga_update_display(void *opaque)
1702 VGACommonState *s = opaque;
1703 DisplaySurface *surface = qemu_console_surface(s->con);
1704 int full_update, graphic_mode;
1706 qemu_flush_coalesced_mmio_buffer();
1708 if (surface_bits_per_pixel(surface) == 0) {
1709 /* nothing to do */
1710 } else {
1711 full_update = 0;
1712 if (!(s->ar_index & 0x20)) {
1713 graphic_mode = GMODE_BLANK;
1714 } else {
1715 graphic_mode = s->gr[VGA_GFX_MISC] & VGA_GR06_GRAPHICS_MODE;
1717 if (graphic_mode != s->graphic_mode) {
1718 s->graphic_mode = graphic_mode;
1719 s->cursor_blink_time = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
1720 full_update = 1;
1722 switch(graphic_mode) {
1723 case GMODE_TEXT:
1724 vga_draw_text(s, full_update);
1725 break;
1726 case GMODE_GRAPH:
1727 vga_draw_graphic(s, full_update);
1728 break;
1729 case GMODE_BLANK:
1730 default:
1731 vga_draw_blank(s, full_update);
1732 break;
1737 /* force a full display refresh */
1738 static void vga_invalidate_display(void *opaque)
1740 VGACommonState *s = opaque;
1742 s->last_width = -1;
1743 s->last_height = -1;
1746 void vga_common_reset(VGACommonState *s)
1748 s->sr_index = 0;
1749 memset(s->sr, '\0', sizeof(s->sr));
1750 s->gr_index = 0;
1751 memset(s->gr, '\0', sizeof(s->gr));
1752 s->ar_index = 0;
1753 memset(s->ar, '\0', sizeof(s->ar));
1754 s->ar_flip_flop = 0;
1755 s->cr_index = 0;
1756 memset(s->cr, '\0', sizeof(s->cr));
1757 s->msr = 0;
1758 s->fcr = 0;
1759 s->st00 = 0;
1760 s->st01 = 0;
1761 s->dac_state = 0;
1762 s->dac_sub_index = 0;
1763 s->dac_read_index = 0;
1764 s->dac_write_index = 0;
1765 memset(s->dac_cache, '\0', sizeof(s->dac_cache));
1766 s->dac_8bit = 0;
1767 memset(s->palette, '\0', sizeof(s->palette));
1768 s->bank_offset = 0;
1769 s->vbe_index = 0;
1770 memset(s->vbe_regs, '\0', sizeof(s->vbe_regs));
1771 s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID5;
1772 s->vbe_start_addr = 0;
1773 s->vbe_line_offset = 0;
1774 s->vbe_bank_mask = (s->vram_size >> 16) - 1;
1775 memset(s->font_offsets, '\0', sizeof(s->font_offsets));
1776 s->graphic_mode = -1; /* force full update */
1777 s->shift_control = 0;
1778 s->double_scan = 0;
1779 s->line_offset = 0;
1780 s->line_compare = 0;
1781 s->start_addr = 0;
1782 s->plane_updated = 0;
1783 s->last_cw = 0;
1784 s->last_ch = 0;
1785 s->last_width = 0;
1786 s->last_height = 0;
1787 s->last_scr_width = 0;
1788 s->last_scr_height = 0;
1789 s->cursor_start = 0;
1790 s->cursor_end = 0;
1791 s->cursor_offset = 0;
1792 s->big_endian_fb = s->default_endian_fb;
1793 memset(s->invalidated_y_table, '\0', sizeof(s->invalidated_y_table));
1794 memset(s->last_palette, '\0', sizeof(s->last_palette));
1795 memset(s->last_ch_attr, '\0', sizeof(s->last_ch_attr));
1796 switch (vga_retrace_method) {
1797 case VGA_RETRACE_DUMB:
1798 break;
1799 case VGA_RETRACE_PRECISE:
1800 memset(&s->retrace_info, 0, sizeof (s->retrace_info));
1801 break;
1803 vga_update_memory_access(s);
1806 static void vga_reset(void *opaque)
1808 VGACommonState *s = opaque;
1809 vga_common_reset(s);
1812 #define TEXTMODE_X(x) ((x) % width)
1813 #define TEXTMODE_Y(x) ((x) / width)
1814 #define VMEM2CHTYPE(v) ((v & 0xff0007ff) | \
1815 ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1))
1816 /* relay text rendering to the display driver
1817 * instead of doing a full vga_update_display() */
1818 static void vga_update_text(void *opaque, console_ch_t *chardata)
1820 VGACommonState *s = opaque;
1821 int graphic_mode, i, cursor_offset, cursor_visible;
1822 int cw, cheight, width, height, size, c_min, c_max;
1823 uint32_t *src;
1824 console_ch_t *dst, val;
1825 char msg_buffer[80];
1826 int full_update = 0;
1828 qemu_flush_coalesced_mmio_buffer();
1830 if (!(s->ar_index & 0x20)) {
1831 graphic_mode = GMODE_BLANK;
1832 } else {
1833 graphic_mode = s->gr[VGA_GFX_MISC] & VGA_GR06_GRAPHICS_MODE;
1835 if (graphic_mode != s->graphic_mode) {
1836 s->graphic_mode = graphic_mode;
1837 full_update = 1;
1839 if (s->last_width == -1) {
1840 s->last_width = 0;
1841 full_update = 1;
1844 switch (graphic_mode) {
1845 case GMODE_TEXT:
1846 /* TODO: update palette */
1847 full_update |= update_basic_params(s);
1849 /* total width & height */
1850 cheight = (s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1;
1851 cw = 8;
1852 if (!(s->sr[VGA_SEQ_CLOCK_MODE] & VGA_SR01_CHAR_CLK_8DOTS)) {
1853 cw = 9;
1855 if (s->sr[VGA_SEQ_CLOCK_MODE] & 0x08) {
1856 cw = 16; /* NOTE: no 18 pixel wide */
1858 width = (s->cr[VGA_CRTC_H_DISP] + 1);
1859 if (s->cr[VGA_CRTC_V_TOTAL] == 100) {
1860 /* ugly hack for CGA 160x100x16 - explain me the logic */
1861 height = 100;
1862 } else {
1863 height = s->cr[VGA_CRTC_V_DISP_END] |
1864 ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) |
1865 ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3);
1866 height = (height + 1) / cheight;
1869 size = (height * width);
1870 if (size > CH_ATTR_SIZE) {
1871 if (!full_update)
1872 return;
1874 snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Text mode",
1875 width, height);
1876 break;
1879 if (width != s->last_width || height != s->last_height ||
1880 cw != s->last_cw || cheight != s->last_ch) {
1881 s->last_scr_width = width * cw;
1882 s->last_scr_height = height * cheight;
1883 qemu_console_resize(s->con, s->last_scr_width, s->last_scr_height);
1884 dpy_text_resize(s->con, width, height);
1885 s->last_depth = 0;
1886 s->last_width = width;
1887 s->last_height = height;
1888 s->last_ch = cheight;
1889 s->last_cw = cw;
1890 full_update = 1;
1893 if (full_update) {
1894 s->full_update_gfx = 1;
1896 if (s->full_update_text) {
1897 s->full_update_text = 0;
1898 full_update |= 1;
1901 /* Update "hardware" cursor */
1902 cursor_offset = ((s->cr[VGA_CRTC_CURSOR_HI] << 8) |
1903 s->cr[VGA_CRTC_CURSOR_LO]) - s->start_addr;
1904 if (cursor_offset != s->cursor_offset ||
1905 s->cr[VGA_CRTC_CURSOR_START] != s->cursor_start ||
1906 s->cr[VGA_CRTC_CURSOR_END] != s->cursor_end || full_update) {
1907 cursor_visible = !(s->cr[VGA_CRTC_CURSOR_START] & 0x20);
1908 if (cursor_visible && cursor_offset < size && cursor_offset >= 0)
1909 dpy_text_cursor(s->con,
1910 TEXTMODE_X(cursor_offset),
1911 TEXTMODE_Y(cursor_offset));
1912 else
1913 dpy_text_cursor(s->con, -1, -1);
1914 s->cursor_offset = cursor_offset;
1915 s->cursor_start = s->cr[VGA_CRTC_CURSOR_START];
1916 s->cursor_end = s->cr[VGA_CRTC_CURSOR_END];
1919 src = (uint32_t *) s->vram_ptr + s->start_addr;
1920 dst = chardata;
1922 if (full_update) {
1923 for (i = 0; i < size; src ++, dst ++, i ++)
1924 console_write_ch(dst, VMEM2CHTYPE(le32_to_cpu(*src)));
1926 dpy_text_update(s->con, 0, 0, width, height);
1927 } else {
1928 c_max = 0;
1930 for (i = 0; i < size; src ++, dst ++, i ++) {
1931 console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
1932 if (*dst != val) {
1933 *dst = val;
1934 c_max = i;
1935 break;
1938 c_min = i;
1939 for (; i < size; src ++, dst ++, i ++) {
1940 console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
1941 if (*dst != val) {
1942 *dst = val;
1943 c_max = i;
1947 if (c_min <= c_max) {
1948 i = TEXTMODE_Y(c_min);
1949 dpy_text_update(s->con, 0, i, width, TEXTMODE_Y(c_max) - i + 1);
1953 return;
1954 case GMODE_GRAPH:
1955 if (!full_update)
1956 return;
1958 s->get_resolution(s, &width, &height);
1959 snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Graphic mode",
1960 width, height);
1961 break;
1962 case GMODE_BLANK:
1963 default:
1964 if (!full_update)
1965 return;
1967 snprintf(msg_buffer, sizeof(msg_buffer), "VGA Blank mode");
1968 break;
1971 /* Display a message */
1972 s->last_width = 60;
1973 s->last_height = height = 3;
1974 dpy_text_cursor(s->con, -1, -1);
1975 dpy_text_resize(s->con, s->last_width, height);
1977 for (dst = chardata, i = 0; i < s->last_width * height; i ++)
1978 console_write_ch(dst ++, ' ');
1980 size = strlen(msg_buffer);
1981 width = (s->last_width - size) / 2;
1982 dst = chardata + s->last_width + width;
1983 for (i = 0; i < size; i ++)
1984 console_write_ch(dst ++, ATTR2CHTYPE(msg_buffer[i], QEMU_COLOR_BLUE,
1985 QEMU_COLOR_BLACK, 1));
1987 dpy_text_update(s->con, 0, 0, s->last_width, height);
1990 static uint64_t vga_mem_read(void *opaque, hwaddr addr,
1991 unsigned size)
1993 VGACommonState *s = opaque;
1995 return vga_mem_readb(s, addr);
1998 static void vga_mem_write(void *opaque, hwaddr addr,
1999 uint64_t data, unsigned size)
2001 VGACommonState *s = opaque;
2003 vga_mem_writeb(s, addr, data);
2006 const MemoryRegionOps vga_mem_ops = {
2007 .read = vga_mem_read,
2008 .write = vga_mem_write,
2009 .endianness = DEVICE_LITTLE_ENDIAN,
2010 .impl = {
2011 .min_access_size = 1,
2012 .max_access_size = 1,
2016 static int vga_common_post_load(void *opaque, int version_id)
2018 VGACommonState *s = opaque;
2020 /* force refresh */
2021 s->graphic_mode = -1;
2022 return 0;
2025 static bool vga_endian_state_needed(void *opaque)
2027 VGACommonState *s = opaque;
2030 * Only send the endian state if it's different from the
2031 * default one, thus ensuring backward compatibility for
2032 * migration of the common case
2034 return s->default_endian_fb != s->big_endian_fb;
2037 static const VMStateDescription vmstate_vga_endian = {
2038 .name = "vga.endian",
2039 .version_id = 1,
2040 .minimum_version_id = 1,
2041 .needed = vga_endian_state_needed,
2042 .fields = (VMStateField[]) {
2043 VMSTATE_BOOL(big_endian_fb, VGACommonState),
2044 VMSTATE_END_OF_LIST()
2048 const VMStateDescription vmstate_vga_common = {
2049 .name = "vga",
2050 .version_id = 2,
2051 .minimum_version_id = 2,
2052 .post_load = vga_common_post_load,
2053 .fields = (VMStateField[]) {
2054 VMSTATE_UINT32(latch, VGACommonState),
2055 VMSTATE_UINT8(sr_index, VGACommonState),
2056 VMSTATE_PARTIAL_BUFFER(sr, VGACommonState, 8),
2057 VMSTATE_UINT8(gr_index, VGACommonState),
2058 VMSTATE_PARTIAL_BUFFER(gr, VGACommonState, 16),
2059 VMSTATE_UINT8(ar_index, VGACommonState),
2060 VMSTATE_BUFFER(ar, VGACommonState),
2061 VMSTATE_INT32(ar_flip_flop, VGACommonState),
2062 VMSTATE_UINT8(cr_index, VGACommonState),
2063 VMSTATE_BUFFER(cr, VGACommonState),
2064 VMSTATE_UINT8(msr, VGACommonState),
2065 VMSTATE_UINT8(fcr, VGACommonState),
2066 VMSTATE_UINT8(st00, VGACommonState),
2067 VMSTATE_UINT8(st01, VGACommonState),
2069 VMSTATE_UINT8(dac_state, VGACommonState),
2070 VMSTATE_UINT8(dac_sub_index, VGACommonState),
2071 VMSTATE_UINT8(dac_read_index, VGACommonState),
2072 VMSTATE_UINT8(dac_write_index, VGACommonState),
2073 VMSTATE_BUFFER(dac_cache, VGACommonState),
2074 VMSTATE_BUFFER(palette, VGACommonState),
2076 VMSTATE_INT32(bank_offset, VGACommonState),
2077 VMSTATE_UINT8_EQUAL(is_vbe_vmstate, VGACommonState),
2078 VMSTATE_UINT16(vbe_index, VGACommonState),
2079 VMSTATE_UINT16_ARRAY(vbe_regs, VGACommonState, VBE_DISPI_INDEX_NB),
2080 VMSTATE_UINT32(vbe_start_addr, VGACommonState),
2081 VMSTATE_UINT32(vbe_line_offset, VGACommonState),
2082 VMSTATE_UINT32(vbe_bank_mask, VGACommonState),
2083 VMSTATE_END_OF_LIST()
2085 .subsections = (const VMStateDescription*[]) {
2086 &vmstate_vga_endian,
2087 NULL
2091 static const GraphicHwOps vga_ops = {
2092 .invalidate = vga_invalidate_display,
2093 .gfx_update = vga_update_display,
2094 .text_update = vga_update_text,
2097 static inline uint32_t uint_clamp(uint32_t val, uint32_t vmin, uint32_t vmax)
2099 if (val < vmin) {
2100 return vmin;
2102 if (val > vmax) {
2103 return vmax;
2105 return val;
2108 void vga_common_init(VGACommonState *s, Object *obj, bool global_vmstate)
2110 int i, j, v, b;
2112 for(i = 0;i < 256; i++) {
2113 v = 0;
2114 for(j = 0; j < 8; j++) {
2115 v |= ((i >> j) & 1) << (j * 4);
2117 expand4[i] = v;
2119 v = 0;
2120 for(j = 0; j < 4; j++) {
2121 v |= ((i >> (2 * j)) & 3) << (j * 4);
2123 expand2[i] = v;
2125 for(i = 0; i < 16; i++) {
2126 v = 0;
2127 for(j = 0; j < 4; j++) {
2128 b = ((i >> j) & 1);
2129 v |= b << (2 * j);
2130 v |= b << (2 * j + 1);
2132 expand4to8[i] = v;
2135 s->vram_size_mb = uint_clamp(s->vram_size_mb, 1, 512);
2136 s->vram_size_mb = pow2ceil(s->vram_size_mb);
2137 s->vram_size = s->vram_size_mb << 20;
2139 if (!s->vbe_size) {
2140 s->vbe_size = s->vram_size;
2143 s->is_vbe_vmstate = 1;
2144 memory_region_init_ram(&s->vram, obj, "vga.vram", s->vram_size,
2145 &error_fatal);
2146 vmstate_register_ram(&s->vram, global_vmstate ? NULL : DEVICE(obj));
2147 xen_register_framebuffer(&s->vram);
2148 s->vram_ptr = memory_region_get_ram_ptr(&s->vram);
2149 s->get_bpp = vga_get_bpp;
2150 s->get_offsets = vga_get_offsets;
2151 s->get_resolution = vga_get_resolution;
2152 s->hw_ops = &vga_ops;
2153 switch (vga_retrace_method) {
2154 case VGA_RETRACE_DUMB:
2155 s->retrace = vga_dumb_retrace;
2156 s->update_retrace_info = vga_dumb_update_retrace_info;
2157 break;
2159 case VGA_RETRACE_PRECISE:
2160 s->retrace = vga_precise_retrace;
2161 s->update_retrace_info = vga_precise_update_retrace_info;
2162 break;
2166 * Set default fb endian based on target, could probably be turned
2167 * into a device attribute set by the machine/platform to remove
2168 * all target endian dependencies from this file.
2170 #ifdef TARGET_WORDS_BIGENDIAN
2171 s->default_endian_fb = true;
2172 #else
2173 s->default_endian_fb = false;
2174 #endif
2175 vga_dirty_log_start(s);
2178 static const MemoryRegionPortio vga_portio_list[] = {
2179 { 0x04, 2, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3b4 */
2180 { 0x0a, 1, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3ba */
2181 { 0x10, 16, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3c0 */
2182 { 0x24, 2, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3d4 */
2183 { 0x2a, 1, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3da */
2184 PORTIO_END_OF_LIST(),
2187 static const MemoryRegionPortio vbe_portio_list[] = {
2188 { 0, 1, 2, .read = vbe_ioport_read_index, .write = vbe_ioport_write_index },
2189 # ifdef TARGET_I386
2190 { 1, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data },
2191 # endif
2192 { 2, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data },
2193 PORTIO_END_OF_LIST(),
2196 /* Used by both ISA and PCI */
2197 MemoryRegion *vga_init_io(VGACommonState *s, Object *obj,
2198 const MemoryRegionPortio **vga_ports,
2199 const MemoryRegionPortio **vbe_ports)
2201 MemoryRegion *vga_mem;
2203 *vga_ports = vga_portio_list;
2204 *vbe_ports = vbe_portio_list;
2206 vga_mem = g_malloc(sizeof(*vga_mem));
2207 memory_region_init_io(vga_mem, obj, &vga_mem_ops, s,
2208 "vga-lowmem", 0x20000);
2209 memory_region_set_flush_coalesced(vga_mem);
2211 return vga_mem;
2214 void vga_init(VGACommonState *s, Object *obj, MemoryRegion *address_space,
2215 MemoryRegion *address_space_io, bool init_vga_ports)
2217 MemoryRegion *vga_io_memory;
2218 const MemoryRegionPortio *vga_ports, *vbe_ports;
2220 qemu_register_reset(vga_reset, s);
2222 s->bank_offset = 0;
2224 s->legacy_address_space = address_space;
2226 vga_io_memory = vga_init_io(s, obj, &vga_ports, &vbe_ports);
2227 memory_region_add_subregion_overlap(address_space,
2228 0x000a0000,
2229 vga_io_memory,
2231 memory_region_set_coalescing(vga_io_memory);
2232 if (init_vga_ports) {
2233 portio_list_init(&s->vga_port_list, obj, vga_ports, s, "vga");
2234 portio_list_set_flush_coalesced(&s->vga_port_list);
2235 portio_list_add(&s->vga_port_list, address_space_io, 0x3b0);
2237 if (vbe_ports) {
2238 portio_list_init(&s->vbe_port_list, obj, vbe_ports, s, "vbe");
2239 portio_list_add(&s->vbe_port_list, address_space_io, 0x1ce);
2243 void vga_init_vbe(VGACommonState *s, Object *obj, MemoryRegion *system_memory)
2245 /* With pc-0.12 and below we map both the PCI BAR and the fixed VBE region,
2246 * so use an alias to avoid double-mapping the same region.
2248 memory_region_init_alias(&s->vram_vbe, obj, "vram.vbe",
2249 &s->vram, 0, memory_region_size(&s->vram));
2250 /* XXX: use optimized standard vga accesses */
2251 memory_region_add_subregion(system_memory,
2252 VBE_DISPI_LFB_PHYSICAL_ADDRESS,
2253 &s->vram_vbe);
2254 s->vbe_mapped = 1;