seccomp: add cacheflush to whitelist
[qemu/ar7.git] / hw / display / vga.c
blob9f6839488b5818135b07fd936bddff44c233a87c
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 uint32_t expand4[256];
140 static uint16_t expand2[256];
141 static uint8_t expand4to8[16];
143 static void vga_update_memory_access(VGACommonState *s)
145 hwaddr base, offset, size;
147 if (s->legacy_address_space == NULL) {
148 return;
151 if (s->has_chain4_alias) {
152 memory_region_del_subregion(s->legacy_address_space, &s->chain4_alias);
153 object_unparent(OBJECT(&s->chain4_alias));
154 s->has_chain4_alias = false;
155 s->plane_updated = 0xf;
157 if ((s->sr[VGA_SEQ_PLANE_WRITE] & VGA_SR02_ALL_PLANES) ==
158 VGA_SR02_ALL_PLANES && s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
159 offset = 0;
160 switch ((s->gr[VGA_GFX_MISC] >> 2) & 3) {
161 case 0:
162 base = 0xa0000;
163 size = 0x20000;
164 break;
165 case 1:
166 base = 0xa0000;
167 size = 0x10000;
168 offset = s->bank_offset;
169 break;
170 case 2:
171 base = 0xb0000;
172 size = 0x8000;
173 break;
174 case 3:
175 default:
176 base = 0xb8000;
177 size = 0x8000;
178 break;
180 memory_region_init_alias(&s->chain4_alias, memory_region_owner(&s->vram),
181 "vga.chain4", &s->vram, offset, size);
182 memory_region_add_subregion_overlap(s->legacy_address_space, base,
183 &s->chain4_alias, 2);
184 s->has_chain4_alias = true;
188 static void vga_dumb_update_retrace_info(VGACommonState *s)
190 (void) s;
193 static void vga_precise_update_retrace_info(VGACommonState *s)
195 int htotal_chars;
196 int hretr_start_char;
197 int hretr_skew_chars;
198 int hretr_end_char;
200 int vtotal_lines;
201 int vretr_start_line;
202 int vretr_end_line;
204 int dots;
205 #if 0
206 int div2, sldiv2;
207 #endif
208 int clocking_mode;
209 int clock_sel;
210 const int clk_hz[] = {25175000, 28322000, 25175000, 25175000};
211 int64_t chars_per_sec;
212 struct vga_precise_retrace *r = &s->retrace_info.precise;
214 htotal_chars = s->cr[VGA_CRTC_H_TOTAL] + 5;
215 hretr_start_char = s->cr[VGA_CRTC_H_SYNC_START];
216 hretr_skew_chars = (s->cr[VGA_CRTC_H_SYNC_END] >> 5) & 3;
217 hretr_end_char = s->cr[VGA_CRTC_H_SYNC_END] & 0x1f;
219 vtotal_lines = (s->cr[VGA_CRTC_V_TOTAL] |
220 (((s->cr[VGA_CRTC_OVERFLOW] & 1) |
221 ((s->cr[VGA_CRTC_OVERFLOW] >> 4) & 2)) << 8)) + 2;
222 vretr_start_line = s->cr[VGA_CRTC_V_SYNC_START] |
223 ((((s->cr[VGA_CRTC_OVERFLOW] >> 2) & 1) |
224 ((s->cr[VGA_CRTC_OVERFLOW] >> 6) & 2)) << 8);
225 vretr_end_line = s->cr[VGA_CRTC_V_SYNC_END] & 0xf;
227 clocking_mode = (s->sr[VGA_SEQ_CLOCK_MODE] >> 3) & 1;
228 clock_sel = (s->msr >> 2) & 3;
229 dots = (s->msr & 1) ? 8 : 9;
231 chars_per_sec = clk_hz[clock_sel] / dots;
233 htotal_chars <<= clocking_mode;
235 r->total_chars = vtotal_lines * htotal_chars;
236 if (r->freq) {
237 r->ticks_per_char = get_ticks_per_sec() / (r->total_chars * r->freq);
238 } else {
239 r->ticks_per_char = get_ticks_per_sec() / chars_per_sec;
242 r->vstart = vretr_start_line;
243 r->vend = r->vstart + vretr_end_line + 1;
245 r->hstart = hretr_start_char + hretr_skew_chars;
246 r->hend = r->hstart + hretr_end_char + 1;
247 r->htotal = htotal_chars;
249 #if 0
250 div2 = (s->cr[VGA_CRTC_MODE] >> 2) & 1;
251 sldiv2 = (s->cr[VGA_CRTC_MODE] >> 3) & 1;
252 printf (
253 "hz=%f\n"
254 "htotal = %d\n"
255 "hretr_start = %d\n"
256 "hretr_skew = %d\n"
257 "hretr_end = %d\n"
258 "vtotal = %d\n"
259 "vretr_start = %d\n"
260 "vretr_end = %d\n"
261 "div2 = %d sldiv2 = %d\n"
262 "clocking_mode = %d\n"
263 "clock_sel = %d %d\n"
264 "dots = %d\n"
265 "ticks/char = %" PRId64 "\n"
266 "\n",
267 (double) get_ticks_per_sec() / (r->ticks_per_char * r->total_chars),
268 htotal_chars,
269 hretr_start_char,
270 hretr_skew_chars,
271 hretr_end_char,
272 vtotal_lines,
273 vretr_start_line,
274 vretr_end_line,
275 div2, sldiv2,
276 clocking_mode,
277 clock_sel,
278 clk_hz[clock_sel],
279 dots,
280 r->ticks_per_char
282 #endif
285 static uint8_t vga_precise_retrace(VGACommonState *s)
287 struct vga_precise_retrace *r = &s->retrace_info.precise;
288 uint8_t val = s->st01 & ~(ST01_V_RETRACE | ST01_DISP_ENABLE);
290 if (r->total_chars) {
291 int cur_line, cur_line_char, cur_char;
292 int64_t cur_tick;
294 cur_tick = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
296 cur_char = (cur_tick / r->ticks_per_char) % r->total_chars;
297 cur_line = cur_char / r->htotal;
299 if (cur_line >= r->vstart && cur_line <= r->vend) {
300 val |= ST01_V_RETRACE | ST01_DISP_ENABLE;
301 } else {
302 cur_line_char = cur_char % r->htotal;
303 if (cur_line_char >= r->hstart && cur_line_char <= r->hend) {
304 val |= ST01_DISP_ENABLE;
308 return val;
309 } else {
310 return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
314 static uint8_t vga_dumb_retrace(VGACommonState *s)
316 return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
319 int vga_ioport_invalid(VGACommonState *s, uint32_t addr)
321 if (s->msr & VGA_MIS_COLOR) {
322 /* Color */
323 return (addr >= 0x3b0 && addr <= 0x3bf);
324 } else {
325 /* Monochrome */
326 return (addr >= 0x3d0 && addr <= 0x3df);
330 uint32_t vga_ioport_read(void *opaque, uint32_t addr)
332 VGACommonState *s = opaque;
333 int val, index;
335 if (vga_ioport_invalid(s, addr)) {
336 val = 0xff;
337 } else {
338 switch(addr) {
339 case VGA_ATT_W:
340 if (s->ar_flip_flop == 0) {
341 val = s->ar_index;
342 } else {
343 val = 0;
345 break;
346 case VGA_ATT_R:
347 index = s->ar_index & 0x1f;
348 if (index < VGA_ATT_C) {
349 val = s->ar[index];
350 } else {
351 val = 0;
353 break;
354 case VGA_MIS_W:
355 val = s->st00;
356 break;
357 case VGA_SEQ_I:
358 val = s->sr_index;
359 break;
360 case VGA_SEQ_D:
361 val = s->sr[s->sr_index];
362 #ifdef DEBUG_VGA_REG
363 printf("vga: read SR%x = 0x%02x\n", s->sr_index, val);
364 #endif
365 break;
366 case VGA_PEL_IR:
367 val = s->dac_state;
368 break;
369 case VGA_PEL_IW:
370 val = s->dac_write_index;
371 break;
372 case VGA_PEL_D:
373 val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
374 if (++s->dac_sub_index == 3) {
375 s->dac_sub_index = 0;
376 s->dac_read_index++;
378 break;
379 case VGA_FTC_R:
380 val = s->fcr;
381 break;
382 case VGA_MIS_R:
383 val = s->msr;
384 break;
385 case VGA_GFX_I:
386 val = s->gr_index;
387 break;
388 case VGA_GFX_D:
389 val = s->gr[s->gr_index];
390 #ifdef DEBUG_VGA_REG
391 printf("vga: read GR%x = 0x%02x\n", s->gr_index, val);
392 #endif
393 break;
394 case VGA_CRT_IM:
395 case VGA_CRT_IC:
396 val = s->cr_index;
397 break;
398 case VGA_CRT_DM:
399 case VGA_CRT_DC:
400 val = s->cr[s->cr_index];
401 #ifdef DEBUG_VGA_REG
402 printf("vga: read CR%x = 0x%02x\n", s->cr_index, val);
403 #endif
404 break;
405 case VGA_IS1_RM:
406 case VGA_IS1_RC:
407 /* just toggle to fool polling */
408 val = s->st01 = s->retrace(s);
409 s->ar_flip_flop = 0;
410 break;
411 default:
412 val = 0x00;
413 break;
416 #if defined(DEBUG_VGA)
417 printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
418 #endif
419 return val;
422 void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
424 VGACommonState *s = opaque;
425 int index;
427 /* check port range access depending on color/monochrome mode */
428 if (vga_ioport_invalid(s, addr)) {
429 return;
431 #ifdef DEBUG_VGA
432 printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
433 #endif
435 switch(addr) {
436 case VGA_ATT_W:
437 if (s->ar_flip_flop == 0) {
438 val &= 0x3f;
439 s->ar_index = val;
440 } else {
441 index = s->ar_index & 0x1f;
442 switch(index) {
443 case VGA_ATC_PALETTE0 ... VGA_ATC_PALETTEF:
444 s->ar[index] = val & 0x3f;
445 break;
446 case VGA_ATC_MODE:
447 s->ar[index] = val & ~0x10;
448 break;
449 case VGA_ATC_OVERSCAN:
450 s->ar[index] = val;
451 break;
452 case VGA_ATC_PLANE_ENABLE:
453 s->ar[index] = val & ~0xc0;
454 break;
455 case VGA_ATC_PEL:
456 s->ar[index] = val & ~0xf0;
457 break;
458 case VGA_ATC_COLOR_PAGE:
459 s->ar[index] = val & ~0xf0;
460 break;
461 default:
462 break;
465 s->ar_flip_flop ^= 1;
466 break;
467 case VGA_MIS_W:
468 s->msr = val & ~0x10;
469 s->update_retrace_info(s);
470 break;
471 case VGA_SEQ_I:
472 s->sr_index = val & 7;
473 break;
474 case VGA_SEQ_D:
475 #ifdef DEBUG_VGA_REG
476 printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
477 #endif
478 s->sr[s->sr_index] = val & sr_mask[s->sr_index];
479 if (s->sr_index == VGA_SEQ_CLOCK_MODE) {
480 s->update_retrace_info(s);
482 vga_update_memory_access(s);
483 break;
484 case VGA_PEL_IR:
485 s->dac_read_index = val;
486 s->dac_sub_index = 0;
487 s->dac_state = 3;
488 break;
489 case VGA_PEL_IW:
490 s->dac_write_index = val;
491 s->dac_sub_index = 0;
492 s->dac_state = 0;
493 break;
494 case VGA_PEL_D:
495 s->dac_cache[s->dac_sub_index] = val;
496 if (++s->dac_sub_index == 3) {
497 memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
498 s->dac_sub_index = 0;
499 s->dac_write_index++;
501 break;
502 case VGA_GFX_I:
503 s->gr_index = val & 0x0f;
504 break;
505 case VGA_GFX_D:
506 #ifdef DEBUG_VGA_REG
507 printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
508 #endif
509 s->gr[s->gr_index] = val & gr_mask[s->gr_index];
510 vga_update_memory_access(s);
511 break;
512 case VGA_CRT_IM:
513 case VGA_CRT_IC:
514 s->cr_index = val;
515 break;
516 case VGA_CRT_DM:
517 case VGA_CRT_DC:
518 #ifdef DEBUG_VGA_REG
519 printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
520 #endif
521 /* handle CR0-7 protection */
522 if ((s->cr[VGA_CRTC_V_SYNC_END] & VGA_CR11_LOCK_CR0_CR7) &&
523 s->cr_index <= VGA_CRTC_OVERFLOW) {
524 /* can always write bit 4 of CR7 */
525 if (s->cr_index == VGA_CRTC_OVERFLOW) {
526 s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x10) |
527 (val & 0x10);
529 return;
531 s->cr[s->cr_index] = val;
533 switch(s->cr_index) {
534 case VGA_CRTC_H_TOTAL:
535 case VGA_CRTC_H_SYNC_START:
536 case VGA_CRTC_H_SYNC_END:
537 case VGA_CRTC_V_TOTAL:
538 case VGA_CRTC_OVERFLOW:
539 case VGA_CRTC_V_SYNC_END:
540 case VGA_CRTC_MODE:
541 s->update_retrace_info(s);
542 break;
544 break;
545 case VGA_IS1_RM:
546 case VGA_IS1_RC:
547 s->fcr = val & 0x10;
548 break;
553 * Sanity check vbe register writes.
555 * As we don't have a way to signal errors to the guest in the bochs
556 * dispi interface we'll go adjust the registers to the closest valid
557 * value.
559 static void vbe_fixup_regs(VGACommonState *s)
561 uint16_t *r = s->vbe_regs;
562 uint32_t bits, linelength, maxy, offset;
564 if (!(r[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
565 /* vbe is turned off -- nothing to do */
566 return;
569 /* check depth */
570 switch (r[VBE_DISPI_INDEX_BPP]) {
571 case 4:
572 case 8:
573 case 16:
574 case 24:
575 case 32:
576 bits = r[VBE_DISPI_INDEX_BPP];
577 break;
578 case 15:
579 bits = 16;
580 break;
581 default:
582 bits = r[VBE_DISPI_INDEX_BPP] = 8;
583 break;
586 /* check width */
587 r[VBE_DISPI_INDEX_XRES] &= ~7u;
588 if (r[VBE_DISPI_INDEX_XRES] == 0) {
589 r[VBE_DISPI_INDEX_XRES] = 8;
591 if (r[VBE_DISPI_INDEX_XRES] > VBE_DISPI_MAX_XRES) {
592 r[VBE_DISPI_INDEX_XRES] = VBE_DISPI_MAX_XRES;
594 r[VBE_DISPI_INDEX_VIRT_WIDTH] &= ~7u;
595 if (r[VBE_DISPI_INDEX_VIRT_WIDTH] > VBE_DISPI_MAX_XRES) {
596 r[VBE_DISPI_INDEX_VIRT_WIDTH] = VBE_DISPI_MAX_XRES;
598 if (r[VBE_DISPI_INDEX_VIRT_WIDTH] < r[VBE_DISPI_INDEX_XRES]) {
599 r[VBE_DISPI_INDEX_VIRT_WIDTH] = r[VBE_DISPI_INDEX_XRES];
602 /* check height */
603 linelength = r[VBE_DISPI_INDEX_VIRT_WIDTH] * bits / 8;
604 maxy = s->vbe_size / linelength;
605 if (r[VBE_DISPI_INDEX_YRES] == 0) {
606 r[VBE_DISPI_INDEX_YRES] = 1;
608 if (r[VBE_DISPI_INDEX_YRES] > VBE_DISPI_MAX_YRES) {
609 r[VBE_DISPI_INDEX_YRES] = VBE_DISPI_MAX_YRES;
611 if (r[VBE_DISPI_INDEX_YRES] > maxy) {
612 r[VBE_DISPI_INDEX_YRES] = maxy;
615 /* check offset */
616 if (r[VBE_DISPI_INDEX_X_OFFSET] > VBE_DISPI_MAX_XRES) {
617 r[VBE_DISPI_INDEX_X_OFFSET] = VBE_DISPI_MAX_XRES;
619 if (r[VBE_DISPI_INDEX_Y_OFFSET] > VBE_DISPI_MAX_YRES) {
620 r[VBE_DISPI_INDEX_Y_OFFSET] = VBE_DISPI_MAX_YRES;
622 offset = r[VBE_DISPI_INDEX_X_OFFSET] * bits / 8;
623 offset += r[VBE_DISPI_INDEX_Y_OFFSET] * linelength;
624 if (offset + r[VBE_DISPI_INDEX_YRES] * linelength > s->vbe_size) {
625 r[VBE_DISPI_INDEX_Y_OFFSET] = 0;
626 offset = r[VBE_DISPI_INDEX_X_OFFSET] * bits / 8;
627 if (offset + r[VBE_DISPI_INDEX_YRES] * linelength > s->vbe_size) {
628 r[VBE_DISPI_INDEX_X_OFFSET] = 0;
629 offset = 0;
633 /* update vga state */
634 r[VBE_DISPI_INDEX_VIRT_HEIGHT] = maxy;
635 s->vbe_line_offset = linelength;
636 s->vbe_start_addr = offset / 4;
639 static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
641 VGACommonState *s = opaque;
642 uint32_t val;
643 val = s->vbe_index;
644 return val;
647 uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr)
649 VGACommonState *s = opaque;
650 uint32_t val;
652 if (s->vbe_index < VBE_DISPI_INDEX_NB) {
653 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_GETCAPS) {
654 switch(s->vbe_index) {
655 /* XXX: do not hardcode ? */
656 case VBE_DISPI_INDEX_XRES:
657 val = VBE_DISPI_MAX_XRES;
658 break;
659 case VBE_DISPI_INDEX_YRES:
660 val = VBE_DISPI_MAX_YRES;
661 break;
662 case VBE_DISPI_INDEX_BPP:
663 val = VBE_DISPI_MAX_BPP;
664 break;
665 default:
666 val = s->vbe_regs[s->vbe_index];
667 break;
669 } else {
670 val = s->vbe_regs[s->vbe_index];
672 } else if (s->vbe_index == VBE_DISPI_INDEX_VIDEO_MEMORY_64K) {
673 val = s->vbe_size / (64 * 1024);
674 } else {
675 val = 0;
677 #ifdef DEBUG_BOCHS_VBE
678 printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val);
679 #endif
680 return val;
683 void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val)
685 VGACommonState *s = opaque;
686 s->vbe_index = val;
689 void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
691 VGACommonState *s = opaque;
693 if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
694 #ifdef DEBUG_BOCHS_VBE
695 printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val);
696 #endif
697 switch(s->vbe_index) {
698 case VBE_DISPI_INDEX_ID:
699 if (val == VBE_DISPI_ID0 ||
700 val == VBE_DISPI_ID1 ||
701 val == VBE_DISPI_ID2 ||
702 val == VBE_DISPI_ID3 ||
703 val == VBE_DISPI_ID4) {
704 s->vbe_regs[s->vbe_index] = val;
706 break;
707 case VBE_DISPI_INDEX_XRES:
708 case VBE_DISPI_INDEX_YRES:
709 case VBE_DISPI_INDEX_BPP:
710 case VBE_DISPI_INDEX_VIRT_WIDTH:
711 case VBE_DISPI_INDEX_X_OFFSET:
712 case VBE_DISPI_INDEX_Y_OFFSET:
713 s->vbe_regs[s->vbe_index] = val;
714 vbe_fixup_regs(s);
715 break;
716 case VBE_DISPI_INDEX_BANK:
717 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
718 val &= (s->vbe_bank_mask >> 2);
719 } else {
720 val &= s->vbe_bank_mask;
722 s->vbe_regs[s->vbe_index] = val;
723 s->bank_offset = (val << 16);
724 vga_update_memory_access(s);
725 break;
726 case VBE_DISPI_INDEX_ENABLE:
727 if ((val & VBE_DISPI_ENABLED) &&
728 !(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
729 int h, shift_control;
731 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = 0;
732 s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
733 s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
734 s->vbe_regs[VBE_DISPI_INDEX_ENABLE] |= VBE_DISPI_ENABLED;
735 vbe_fixup_regs(s);
737 /* clear the screen */
738 if (!(val & VBE_DISPI_NOCLEARMEM)) {
739 memset(s->vram_ptr, 0,
740 s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
743 /* we initialize the VGA graphic mode */
744 /* graphic mode + memory map 1 */
745 s->gr[VGA_GFX_MISC] = (s->gr[VGA_GFX_MISC] & ~0x0c) | 0x04 |
746 VGA_GR06_GRAPHICS_MODE;
747 s->cr[VGA_CRTC_MODE] |= 3; /* no CGA modes */
748 s->cr[VGA_CRTC_OFFSET] = s->vbe_line_offset >> 3;
749 /* width */
750 s->cr[VGA_CRTC_H_DISP] =
751 (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
752 /* height (only meaningful if < 1024) */
753 h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
754 s->cr[VGA_CRTC_V_DISP_END] = h;
755 s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x42) |
756 ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
757 /* line compare to 1023 */
758 s->cr[VGA_CRTC_LINE_COMPARE] = 0xff;
759 s->cr[VGA_CRTC_OVERFLOW] |= 0x10;
760 s->cr[VGA_CRTC_MAX_SCAN] |= 0x40;
762 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
763 shift_control = 0;
764 s->sr[VGA_SEQ_CLOCK_MODE] &= ~8; /* no double line */
765 } else {
766 shift_control = 2;
767 /* set chain 4 mode */
768 s->sr[VGA_SEQ_MEMORY_MODE] |= VGA_SR04_CHN_4M;
769 /* activate all planes */
770 s->sr[VGA_SEQ_PLANE_WRITE] |= VGA_SR02_ALL_PLANES;
772 s->gr[VGA_GFX_MODE] = (s->gr[VGA_GFX_MODE] & ~0x60) |
773 (shift_control << 5);
774 s->cr[VGA_CRTC_MAX_SCAN] &= ~0x9f; /* no double scan */
775 } else {
776 s->bank_offset = 0;
778 s->dac_8bit = (val & VBE_DISPI_8BIT_DAC) > 0;
779 s->vbe_regs[s->vbe_index] = val;
780 vga_update_memory_access(s);
781 break;
782 default:
783 break;
788 /* called for accesses between 0xa0000 and 0xc0000 */
789 uint32_t vga_mem_readb(VGACommonState *s, hwaddr addr)
791 int memory_map_mode, plane;
792 uint32_t ret;
794 /* convert to VGA memory offset */
795 memory_map_mode = (s->gr[VGA_GFX_MISC] >> 2) & 3;
796 addr &= 0x1ffff;
797 switch(memory_map_mode) {
798 case 0:
799 break;
800 case 1:
801 if (addr >= 0x10000)
802 return 0xff;
803 addr += s->bank_offset;
804 break;
805 case 2:
806 addr -= 0x10000;
807 if (addr >= 0x8000)
808 return 0xff;
809 break;
810 default:
811 case 3:
812 addr -= 0x18000;
813 if (addr >= 0x8000)
814 return 0xff;
815 break;
818 if (s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
819 /* chain 4 mode : simplest access */
820 ret = s->vram_ptr[addr];
821 } else if (s->gr[VGA_GFX_MODE] & 0x10) {
822 /* odd/even mode (aka text mode mapping) */
823 plane = (s->gr[VGA_GFX_PLANE_READ] & 2) | (addr & 1);
824 ret = s->vram_ptr[((addr & ~1) << 1) | plane];
825 } else {
826 /* standard VGA latched access */
827 s->latch = ((uint32_t *)s->vram_ptr)[addr];
829 if (!(s->gr[VGA_GFX_MODE] & 0x08)) {
830 /* read mode 0 */
831 plane = s->gr[VGA_GFX_PLANE_READ];
832 ret = GET_PLANE(s->latch, plane);
833 } else {
834 /* read mode 1 */
835 ret = (s->latch ^ mask16[s->gr[VGA_GFX_COMPARE_VALUE]]) &
836 mask16[s->gr[VGA_GFX_COMPARE_MASK]];
837 ret |= ret >> 16;
838 ret |= ret >> 8;
839 ret = (~ret) & 0xff;
842 return ret;
845 /* called for accesses between 0xa0000 and 0xc0000 */
846 void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
848 int memory_map_mode, plane, write_mode, b, func_select, mask;
849 uint32_t write_mask, bit_mask, set_mask;
851 #ifdef DEBUG_VGA_MEM
852 printf("vga: [0x" TARGET_FMT_plx "] = 0x%02x\n", addr, val);
853 #endif
854 /* convert to VGA memory offset */
855 memory_map_mode = (s->gr[VGA_GFX_MISC] >> 2) & 3;
856 addr &= 0x1ffff;
857 switch(memory_map_mode) {
858 case 0:
859 break;
860 case 1:
861 if (addr >= 0x10000)
862 return;
863 addr += s->bank_offset;
864 break;
865 case 2:
866 addr -= 0x10000;
867 if (addr >= 0x8000)
868 return;
869 break;
870 default:
871 case 3:
872 addr -= 0x18000;
873 if (addr >= 0x8000)
874 return;
875 break;
878 if (s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
879 /* chain 4 mode : simplest access */
880 plane = addr & 3;
881 mask = (1 << plane);
882 if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
883 s->vram_ptr[addr] = val;
884 #ifdef DEBUG_VGA_MEM
885 printf("vga: chain4: [0x" TARGET_FMT_plx "]\n", addr);
886 #endif
887 s->plane_updated |= mask; /* only used to detect font change */
888 memory_region_set_dirty(&s->vram, addr, 1);
890 } else if (s->gr[VGA_GFX_MODE] & 0x10) {
891 /* odd/even mode (aka text mode mapping) */
892 plane = (s->gr[VGA_GFX_PLANE_READ] & 2) | (addr & 1);
893 mask = (1 << plane);
894 if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
895 addr = ((addr & ~1) << 1) | plane;
896 s->vram_ptr[addr] = val;
897 #ifdef DEBUG_VGA_MEM
898 printf("vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr);
899 #endif
900 s->plane_updated |= mask; /* only used to detect font change */
901 memory_region_set_dirty(&s->vram, addr, 1);
903 } else {
904 /* standard VGA latched access */
905 write_mode = s->gr[VGA_GFX_MODE] & 3;
906 switch(write_mode) {
907 default:
908 case 0:
909 /* rotate */
910 b = s->gr[VGA_GFX_DATA_ROTATE] & 7;
911 val = ((val >> b) | (val << (8 - b))) & 0xff;
912 val |= val << 8;
913 val |= val << 16;
915 /* apply set/reset mask */
916 set_mask = mask16[s->gr[VGA_GFX_SR_ENABLE]];
917 val = (val & ~set_mask) |
918 (mask16[s->gr[VGA_GFX_SR_VALUE]] & set_mask);
919 bit_mask = s->gr[VGA_GFX_BIT_MASK];
920 break;
921 case 1:
922 val = s->latch;
923 goto do_write;
924 case 2:
925 val = mask16[val & 0x0f];
926 bit_mask = s->gr[VGA_GFX_BIT_MASK];
927 break;
928 case 3:
929 /* rotate */
930 b = s->gr[VGA_GFX_DATA_ROTATE] & 7;
931 val = (val >> b) | (val << (8 - b));
933 bit_mask = s->gr[VGA_GFX_BIT_MASK] & val;
934 val = mask16[s->gr[VGA_GFX_SR_VALUE]];
935 break;
938 /* apply logical operation */
939 func_select = s->gr[VGA_GFX_DATA_ROTATE] >> 3;
940 switch(func_select) {
941 case 0:
942 default:
943 /* nothing to do */
944 break;
945 case 1:
946 /* and */
947 val &= s->latch;
948 break;
949 case 2:
950 /* or */
951 val |= s->latch;
952 break;
953 case 3:
954 /* xor */
955 val ^= s->latch;
956 break;
959 /* apply bit mask */
960 bit_mask |= bit_mask << 8;
961 bit_mask |= bit_mask << 16;
962 val = (val & bit_mask) | (s->latch & ~bit_mask);
964 do_write:
965 /* mask data according to sr[2] */
966 mask = s->sr[VGA_SEQ_PLANE_WRITE];
967 s->plane_updated |= mask; /* only used to detect font change */
968 write_mask = mask16[mask];
969 ((uint32_t *)s->vram_ptr)[addr] =
970 (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
971 (val & write_mask);
972 #ifdef DEBUG_VGA_MEM
973 printf("vga: latch: [0x" TARGET_FMT_plx "] mask=0x%08x val=0x%08x\n",
974 addr * 4, write_mask, val);
975 #endif
976 memory_region_set_dirty(&s->vram, addr << 2, sizeof(uint32_t));
980 typedef void vga_draw_line_func(VGACommonState *s1, uint8_t *d,
981 const uint8_t *s, int width);
983 #include "vga-helpers.h"
985 /* return true if the palette was modified */
986 static int update_palette16(VGACommonState *s)
988 int full_update, i;
989 uint32_t v, col, *palette;
991 full_update = 0;
992 palette = s->last_palette;
993 for(i = 0; i < 16; i++) {
994 v = s->ar[i];
995 if (s->ar[VGA_ATC_MODE] & 0x80) {
996 v = ((s->ar[VGA_ATC_COLOR_PAGE] & 0xf) << 4) | (v & 0xf);
997 } else {
998 v = ((s->ar[VGA_ATC_COLOR_PAGE] & 0xc) << 4) | (v & 0x3f);
1000 v = v * 3;
1001 col = rgb_to_pixel32(c6_to_8(s->palette[v]),
1002 c6_to_8(s->palette[v + 1]),
1003 c6_to_8(s->palette[v + 2]));
1004 if (col != palette[i]) {
1005 full_update = 1;
1006 palette[i] = col;
1009 return full_update;
1012 /* return true if the palette was modified */
1013 static int update_palette256(VGACommonState *s)
1015 int full_update, i;
1016 uint32_t v, col, *palette;
1018 full_update = 0;
1019 palette = s->last_palette;
1020 v = 0;
1021 for(i = 0; i < 256; i++) {
1022 if (s->dac_8bit) {
1023 col = rgb_to_pixel32(s->palette[v],
1024 s->palette[v + 1],
1025 s->palette[v + 2]);
1026 } else {
1027 col = rgb_to_pixel32(c6_to_8(s->palette[v]),
1028 c6_to_8(s->palette[v + 1]),
1029 c6_to_8(s->palette[v + 2]));
1031 if (col != palette[i]) {
1032 full_update = 1;
1033 palette[i] = col;
1035 v += 3;
1037 return full_update;
1040 static void vga_get_offsets(VGACommonState *s,
1041 uint32_t *pline_offset,
1042 uint32_t *pstart_addr,
1043 uint32_t *pline_compare)
1045 uint32_t start_addr, line_offset, line_compare;
1047 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1048 line_offset = s->vbe_line_offset;
1049 start_addr = s->vbe_start_addr;
1050 line_compare = 65535;
1051 } else {
1052 /* compute line_offset in bytes */
1053 line_offset = s->cr[VGA_CRTC_OFFSET];
1054 line_offset <<= 3;
1056 /* starting address */
1057 start_addr = s->cr[VGA_CRTC_START_LO] |
1058 (s->cr[VGA_CRTC_START_HI] << 8);
1060 /* line compare */
1061 line_compare = s->cr[VGA_CRTC_LINE_COMPARE] |
1062 ((s->cr[VGA_CRTC_OVERFLOW] & 0x10) << 4) |
1063 ((s->cr[VGA_CRTC_MAX_SCAN] & 0x40) << 3);
1065 *pline_offset = line_offset;
1066 *pstart_addr = start_addr;
1067 *pline_compare = line_compare;
1070 /* update start_addr and line_offset. Return TRUE if modified */
1071 static int update_basic_params(VGACommonState *s)
1073 int full_update;
1074 uint32_t start_addr, line_offset, line_compare;
1076 full_update = 0;
1078 s->get_offsets(s, &line_offset, &start_addr, &line_compare);
1080 if (line_offset != s->line_offset ||
1081 start_addr != s->start_addr ||
1082 line_compare != s->line_compare) {
1083 s->line_offset = line_offset;
1084 s->start_addr = start_addr;
1085 s->line_compare = line_compare;
1086 full_update = 1;
1088 return full_update;
1092 static const uint8_t cursor_glyph[32 * 4] = {
1093 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1094 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
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,
1111 static void vga_get_text_resolution(VGACommonState *s, int *pwidth, int *pheight,
1112 int *pcwidth, int *pcheight)
1114 int width, cwidth, height, cheight;
1116 /* total width & height */
1117 cheight = (s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1;
1118 cwidth = 8;
1119 if (!(s->sr[VGA_SEQ_CLOCK_MODE] & VGA_SR01_CHAR_CLK_8DOTS)) {
1120 cwidth = 9;
1122 if (s->sr[VGA_SEQ_CLOCK_MODE] & 0x08) {
1123 cwidth = 16; /* NOTE: no 18 pixel wide */
1125 width = (s->cr[VGA_CRTC_H_DISP] + 1);
1126 if (s->cr[VGA_CRTC_V_TOTAL] == 100) {
1127 /* ugly hack for CGA 160x100x16 - explain me the logic */
1128 height = 100;
1129 } else {
1130 height = s->cr[VGA_CRTC_V_DISP_END] |
1131 ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) |
1132 ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3);
1133 height = (height + 1) / cheight;
1136 *pwidth = width;
1137 *pheight = height;
1138 *pcwidth = cwidth;
1139 *pcheight = cheight;
1143 * Text mode update
1144 * Missing:
1145 * - double scan
1146 * - double width
1147 * - underline
1148 * - flashing
1150 static void vga_draw_text(VGACommonState *s, int full_update)
1152 DisplaySurface *surface = qemu_console_surface(s->con);
1153 int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
1154 int cx_min, cx_max, linesize, x_incr, line, line1;
1155 uint32_t offset, fgcol, bgcol, v, cursor_offset;
1156 uint8_t *d1, *d, *src, *dest, *cursor_ptr;
1157 const uint8_t *font_ptr, *font_base[2];
1158 int dup9, line_offset;
1159 uint32_t *palette;
1160 uint32_t *ch_attr_ptr;
1161 int64_t now = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
1163 /* compute font data address (in plane 2) */
1164 v = s->sr[VGA_SEQ_CHARACTER_MAP];
1165 offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
1166 if (offset != s->font_offsets[0]) {
1167 s->font_offsets[0] = offset;
1168 full_update = 1;
1170 font_base[0] = s->vram_ptr + offset;
1172 offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
1173 font_base[1] = s->vram_ptr + offset;
1174 if (offset != s->font_offsets[1]) {
1175 s->font_offsets[1] = offset;
1176 full_update = 1;
1178 if (s->plane_updated & (1 << 2) || s->has_chain4_alias) {
1179 /* if the plane 2 was modified since the last display, it
1180 indicates the font may have been modified */
1181 s->plane_updated = 0;
1182 full_update = 1;
1184 full_update |= update_basic_params(s);
1186 line_offset = s->line_offset;
1188 vga_get_text_resolution(s, &width, &height, &cw, &cheight);
1189 if ((height * width) <= 1) {
1190 /* better than nothing: exit if transient size is too small */
1191 return;
1193 if ((height * width) > CH_ATTR_SIZE) {
1194 /* better than nothing: exit if transient size is too big */
1195 return;
1198 if (width != s->last_width || height != s->last_height ||
1199 cw != s->last_cw || cheight != s->last_ch || s->last_depth) {
1200 s->last_scr_width = width * cw;
1201 s->last_scr_height = height * cheight;
1202 qemu_console_resize(s->con, s->last_scr_width, s->last_scr_height);
1203 surface = qemu_console_surface(s->con);
1204 dpy_text_resize(s->con, width, height);
1205 s->last_depth = 0;
1206 s->last_width = width;
1207 s->last_height = height;
1208 s->last_ch = cheight;
1209 s->last_cw = cw;
1210 full_update = 1;
1212 full_update |= update_palette16(s);
1213 palette = s->last_palette;
1214 x_incr = cw * surface_bytes_per_pixel(surface);
1216 if (full_update) {
1217 s->full_update_text = 1;
1219 if (s->full_update_gfx) {
1220 s->full_update_gfx = 0;
1221 full_update |= 1;
1224 cursor_offset = ((s->cr[VGA_CRTC_CURSOR_HI] << 8) |
1225 s->cr[VGA_CRTC_CURSOR_LO]) - s->start_addr;
1226 if (cursor_offset != s->cursor_offset ||
1227 s->cr[VGA_CRTC_CURSOR_START] != s->cursor_start ||
1228 s->cr[VGA_CRTC_CURSOR_END] != s->cursor_end) {
1229 /* if the cursor position changed, we update the old and new
1230 chars */
1231 if (s->cursor_offset < CH_ATTR_SIZE)
1232 s->last_ch_attr[s->cursor_offset] = -1;
1233 if (cursor_offset < CH_ATTR_SIZE)
1234 s->last_ch_attr[cursor_offset] = -1;
1235 s->cursor_offset = cursor_offset;
1236 s->cursor_start = s->cr[VGA_CRTC_CURSOR_START];
1237 s->cursor_end = s->cr[VGA_CRTC_CURSOR_END];
1239 cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
1240 if (now >= s->cursor_blink_time) {
1241 s->cursor_blink_time = now + VGA_TEXT_CURSOR_PERIOD_MS / 2;
1242 s->cursor_visible_phase = !s->cursor_visible_phase;
1245 dest = surface_data(surface);
1246 linesize = surface_stride(surface);
1247 ch_attr_ptr = s->last_ch_attr;
1248 line = 0;
1249 offset = s->start_addr * 4;
1250 for(cy = 0; cy < height; cy++) {
1251 d1 = dest;
1252 src = s->vram_ptr + offset;
1253 cx_min = width;
1254 cx_max = -1;
1255 for(cx = 0; cx < width; cx++) {
1256 ch_attr = *(uint16_t *)src;
1257 if (full_update || ch_attr != *ch_attr_ptr || src == cursor_ptr) {
1258 if (cx < cx_min)
1259 cx_min = cx;
1260 if (cx > cx_max)
1261 cx_max = cx;
1262 *ch_attr_ptr = ch_attr;
1263 #ifdef HOST_WORDS_BIGENDIAN
1264 ch = ch_attr >> 8;
1265 cattr = ch_attr & 0xff;
1266 #else
1267 ch = ch_attr & 0xff;
1268 cattr = ch_attr >> 8;
1269 #endif
1270 font_ptr = font_base[(cattr >> 3) & 1];
1271 font_ptr += 32 * 4 * ch;
1272 bgcol = palette[cattr >> 4];
1273 fgcol = palette[cattr & 0x0f];
1274 if (cw == 16) {
1275 vga_draw_glyph16(d1, linesize,
1276 font_ptr, cheight, fgcol, bgcol);
1277 } else if (cw != 9) {
1278 vga_draw_glyph8(d1, linesize,
1279 font_ptr, cheight, fgcol, bgcol);
1280 } else {
1281 dup9 = 0;
1282 if (ch >= 0xb0 && ch <= 0xdf &&
1283 (s->ar[VGA_ATC_MODE] & 0x04)) {
1284 dup9 = 1;
1286 vga_draw_glyph9(d1, linesize,
1287 font_ptr, cheight, fgcol, bgcol, dup9);
1289 if (src == cursor_ptr &&
1290 !(s->cr[VGA_CRTC_CURSOR_START] & 0x20) &&
1291 s->cursor_visible_phase) {
1292 int line_start, line_last, h;
1293 /* draw the cursor */
1294 line_start = s->cr[VGA_CRTC_CURSOR_START] & 0x1f;
1295 line_last = s->cr[VGA_CRTC_CURSOR_END] & 0x1f;
1296 /* XXX: check that */
1297 if (line_last > cheight - 1)
1298 line_last = cheight - 1;
1299 if (line_last >= line_start && line_start < cheight) {
1300 h = line_last - line_start + 1;
1301 d = d1 + linesize * line_start;
1302 if (cw == 16) {
1303 vga_draw_glyph16(d, linesize,
1304 cursor_glyph, h, fgcol, bgcol);
1305 } else if (cw != 9) {
1306 vga_draw_glyph8(d, linesize,
1307 cursor_glyph, h, fgcol, bgcol);
1308 } else {
1309 vga_draw_glyph9(d, linesize,
1310 cursor_glyph, h, fgcol, bgcol, 1);
1315 d1 += x_incr;
1316 src += 4;
1317 ch_attr_ptr++;
1319 if (cx_max != -1) {
1320 dpy_gfx_update(s->con, cx_min * cw, cy * cheight,
1321 (cx_max - cx_min + 1) * cw, cheight);
1323 dest += linesize * cheight;
1324 line1 = line + cheight;
1325 offset += line_offset;
1326 if (line < s->line_compare && line1 >= s->line_compare) {
1327 offset = 0;
1329 line = line1;
1333 enum {
1334 VGA_DRAW_LINE2,
1335 VGA_DRAW_LINE2D2,
1336 VGA_DRAW_LINE4,
1337 VGA_DRAW_LINE4D2,
1338 VGA_DRAW_LINE8D2,
1339 VGA_DRAW_LINE8,
1340 VGA_DRAW_LINE15_LE,
1341 VGA_DRAW_LINE16_LE,
1342 VGA_DRAW_LINE24_LE,
1343 VGA_DRAW_LINE32_LE,
1344 VGA_DRAW_LINE15_BE,
1345 VGA_DRAW_LINE16_BE,
1346 VGA_DRAW_LINE24_BE,
1347 VGA_DRAW_LINE32_BE,
1348 VGA_DRAW_LINE_NB,
1351 static vga_draw_line_func * const vga_draw_line_table[VGA_DRAW_LINE_NB] = {
1352 vga_draw_line2,
1353 vga_draw_line2d2,
1354 vga_draw_line4,
1355 vga_draw_line4d2,
1356 vga_draw_line8d2,
1357 vga_draw_line8,
1358 vga_draw_line15_le,
1359 vga_draw_line16_le,
1360 vga_draw_line24_le,
1361 vga_draw_line32_le,
1362 vga_draw_line15_be,
1363 vga_draw_line16_be,
1364 vga_draw_line24_be,
1365 vga_draw_line32_be,
1368 static int vga_get_bpp(VGACommonState *s)
1370 int ret;
1372 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1373 ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
1374 } else {
1375 ret = 0;
1377 return ret;
1380 static void vga_get_resolution(VGACommonState *s, int *pwidth, int *pheight)
1382 int width, height;
1384 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1385 width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
1386 height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
1387 } else {
1388 width = (s->cr[VGA_CRTC_H_DISP] + 1) * 8;
1389 height = s->cr[VGA_CRTC_V_DISP_END] |
1390 ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) |
1391 ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3);
1392 height = (height + 1);
1394 *pwidth = width;
1395 *pheight = height;
1398 void vga_invalidate_scanlines(VGACommonState *s, int y1, int y2)
1400 int y;
1401 if (y1 >= VGA_MAX_HEIGHT)
1402 return;
1403 if (y2 >= VGA_MAX_HEIGHT)
1404 y2 = VGA_MAX_HEIGHT;
1405 for(y = y1; y < y2; y++) {
1406 s->invalidated_y_table[y >> 5] |= 1 << (y & 0x1f);
1410 void vga_sync_dirty_bitmap(VGACommonState *s)
1412 memory_region_sync_dirty_bitmap(&s->vram);
1415 void vga_dirty_log_start(VGACommonState *s)
1417 memory_region_set_log(&s->vram, true, DIRTY_MEMORY_VGA);
1420 void vga_dirty_log_stop(VGACommonState *s)
1422 memory_region_set_log(&s->vram, false, DIRTY_MEMORY_VGA);
1426 * graphic modes
1428 static void vga_draw_graphic(VGACommonState *s, int full_update)
1430 DisplaySurface *surface = qemu_console_surface(s->con);
1431 int y1, y, update, linesize, y_start, double_scan, mask, depth;
1432 int width, height, shift_control, line_offset, bwidth, bits;
1433 ram_addr_t page0, page1, page_min, page_max;
1434 int disp_width, multi_scan, multi_run;
1435 uint8_t *d;
1436 uint32_t v, addr1, addr;
1437 vga_draw_line_func *vga_draw_line = NULL;
1438 bool share_surface;
1439 pixman_format_code_t format;
1440 #ifdef HOST_WORDS_BIGENDIAN
1441 bool byteswap = !s->big_endian_fb;
1442 #else
1443 bool byteswap = s->big_endian_fb;
1444 #endif
1446 full_update |= update_basic_params(s);
1448 if (!full_update)
1449 vga_sync_dirty_bitmap(s);
1451 s->get_resolution(s, &width, &height);
1452 disp_width = width;
1454 shift_control = (s->gr[VGA_GFX_MODE] >> 5) & 3;
1455 double_scan = (s->cr[VGA_CRTC_MAX_SCAN] >> 7);
1456 if (shift_control != 1) {
1457 multi_scan = (((s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1) << double_scan)
1458 - 1;
1459 } else {
1460 /* in CGA modes, multi_scan is ignored */
1461 /* XXX: is it correct ? */
1462 multi_scan = double_scan;
1464 multi_run = multi_scan;
1465 if (shift_control != s->shift_control ||
1466 double_scan != s->double_scan) {
1467 full_update = 1;
1468 s->shift_control = shift_control;
1469 s->double_scan = double_scan;
1472 if (shift_control == 0) {
1473 if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
1474 disp_width <<= 1;
1476 } else if (shift_control == 1) {
1477 if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
1478 disp_width <<= 1;
1482 depth = s->get_bpp(s);
1485 * Check whether we can share the surface with the backend
1486 * or whether we need a shadow surface. We share native
1487 * endian surfaces for 15bpp and above and byteswapped
1488 * surfaces for 24bpp and above.
1490 format = qemu_default_pixman_format(depth, !byteswap);
1491 if (format) {
1492 share_surface = dpy_gfx_check_format(s->con, format)
1493 && !s->force_shadow;
1494 } else {
1495 share_surface = false;
1497 if (s->line_offset != s->last_line_offset ||
1498 disp_width != s->last_width ||
1499 height != s->last_height ||
1500 s->last_depth != depth ||
1501 s->last_byteswap != byteswap ||
1502 share_surface != is_buffer_shared(surface)) {
1503 if (share_surface) {
1504 surface = qemu_create_displaysurface_from(disp_width,
1505 height, format, s->line_offset,
1506 s->vram_ptr + (s->start_addr * 4));
1507 dpy_gfx_replace_surface(s->con, surface);
1508 #ifdef DEBUG_VGA
1509 printf("VGA: Using shared surface for depth=%d swap=%d\n",
1510 depth, byteswap);
1511 #endif
1512 } else {
1513 qemu_console_resize(s->con, disp_width, height);
1514 surface = qemu_console_surface(s->con);
1515 #ifdef DEBUG_VGA
1516 printf("VGA: Using shadow surface for depth=%d swap=%d\n",
1517 depth, byteswap);
1518 #endif
1520 s->last_scr_width = disp_width;
1521 s->last_scr_height = height;
1522 s->last_width = disp_width;
1523 s->last_height = height;
1524 s->last_line_offset = s->line_offset;
1525 s->last_depth = depth;
1526 s->last_byteswap = byteswap;
1527 full_update = 1;
1528 } else if (is_buffer_shared(surface) &&
1529 (full_update || surface_data(surface) != s->vram_ptr
1530 + (s->start_addr * 4))) {
1531 pixman_format_code_t format =
1532 qemu_default_pixman_format(depth, !byteswap);
1533 surface = qemu_create_displaysurface_from(disp_width,
1534 height, format, s->line_offset,
1535 s->vram_ptr + (s->start_addr * 4));
1536 dpy_gfx_replace_surface(s->con, surface);
1539 if (shift_control == 0) {
1540 full_update |= update_palette16(s);
1541 if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
1542 v = VGA_DRAW_LINE4D2;
1543 } else {
1544 v = VGA_DRAW_LINE4;
1546 bits = 4;
1547 } else if (shift_control == 1) {
1548 full_update |= update_palette16(s);
1549 if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
1550 v = VGA_DRAW_LINE2D2;
1551 } else {
1552 v = VGA_DRAW_LINE2;
1554 bits = 4;
1555 } else {
1556 switch(s->get_bpp(s)) {
1557 default:
1558 case 0:
1559 full_update |= update_palette256(s);
1560 v = VGA_DRAW_LINE8D2;
1561 bits = 4;
1562 break;
1563 case 8:
1564 full_update |= update_palette256(s);
1565 v = VGA_DRAW_LINE8;
1566 bits = 8;
1567 break;
1568 case 15:
1569 v = s->big_endian_fb ? VGA_DRAW_LINE15_BE : VGA_DRAW_LINE15_LE;
1570 bits = 16;
1571 break;
1572 case 16:
1573 v = s->big_endian_fb ? VGA_DRAW_LINE16_BE : VGA_DRAW_LINE16_LE;
1574 bits = 16;
1575 break;
1576 case 24:
1577 v = s->big_endian_fb ? VGA_DRAW_LINE24_BE : VGA_DRAW_LINE24_LE;
1578 bits = 24;
1579 break;
1580 case 32:
1581 v = s->big_endian_fb ? VGA_DRAW_LINE32_BE : VGA_DRAW_LINE32_LE;
1582 bits = 32;
1583 break;
1586 vga_draw_line = vga_draw_line_table[v];
1588 if (!is_buffer_shared(surface) && s->cursor_invalidate) {
1589 s->cursor_invalidate(s);
1592 line_offset = s->line_offset;
1593 #if 0
1594 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",
1595 width, height, v, line_offset, s->cr[9], s->cr[VGA_CRTC_MODE],
1596 s->line_compare, s->sr[VGA_SEQ_CLOCK_MODE]);
1597 #endif
1598 addr1 = (s->start_addr * 4);
1599 bwidth = (width * bits + 7) / 8;
1600 y_start = -1;
1601 page_min = -1;
1602 page_max = 0;
1603 d = surface_data(surface);
1604 linesize = surface_stride(surface);
1605 y1 = 0;
1606 for(y = 0; y < height; y++) {
1607 addr = addr1;
1608 if (!(s->cr[VGA_CRTC_MODE] & 1)) {
1609 int shift;
1610 /* CGA compatibility handling */
1611 shift = 14 + ((s->cr[VGA_CRTC_MODE] >> 6) & 1);
1612 addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
1614 if (!(s->cr[VGA_CRTC_MODE] & 2)) {
1615 addr = (addr & ~0x8000) | ((y1 & 2) << 14);
1617 update = full_update;
1618 page0 = addr;
1619 page1 = addr + bwidth - 1;
1620 update |= memory_region_get_dirty(&s->vram, page0, page1 - page0,
1621 DIRTY_MEMORY_VGA);
1622 /* explicit invalidation for the hardware cursor */
1623 update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
1624 if (update) {
1625 if (y_start < 0)
1626 y_start = y;
1627 if (page0 < page_min)
1628 page_min = page0;
1629 if (page1 > page_max)
1630 page_max = page1;
1631 if (!(is_buffer_shared(surface))) {
1632 vga_draw_line(s, d, s->vram_ptr + addr, width);
1633 if (s->cursor_draw_line)
1634 s->cursor_draw_line(s, d, y);
1636 } else {
1637 if (y_start >= 0) {
1638 /* flush to display */
1639 dpy_gfx_update(s->con, 0, y_start,
1640 disp_width, y - y_start);
1641 y_start = -1;
1644 if (!multi_run) {
1645 mask = (s->cr[VGA_CRTC_MODE] & 3) ^ 3;
1646 if ((y1 & mask) == mask)
1647 addr1 += line_offset;
1648 y1++;
1649 multi_run = multi_scan;
1650 } else {
1651 multi_run--;
1653 /* line compare acts on the displayed lines */
1654 if (y == s->line_compare)
1655 addr1 = 0;
1656 d += linesize;
1658 if (y_start >= 0) {
1659 /* flush to display */
1660 dpy_gfx_update(s->con, 0, y_start,
1661 disp_width, y - y_start);
1663 /* reset modified pages */
1664 if (page_max >= page_min) {
1665 memory_region_reset_dirty(&s->vram,
1666 page_min,
1667 page_max - page_min,
1668 DIRTY_MEMORY_VGA);
1670 memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
1673 static void vga_draw_blank(VGACommonState *s, int full_update)
1675 DisplaySurface *surface = qemu_console_surface(s->con);
1676 int i, w;
1677 uint8_t *d;
1679 if (!full_update)
1680 return;
1681 if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
1682 return;
1684 w = s->last_scr_width * surface_bytes_per_pixel(surface);
1685 d = surface_data(surface);
1686 for(i = 0; i < s->last_scr_height; i++) {
1687 memset(d, 0, w);
1688 d += surface_stride(surface);
1690 dpy_gfx_update(s->con, 0, 0,
1691 s->last_scr_width, s->last_scr_height);
1694 #define GMODE_TEXT 0
1695 #define GMODE_GRAPH 1
1696 #define GMODE_BLANK 2
1698 static void vga_update_display(void *opaque)
1700 VGACommonState *s = opaque;
1701 DisplaySurface *surface = qemu_console_surface(s->con);
1702 int full_update, graphic_mode;
1704 qemu_flush_coalesced_mmio_buffer();
1706 if (surface_bits_per_pixel(surface) == 0) {
1707 /* nothing to do */
1708 } else {
1709 full_update = 0;
1710 if (!(s->ar_index & 0x20)) {
1711 graphic_mode = GMODE_BLANK;
1712 } else {
1713 graphic_mode = s->gr[VGA_GFX_MISC] & VGA_GR06_GRAPHICS_MODE;
1715 if (graphic_mode != s->graphic_mode) {
1716 s->graphic_mode = graphic_mode;
1717 s->cursor_blink_time = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
1718 full_update = 1;
1720 switch(graphic_mode) {
1721 case GMODE_TEXT:
1722 vga_draw_text(s, full_update);
1723 break;
1724 case GMODE_GRAPH:
1725 vga_draw_graphic(s, full_update);
1726 break;
1727 case GMODE_BLANK:
1728 default:
1729 vga_draw_blank(s, full_update);
1730 break;
1735 /* force a full display refresh */
1736 static void vga_invalidate_display(void *opaque)
1738 VGACommonState *s = opaque;
1740 s->last_width = -1;
1741 s->last_height = -1;
1744 void vga_common_reset(VGACommonState *s)
1746 s->sr_index = 0;
1747 memset(s->sr, '\0', sizeof(s->sr));
1748 s->gr_index = 0;
1749 memset(s->gr, '\0', sizeof(s->gr));
1750 s->ar_index = 0;
1751 memset(s->ar, '\0', sizeof(s->ar));
1752 s->ar_flip_flop = 0;
1753 s->cr_index = 0;
1754 memset(s->cr, '\0', sizeof(s->cr));
1755 s->msr = 0;
1756 s->fcr = 0;
1757 s->st00 = 0;
1758 s->st01 = 0;
1759 s->dac_state = 0;
1760 s->dac_sub_index = 0;
1761 s->dac_read_index = 0;
1762 s->dac_write_index = 0;
1763 memset(s->dac_cache, '\0', sizeof(s->dac_cache));
1764 s->dac_8bit = 0;
1765 memset(s->palette, '\0', sizeof(s->palette));
1766 s->bank_offset = 0;
1767 s->vbe_index = 0;
1768 memset(s->vbe_regs, '\0', sizeof(s->vbe_regs));
1769 s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID5;
1770 s->vbe_start_addr = 0;
1771 s->vbe_line_offset = 0;
1772 s->vbe_bank_mask = (s->vram_size >> 16) - 1;
1773 memset(s->font_offsets, '\0', sizeof(s->font_offsets));
1774 s->graphic_mode = -1; /* force full update */
1775 s->shift_control = 0;
1776 s->double_scan = 0;
1777 s->line_offset = 0;
1778 s->line_compare = 0;
1779 s->start_addr = 0;
1780 s->plane_updated = 0;
1781 s->last_cw = 0;
1782 s->last_ch = 0;
1783 s->last_width = 0;
1784 s->last_height = 0;
1785 s->last_scr_width = 0;
1786 s->last_scr_height = 0;
1787 s->cursor_start = 0;
1788 s->cursor_end = 0;
1789 s->cursor_offset = 0;
1790 s->big_endian_fb = s->default_endian_fb;
1791 memset(s->invalidated_y_table, '\0', sizeof(s->invalidated_y_table));
1792 memset(s->last_palette, '\0', sizeof(s->last_palette));
1793 memset(s->last_ch_attr, '\0', sizeof(s->last_ch_attr));
1794 switch (vga_retrace_method) {
1795 case VGA_RETRACE_DUMB:
1796 break;
1797 case VGA_RETRACE_PRECISE:
1798 memset(&s->retrace_info, 0, sizeof (s->retrace_info));
1799 break;
1801 vga_update_memory_access(s);
1804 static void vga_reset(void *opaque)
1806 VGACommonState *s = opaque;
1807 vga_common_reset(s);
1810 #define TEXTMODE_X(x) ((x) % width)
1811 #define TEXTMODE_Y(x) ((x) / width)
1812 #define VMEM2CHTYPE(v) ((v & 0xff0007ff) | \
1813 ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1))
1814 /* relay text rendering to the display driver
1815 * instead of doing a full vga_update_display() */
1816 static void vga_update_text(void *opaque, console_ch_t *chardata)
1818 VGACommonState *s = opaque;
1819 int graphic_mode, i, cursor_offset, cursor_visible;
1820 int cw, cheight, width, height, size, c_min, c_max;
1821 uint32_t *src;
1822 console_ch_t *dst, val;
1823 char msg_buffer[80];
1824 int full_update = 0;
1826 qemu_flush_coalesced_mmio_buffer();
1828 if (!(s->ar_index & 0x20)) {
1829 graphic_mode = GMODE_BLANK;
1830 } else {
1831 graphic_mode = s->gr[VGA_GFX_MISC] & VGA_GR06_GRAPHICS_MODE;
1833 if (graphic_mode != s->graphic_mode) {
1834 s->graphic_mode = graphic_mode;
1835 full_update = 1;
1837 if (s->last_width == -1) {
1838 s->last_width = 0;
1839 full_update = 1;
1842 switch (graphic_mode) {
1843 case GMODE_TEXT:
1844 /* TODO: update palette */
1845 full_update |= update_basic_params(s);
1847 /* total width & height */
1848 cheight = (s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1;
1849 cw = 8;
1850 if (!(s->sr[VGA_SEQ_CLOCK_MODE] & VGA_SR01_CHAR_CLK_8DOTS)) {
1851 cw = 9;
1853 if (s->sr[VGA_SEQ_CLOCK_MODE] & 0x08) {
1854 cw = 16; /* NOTE: no 18 pixel wide */
1856 width = (s->cr[VGA_CRTC_H_DISP] + 1);
1857 if (s->cr[VGA_CRTC_V_TOTAL] == 100) {
1858 /* ugly hack for CGA 160x100x16 - explain me the logic */
1859 height = 100;
1860 } else {
1861 height = s->cr[VGA_CRTC_V_DISP_END] |
1862 ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) |
1863 ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3);
1864 height = (height + 1) / cheight;
1867 size = (height * width);
1868 if (size > CH_ATTR_SIZE) {
1869 if (!full_update)
1870 return;
1872 snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Text mode",
1873 width, height);
1874 break;
1877 if (width != s->last_width || height != s->last_height ||
1878 cw != s->last_cw || cheight != s->last_ch) {
1879 s->last_scr_width = width * cw;
1880 s->last_scr_height = height * cheight;
1881 qemu_console_resize(s->con, s->last_scr_width, s->last_scr_height);
1882 dpy_text_resize(s->con, width, height);
1883 s->last_depth = 0;
1884 s->last_width = width;
1885 s->last_height = height;
1886 s->last_ch = cheight;
1887 s->last_cw = cw;
1888 full_update = 1;
1891 if (full_update) {
1892 s->full_update_gfx = 1;
1894 if (s->full_update_text) {
1895 s->full_update_text = 0;
1896 full_update |= 1;
1899 /* Update "hardware" cursor */
1900 cursor_offset = ((s->cr[VGA_CRTC_CURSOR_HI] << 8) |
1901 s->cr[VGA_CRTC_CURSOR_LO]) - s->start_addr;
1902 if (cursor_offset != s->cursor_offset ||
1903 s->cr[VGA_CRTC_CURSOR_START] != s->cursor_start ||
1904 s->cr[VGA_CRTC_CURSOR_END] != s->cursor_end || full_update) {
1905 cursor_visible = !(s->cr[VGA_CRTC_CURSOR_START] & 0x20);
1906 if (cursor_visible && cursor_offset < size && cursor_offset >= 0)
1907 dpy_text_cursor(s->con,
1908 TEXTMODE_X(cursor_offset),
1909 TEXTMODE_Y(cursor_offset));
1910 else
1911 dpy_text_cursor(s->con, -1, -1);
1912 s->cursor_offset = cursor_offset;
1913 s->cursor_start = s->cr[VGA_CRTC_CURSOR_START];
1914 s->cursor_end = s->cr[VGA_CRTC_CURSOR_END];
1917 src = (uint32_t *) s->vram_ptr + s->start_addr;
1918 dst = chardata;
1920 if (full_update) {
1921 for (i = 0; i < size; src ++, dst ++, i ++)
1922 console_write_ch(dst, VMEM2CHTYPE(le32_to_cpu(*src)));
1924 dpy_text_update(s->con, 0, 0, width, height);
1925 } else {
1926 c_max = 0;
1928 for (i = 0; i < size; src ++, dst ++, i ++) {
1929 console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
1930 if (*dst != val) {
1931 *dst = val;
1932 c_max = i;
1933 break;
1936 c_min = i;
1937 for (; i < size; src ++, dst ++, i ++) {
1938 console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
1939 if (*dst != val) {
1940 *dst = val;
1941 c_max = i;
1945 if (c_min <= c_max) {
1946 i = TEXTMODE_Y(c_min);
1947 dpy_text_update(s->con, 0, i, width, TEXTMODE_Y(c_max) - i + 1);
1951 return;
1952 case GMODE_GRAPH:
1953 if (!full_update)
1954 return;
1956 s->get_resolution(s, &width, &height);
1957 snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Graphic mode",
1958 width, height);
1959 break;
1960 case GMODE_BLANK:
1961 default:
1962 if (!full_update)
1963 return;
1965 snprintf(msg_buffer, sizeof(msg_buffer), "VGA Blank mode");
1966 break;
1969 /* Display a message */
1970 s->last_width = 60;
1971 s->last_height = height = 3;
1972 dpy_text_cursor(s->con, -1, -1);
1973 dpy_text_resize(s->con, s->last_width, height);
1975 for (dst = chardata, i = 0; i < s->last_width * height; i ++)
1976 console_write_ch(dst ++, ' ');
1978 size = strlen(msg_buffer);
1979 width = (s->last_width - size) / 2;
1980 dst = chardata + s->last_width + width;
1981 for (i = 0; i < size; i ++)
1982 console_write_ch(dst ++, 0x00200100 | msg_buffer[i]);
1984 dpy_text_update(s->con, 0, 0, s->last_width, height);
1987 static uint64_t vga_mem_read(void *opaque, hwaddr addr,
1988 unsigned size)
1990 VGACommonState *s = opaque;
1992 return vga_mem_readb(s, addr);
1995 static void vga_mem_write(void *opaque, hwaddr addr,
1996 uint64_t data, unsigned size)
1998 VGACommonState *s = opaque;
2000 vga_mem_writeb(s, addr, data);
2003 const MemoryRegionOps vga_mem_ops = {
2004 .read = vga_mem_read,
2005 .write = vga_mem_write,
2006 .endianness = DEVICE_LITTLE_ENDIAN,
2007 .impl = {
2008 .min_access_size = 1,
2009 .max_access_size = 1,
2013 static int vga_common_post_load(void *opaque, int version_id)
2015 VGACommonState *s = opaque;
2017 /* force refresh */
2018 s->graphic_mode = -1;
2019 return 0;
2022 static bool vga_endian_state_needed(void *opaque)
2024 VGACommonState *s = opaque;
2027 * Only send the endian state if it's different from the
2028 * default one, thus ensuring backward compatibility for
2029 * migration of the common case
2031 return s->default_endian_fb != s->big_endian_fb;
2034 static const VMStateDescription vmstate_vga_endian = {
2035 .name = "vga.endian",
2036 .version_id = 1,
2037 .minimum_version_id = 1,
2038 .needed = vga_endian_state_needed,
2039 .fields = (VMStateField[]) {
2040 VMSTATE_BOOL(big_endian_fb, VGACommonState),
2041 VMSTATE_END_OF_LIST()
2045 const VMStateDescription vmstate_vga_common = {
2046 .name = "vga",
2047 .version_id = 2,
2048 .minimum_version_id = 2,
2049 .post_load = vga_common_post_load,
2050 .fields = (VMStateField[]) {
2051 VMSTATE_UINT32(latch, VGACommonState),
2052 VMSTATE_UINT8(sr_index, VGACommonState),
2053 VMSTATE_PARTIAL_BUFFER(sr, VGACommonState, 8),
2054 VMSTATE_UINT8(gr_index, VGACommonState),
2055 VMSTATE_PARTIAL_BUFFER(gr, VGACommonState, 16),
2056 VMSTATE_UINT8(ar_index, VGACommonState),
2057 VMSTATE_BUFFER(ar, VGACommonState),
2058 VMSTATE_INT32(ar_flip_flop, VGACommonState),
2059 VMSTATE_UINT8(cr_index, VGACommonState),
2060 VMSTATE_BUFFER(cr, VGACommonState),
2061 VMSTATE_UINT8(msr, VGACommonState),
2062 VMSTATE_UINT8(fcr, VGACommonState),
2063 VMSTATE_UINT8(st00, VGACommonState),
2064 VMSTATE_UINT8(st01, VGACommonState),
2066 VMSTATE_UINT8(dac_state, VGACommonState),
2067 VMSTATE_UINT8(dac_sub_index, VGACommonState),
2068 VMSTATE_UINT8(dac_read_index, VGACommonState),
2069 VMSTATE_UINT8(dac_write_index, VGACommonState),
2070 VMSTATE_BUFFER(dac_cache, VGACommonState),
2071 VMSTATE_BUFFER(palette, VGACommonState),
2073 VMSTATE_INT32(bank_offset, VGACommonState),
2074 VMSTATE_UINT8_EQUAL(is_vbe_vmstate, VGACommonState),
2075 VMSTATE_UINT16(vbe_index, VGACommonState),
2076 VMSTATE_UINT16_ARRAY(vbe_regs, VGACommonState, VBE_DISPI_INDEX_NB),
2077 VMSTATE_UINT32(vbe_start_addr, VGACommonState),
2078 VMSTATE_UINT32(vbe_line_offset, VGACommonState),
2079 VMSTATE_UINT32(vbe_bank_mask, VGACommonState),
2080 VMSTATE_END_OF_LIST()
2082 .subsections = (const VMStateDescription*[]) {
2083 &vmstate_vga_endian,
2084 NULL
2088 static const GraphicHwOps vga_ops = {
2089 .invalidate = vga_invalidate_display,
2090 .gfx_update = vga_update_display,
2091 .text_update = vga_update_text,
2094 static inline uint32_t uint_clamp(uint32_t val, uint32_t vmin, uint32_t vmax)
2096 if (val < vmin) {
2097 return vmin;
2099 if (val > vmax) {
2100 return vmax;
2102 return val;
2105 void vga_common_init(VGACommonState *s, Object *obj, bool global_vmstate)
2107 int i, j, v, b;
2109 for(i = 0;i < 256; i++) {
2110 v = 0;
2111 for(j = 0; j < 8; j++) {
2112 v |= ((i >> j) & 1) << (j * 4);
2114 expand4[i] = v;
2116 v = 0;
2117 for(j = 0; j < 4; j++) {
2118 v |= ((i >> (2 * j)) & 3) << (j * 4);
2120 expand2[i] = v;
2122 for(i = 0; i < 16; i++) {
2123 v = 0;
2124 for(j = 0; j < 4; j++) {
2125 b = ((i >> j) & 1);
2126 v |= b << (2 * j);
2127 v |= b << (2 * j + 1);
2129 expand4to8[i] = v;
2132 s->vram_size_mb = uint_clamp(s->vram_size_mb, 1, 512);
2133 s->vram_size_mb = pow2ceil(s->vram_size_mb);
2134 s->vram_size = s->vram_size_mb << 20;
2136 if (!s->vbe_size) {
2137 s->vbe_size = s->vram_size;
2140 s->is_vbe_vmstate = 1;
2141 memory_region_init_ram(&s->vram, obj, "vga.vram", s->vram_size,
2142 &error_fatal);
2143 vmstate_register_ram(&s->vram, global_vmstate ? NULL : DEVICE(obj));
2144 xen_register_framebuffer(&s->vram);
2145 s->vram_ptr = memory_region_get_ram_ptr(&s->vram);
2146 s->get_bpp = vga_get_bpp;
2147 s->get_offsets = vga_get_offsets;
2148 s->get_resolution = vga_get_resolution;
2149 s->hw_ops = &vga_ops;
2150 switch (vga_retrace_method) {
2151 case VGA_RETRACE_DUMB:
2152 s->retrace = vga_dumb_retrace;
2153 s->update_retrace_info = vga_dumb_update_retrace_info;
2154 break;
2156 case VGA_RETRACE_PRECISE:
2157 s->retrace = vga_precise_retrace;
2158 s->update_retrace_info = vga_precise_update_retrace_info;
2159 break;
2163 * Set default fb endian based on target, could probably be turned
2164 * into a device attribute set by the machine/platform to remove
2165 * all target endian dependencies from this file.
2167 #ifdef TARGET_WORDS_BIGENDIAN
2168 s->default_endian_fb = true;
2169 #else
2170 s->default_endian_fb = false;
2171 #endif
2172 vga_dirty_log_start(s);
2175 static const MemoryRegionPortio vga_portio_list[] = {
2176 { 0x04, 2, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3b4 */
2177 { 0x0a, 1, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3ba */
2178 { 0x10, 16, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3c0 */
2179 { 0x24, 2, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3d4 */
2180 { 0x2a, 1, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3da */
2181 PORTIO_END_OF_LIST(),
2184 static const MemoryRegionPortio vbe_portio_list[] = {
2185 { 0, 1, 2, .read = vbe_ioport_read_index, .write = vbe_ioport_write_index },
2186 # ifdef TARGET_I386
2187 { 1, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data },
2188 # endif
2189 { 2, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data },
2190 PORTIO_END_OF_LIST(),
2193 /* Used by both ISA and PCI */
2194 MemoryRegion *vga_init_io(VGACommonState *s, Object *obj,
2195 const MemoryRegionPortio **vga_ports,
2196 const MemoryRegionPortio **vbe_ports)
2198 MemoryRegion *vga_mem;
2200 *vga_ports = vga_portio_list;
2201 *vbe_ports = vbe_portio_list;
2203 vga_mem = g_malloc(sizeof(*vga_mem));
2204 memory_region_init_io(vga_mem, obj, &vga_mem_ops, s,
2205 "vga-lowmem", 0x20000);
2206 memory_region_set_flush_coalesced(vga_mem);
2208 return vga_mem;
2211 void vga_init(VGACommonState *s, Object *obj, MemoryRegion *address_space,
2212 MemoryRegion *address_space_io, bool init_vga_ports)
2214 MemoryRegion *vga_io_memory;
2215 const MemoryRegionPortio *vga_ports, *vbe_ports;
2217 qemu_register_reset(vga_reset, s);
2219 s->bank_offset = 0;
2221 s->legacy_address_space = address_space;
2223 vga_io_memory = vga_init_io(s, obj, &vga_ports, &vbe_ports);
2224 memory_region_add_subregion_overlap(address_space,
2225 0x000a0000,
2226 vga_io_memory,
2228 memory_region_set_coalescing(vga_io_memory);
2229 if (init_vga_ports) {
2230 portio_list_init(&s->vga_port_list, obj, vga_ports, s, "vga");
2231 portio_list_set_flush_coalesced(&s->vga_port_list);
2232 portio_list_add(&s->vga_port_list, address_space_io, 0x3b0);
2234 if (vbe_ports) {
2235 portio_list_init(&s->vbe_port_list, obj, vbe_ports, s, "vbe");
2236 portio_list_add(&s->vbe_port_list, address_space_io, 0x1ce);
2240 void vga_init_vbe(VGACommonState *s, Object *obj, MemoryRegion *system_memory)
2242 /* With pc-0.12 and below we map both the PCI BAR and the fixed VBE region,
2243 * so use an alias to avoid double-mapping the same region.
2245 memory_region_init_alias(&s->vram_vbe, obj, "vram.vbe",
2246 &s->vram, 0, memory_region_size(&s->vram));
2247 /* XXX: use optimized standard vga accesses */
2248 memory_region_add_subregion(system_memory,
2249 VBE_DISPI_LFB_PHYSICAL_ADDRESS,
2250 &s->vram_vbe);
2251 s->vbe_mapped = 1;