ia64/xen-unstable

view tools/ioemu/hw/vga.c @ 17804:124367e10376

stubdom: make non-VNC + stdvga work

Signed-off-by: Samuel Thibault <samuel.thibault@eu.citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Mon Jun 09 09:46:46 2008 +0100 (2008-06-09)
parents 638811f870ba
children adf05a812edb
line source
1 /*
2 * QEMU VGA Emulator.
3 *
4 * Copyright (c) 2003 Fabrice Bellard
5 *
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:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
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.
23 */
24 #include "vl.h"
25 #include "vga_int.h"
27 //#define DEBUG_VGA
28 //#define DEBUG_VGA_MEM
29 //#define DEBUG_VGA_REG
31 //#define DEBUG_BOCHS_VBE
33 /* force some bits to zero */
34 const uint8_t sr_mask[8] = {
35 (uint8_t)~0xfc,
36 (uint8_t)~0xc2,
37 (uint8_t)~0xf0,
38 (uint8_t)~0xc0,
39 (uint8_t)~0xf1,
40 (uint8_t)~0xff,
41 (uint8_t)~0xff,
42 (uint8_t)~0x00,
43 };
45 const uint8_t gr_mask[16] = {
46 (uint8_t)~0xf0, /* 0x00 */
47 (uint8_t)~0xf0, /* 0x01 */
48 (uint8_t)~0xf0, /* 0x02 */
49 (uint8_t)~0xe0, /* 0x03 */
50 (uint8_t)~0xfc, /* 0x04 */
51 (uint8_t)~0x84, /* 0x05 */
52 (uint8_t)~0xf0, /* 0x06 */
53 (uint8_t)~0xf0, /* 0x07 */
54 (uint8_t)~0x00, /* 0x08 */
55 (uint8_t)~0xff, /* 0x09 */
56 (uint8_t)~0xff, /* 0x0a */
57 (uint8_t)~0xff, /* 0x0b */
58 (uint8_t)~0xff, /* 0x0c */
59 (uint8_t)~0xff, /* 0x0d */
60 (uint8_t)~0xff, /* 0x0e */
61 (uint8_t)~0xff, /* 0x0f */
62 };
64 #define cbswap_32(__x) \
65 ((uint32_t)( \
66 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
67 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
68 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
69 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
71 #ifdef WORDS_BIGENDIAN
72 #define PAT(x) cbswap_32(x)
73 #else
74 #define PAT(x) (x)
75 #endif
77 #ifdef WORDS_BIGENDIAN
78 #define BIG 1
79 #else
80 #define BIG 0
81 #endif
83 #ifdef WORDS_BIGENDIAN
84 #define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
85 #else
86 #define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
87 #endif
89 static const uint32_t mask16[16] = {
90 PAT(0x00000000),
91 PAT(0x000000ff),
92 PAT(0x0000ff00),
93 PAT(0x0000ffff),
94 PAT(0x00ff0000),
95 PAT(0x00ff00ff),
96 PAT(0x00ffff00),
97 PAT(0x00ffffff),
98 PAT(0xff000000),
99 PAT(0xff0000ff),
100 PAT(0xff00ff00),
101 PAT(0xff00ffff),
102 PAT(0xffff0000),
103 PAT(0xffff00ff),
104 PAT(0xffffff00),
105 PAT(0xffffffff),
106 };
108 #undef PAT
110 #ifdef WORDS_BIGENDIAN
111 #define PAT(x) (x)
112 #else
113 #define PAT(x) cbswap_32(x)
114 #endif
116 static const uint32_t dmask16[16] = {
117 PAT(0x00000000),
118 PAT(0x000000ff),
119 PAT(0x0000ff00),
120 PAT(0x0000ffff),
121 PAT(0x00ff0000),
122 PAT(0x00ff00ff),
123 PAT(0x00ffff00),
124 PAT(0x00ffffff),
125 PAT(0xff000000),
126 PAT(0xff0000ff),
127 PAT(0xff00ff00),
128 PAT(0xff00ffff),
129 PAT(0xffff0000),
130 PAT(0xffff00ff),
131 PAT(0xffffff00),
132 PAT(0xffffffff),
133 };
135 static const uint32_t dmask4[4] = {
136 PAT(0x00000000),
137 PAT(0x0000ffff),
138 PAT(0xffff0000),
139 PAT(0xffffffff),
140 };
142 static uint32_t expand4[256];
143 static uint16_t expand2[256];
144 static uint8_t expand4to8[16];
146 static void vga_screen_dump(void *opaque, const char *filename);
148 static uint32_t vga_ioport_read(void *opaque, uint32_t addr)
149 {
150 VGAState *s = opaque;
151 int val, index;
153 /* check port range access depending on color/monochrome mode */
154 if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
155 (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION))) {
156 val = 0xff;
157 } else {
158 switch(addr) {
159 case 0x3c0:
160 if (s->ar_flip_flop == 0) {
161 val = s->ar_index;
162 } else {
163 val = 0;
164 }
165 break;
166 case 0x3c1:
167 index = s->ar_index & 0x1f;
168 if (index < 21)
169 val = s->ar[index];
170 else
171 val = 0;
172 break;
173 case 0x3c2:
174 val = s->st00;
175 break;
176 case 0x3c4:
177 val = s->sr_index;
178 break;
179 case 0x3c5:
180 val = s->sr[s->sr_index];
181 #ifdef DEBUG_VGA_REG
182 printf("vga: read SR%x = 0x%02x\n", s->sr_index, val);
183 #endif
184 break;
185 case 0x3c7:
186 val = s->dac_state;
187 break;
188 case 0x3c8:
189 val = s->dac_write_index;
190 break;
191 case 0x3c9:
192 val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
193 if (++s->dac_sub_index == 3) {
194 s->dac_sub_index = 0;
195 s->dac_read_index++;
196 }
197 break;
198 case 0x3ca:
199 val = s->fcr;
200 break;
201 case 0x3cc:
202 val = s->msr;
203 break;
204 case 0x3ce:
205 val = s->gr_index;
206 break;
207 case 0x3cf:
208 val = s->gr[s->gr_index];
209 #ifdef DEBUG_VGA_REG
210 printf("vga: read GR%x = 0x%02x\n", s->gr_index, val);
211 #endif
212 break;
213 case 0x3b4:
214 case 0x3d4:
215 val = s->cr_index;
216 break;
217 case 0x3b5:
218 case 0x3d5:
219 val = s->cr[s->cr_index];
220 #ifdef DEBUG_VGA_REG
221 printf("vga: read CR%x = 0x%02x\n", s->cr_index, val);
222 #endif
223 break;
224 case 0x3ba:
225 case 0x3da:
226 /* just toggle to fool polling */
227 s->st01 ^= ST01_V_RETRACE | ST01_DISP_ENABLE;
228 val = s->st01;
229 s->ar_flip_flop = 0;
230 break;
231 default:
232 val = 0x00;
233 break;
234 }
235 }
236 #if defined(DEBUG_VGA)
237 printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
238 #endif
239 return val;
240 }
242 static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
243 {
244 VGAState *s = opaque;
245 int index;
247 /* check port range access depending on color/monochrome mode */
248 if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
249 (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION)))
250 return;
252 #ifdef DEBUG_VGA
253 printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
254 #endif
256 switch(addr) {
257 case 0x3c0:
258 if (s->ar_flip_flop == 0) {
259 val &= 0x3f;
260 s->ar_index = val;
261 } else {
262 index = s->ar_index & 0x1f;
263 switch(index) {
264 case 0x00 ... 0x0f:
265 s->ar[index] = val & 0x3f;
266 break;
267 case 0x10:
268 s->ar[index] = val & ~0x10;
269 break;
270 case 0x11:
271 s->ar[index] = val;
272 break;
273 case 0x12:
274 s->ar[index] = val & ~0xc0;
275 break;
276 case 0x13:
277 s->ar[index] = val & ~0xf0;
278 break;
279 case 0x14:
280 s->ar[index] = val & ~0xf0;
281 break;
282 default:
283 break;
284 }
285 }
286 s->ar_flip_flop ^= 1;
287 break;
288 case 0x3c2:
289 s->msr = val & ~0x10;
290 break;
291 case 0x3c4:
292 s->sr_index = val & 7;
293 break;
294 case 0x3c5:
295 #ifdef DEBUG_VGA_REG
296 printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
297 #endif
298 s->sr[s->sr_index] = val & sr_mask[s->sr_index];
299 break;
300 case 0x3c7:
301 s->dac_read_index = val;
302 s->dac_sub_index = 0;
303 s->dac_state = 3;
304 break;
305 case 0x3c8:
306 s->dac_write_index = val;
307 s->dac_sub_index = 0;
308 s->dac_state = 0;
309 break;
310 case 0x3c9:
311 s->dac_cache[s->dac_sub_index] = val;
312 if (++s->dac_sub_index == 3) {
313 memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
314 s->dac_sub_index = 0;
315 s->dac_write_index++;
316 }
317 break;
318 case 0x3ce:
319 s->gr_index = val & 0x0f;
320 break;
321 case 0x3cf:
322 #ifdef DEBUG_VGA_REG
323 printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
324 #endif
325 s->gr[s->gr_index] = val & gr_mask[s->gr_index];
326 break;
327 case 0x3b4:
328 case 0x3d4:
329 s->cr_index = val;
330 break;
331 case 0x3b5:
332 case 0x3d5:
333 #ifdef DEBUG_VGA_REG
334 printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
335 #endif
336 /* handle CR0-7 protection */
337 if ((s->cr[0x11] & 0x80) && s->cr_index <= 7) {
338 /* can always write bit 4 of CR7 */
339 if (s->cr_index == 7)
340 s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
341 return;
342 }
343 switch(s->cr_index) {
344 case 0x01: /* horizontal display end */
345 case 0x07:
346 case 0x09:
347 case 0x0c:
348 case 0x0d:
349 case 0x12: /* veritcal display end */
350 s->cr[s->cr_index] = val;
351 break;
352 default:
353 s->cr[s->cr_index] = val;
354 break;
355 }
356 break;
357 case 0x3ba:
358 case 0x3da:
359 s->fcr = val & 0x10;
360 break;
361 }
362 }
364 #ifdef CONFIG_BOCHS_VBE
365 static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
366 {
367 VGAState *s = opaque;
368 uint32_t val;
369 val = s->vbe_index;
370 return val;
371 }
373 static uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr)
374 {
375 VGAState *s = opaque;
376 uint32_t val;
378 if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
379 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_GETCAPS) {
380 switch(s->vbe_index) {
381 /* XXX: do not hardcode ? */
382 case VBE_DISPI_INDEX_XRES:
383 val = VBE_DISPI_MAX_XRES;
384 break;
385 case VBE_DISPI_INDEX_YRES:
386 val = VBE_DISPI_MAX_YRES;
387 break;
388 case VBE_DISPI_INDEX_BPP:
389 val = VBE_DISPI_MAX_BPP;
390 break;
391 default:
392 val = s->vbe_regs[s->vbe_index];
393 break;
394 }
395 } else {
396 val = s->vbe_regs[s->vbe_index];
397 }
398 } else {
399 val = 0;
400 }
401 #ifdef DEBUG_BOCHS_VBE
402 printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val);
403 #endif
404 return val;
405 }
407 static void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val)
408 {
409 VGAState *s = opaque;
410 s->vbe_index = val;
411 }
413 static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
414 {
415 VGAState *s = opaque;
417 if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
418 #ifdef DEBUG_BOCHS_VBE
419 printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val);
420 #endif
421 switch(s->vbe_index) {
422 case VBE_DISPI_INDEX_ID:
423 if (val == VBE_DISPI_ID0 ||
424 val == VBE_DISPI_ID1 ||
425 val == VBE_DISPI_ID2 ||
426 val == VBE_DISPI_ID3 ||
427 val == VBE_DISPI_ID4) {
428 s->vbe_regs[s->vbe_index] = val;
429 }
430 break;
431 case VBE_DISPI_INDEX_XRES:
432 if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) {
433 s->vbe_regs[s->vbe_index] = val;
434 }
435 break;
436 case VBE_DISPI_INDEX_YRES:
437 if (val <= VBE_DISPI_MAX_YRES) {
438 s->vbe_regs[s->vbe_index] = val;
439 }
440 break;
441 case VBE_DISPI_INDEX_BPP:
442 if (val == 0)
443 val = 8;
444 if (val == 4 || val == 8 || val == 15 ||
445 val == 16 || val == 24 || val == 32) {
446 s->vbe_regs[s->vbe_index] = val;
447 }
448 break;
449 case VBE_DISPI_INDEX_BANK:
450 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
451 val &= (s->vbe_bank_mask >> 2);
452 } else {
453 val &= s->vbe_bank_mask;
454 }
455 s->vbe_regs[s->vbe_index] = val;
456 s->bank_offset = (val << 16);
457 break;
458 case VBE_DISPI_INDEX_ENABLE:
459 if ((val & VBE_DISPI_ENABLED) &&
460 !(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
461 int h, shift_control;
463 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] =
464 s->vbe_regs[VBE_DISPI_INDEX_XRES];
465 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] =
466 s->vbe_regs[VBE_DISPI_INDEX_YRES];
467 s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
468 s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
470 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
471 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1;
472 else
473 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] *
474 ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
475 s->vbe_start_addr = 0;
477 /* clear the screen (should be done in BIOS) */
478 if (!(val & VBE_DISPI_NOCLEARMEM)) {
479 memset(s->vram_ptr, 0,
480 s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
481 }
483 /* we initialize the VGA graphic mode (should be done
484 in BIOS) */
485 s->gr[0x06] = (s->gr[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
486 s->cr[0x17] |= 3; /* no CGA modes */
487 s->cr[0x13] = s->vbe_line_offset >> 3;
488 /* width */
489 s->cr[0x01] = (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
490 /* height (only meaningful if < 1024) */
491 h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
492 s->cr[0x12] = h;
493 s->cr[0x07] = (s->cr[0x07] & ~0x42) |
494 ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
495 /* line compare to 1023 */
496 s->cr[0x18] = 0xff;
497 s->cr[0x07] |= 0x10;
498 s->cr[0x09] |= 0x40;
500 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
501 shift_control = 0;
502 s->sr[0x01] &= ~8; /* no double line */
503 } else {
504 shift_control = 2;
505 s->sr[4] |= 0x08; /* set chain 4 mode */
506 s->sr[2] |= 0x0f; /* activate all planes */
507 }
508 s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5);
509 s->cr[0x09] &= ~0x9f; /* no double scan */
510 } else {
511 /* XXX: the bios should do that */
512 s->bank_offset = 0;
513 }
514 s->dac_8bit = (val & VBE_DISPI_8BIT_DAC) > 0;
515 s->vbe_regs[s->vbe_index] = val;
516 break;
517 case VBE_DISPI_INDEX_VIRT_WIDTH:
518 {
519 int w, h, line_offset;
521 if (val < s->vbe_regs[VBE_DISPI_INDEX_XRES])
522 return;
523 w = val;
524 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
525 line_offset = w >> 1;
526 else
527 line_offset = w * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
528 h = s->vram_size / line_offset;
529 /* XXX: support weird bochs semantics ? */
530 if (h < s->vbe_regs[VBE_DISPI_INDEX_YRES])
531 return;
532 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = w;
533 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h;
534 s->vbe_line_offset = line_offset;
535 }
536 break;
537 case VBE_DISPI_INDEX_X_OFFSET:
538 case VBE_DISPI_INDEX_Y_OFFSET:
539 {
540 int x;
541 s->vbe_regs[s->vbe_index] = val;
542 s->vbe_start_addr = s->vbe_line_offset * s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET];
543 x = s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET];
544 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
545 s->vbe_start_addr += x >> 1;
546 else
547 s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
548 s->vbe_start_addr >>= 2;
549 }
550 break;
551 default:
552 break;
553 }
554 }
555 }
556 #endif
558 /* called for accesses between 0xa0000 and 0xc0000 */
559 uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr)
560 {
561 VGAState *s = opaque;
562 int memory_map_mode, plane;
563 uint32_t ret;
565 /* convert to VGA memory offset */
566 memory_map_mode = (s->gr[6] >> 2) & 3;
567 addr &= 0x1ffff;
568 switch(memory_map_mode) {
569 case 0:
570 break;
571 case 1:
572 if (addr >= 0x10000)
573 return 0xff;
574 addr += s->bank_offset;
575 break;
576 case 2:
577 addr -= 0x10000;
578 if (addr >= 0x8000)
579 return 0xff;
580 break;
581 default:
582 case 3:
583 addr -= 0x18000;
584 if (addr >= 0x8000)
585 return 0xff;
586 break;
587 }
589 if (s->sr[4] & 0x08) {
590 /* chain 4 mode : simplest access */
591 ret = s->vram_ptr[addr];
592 } else if (s->gr[5] & 0x10) {
593 /* odd/even mode (aka text mode mapping) */
594 plane = (s->gr[4] & 2) | (addr & 1);
595 ret = s->vram_ptr[((addr & ~1) << 1) | plane];
596 } else {
597 /* standard VGA latched access */
598 s->latch = ((uint32_t *)s->vram_ptr)[addr];
600 if (!(s->gr[5] & 0x08)) {
601 /* read mode 0 */
602 plane = s->gr[4];
603 ret = GET_PLANE(s->latch, plane);
604 } else {
605 /* read mode 1 */
606 ret = (s->latch ^ mask16[s->gr[2]]) & mask16[s->gr[7]];
607 ret |= ret >> 16;
608 ret |= ret >> 8;
609 ret = (~ret) & 0xff;
610 }
611 }
612 return ret;
613 }
615 static uint32_t vga_mem_readw(void *opaque, target_phys_addr_t addr)
616 {
617 uint32_t v;
618 #ifdef TARGET_WORDS_BIGENDIAN
619 v = vga_mem_readb(opaque, addr) << 8;
620 v |= vga_mem_readb(opaque, addr + 1);
621 #else
622 v = vga_mem_readb(opaque, addr);
623 v |= vga_mem_readb(opaque, addr + 1) << 8;
624 #endif
625 return v;
626 }
628 static uint32_t vga_mem_readl(void *opaque, target_phys_addr_t addr)
629 {
630 uint32_t v;
631 #ifdef TARGET_WORDS_BIGENDIAN
632 v = vga_mem_readb(opaque, addr) << 24;
633 v |= vga_mem_readb(opaque, addr + 1) << 16;
634 v |= vga_mem_readb(opaque, addr + 2) << 8;
635 v |= vga_mem_readb(opaque, addr + 3);
636 #else
637 v = vga_mem_readb(opaque, addr);
638 v |= vga_mem_readb(opaque, addr + 1) << 8;
639 v |= vga_mem_readb(opaque, addr + 2) << 16;
640 v |= vga_mem_readb(opaque, addr + 3) << 24;
641 #endif
642 return v;
643 }
645 /* called for accesses between 0xa0000 and 0xc0000 */
646 void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
647 {
648 VGAState *s = opaque;
649 int memory_map_mode, plane, write_mode, b, func_select, mask;
650 uint32_t write_mask, bit_mask, set_mask;
652 #ifdef DEBUG_VGA_MEM
653 printf("vga: [0x%x] = 0x%02x\n", addr, val);
654 #endif
655 /* convert to VGA memory offset */
656 memory_map_mode = (s->gr[6] >> 2) & 3;
657 addr &= 0x1ffff;
658 switch(memory_map_mode) {
659 case 0:
660 break;
661 case 1:
662 if (addr >= 0x10000)
663 return;
664 addr += s->bank_offset;
665 break;
666 case 2:
667 addr -= 0x10000;
668 if (addr >= 0x8000)
669 return;
670 break;
671 default:
672 case 3:
673 addr -= 0x18000;
674 if (addr >= 0x8000)
675 return;
676 break;
677 }
679 if (s->sr[4] & 0x08) {
680 /* chain 4 mode : simplest access */
681 plane = addr & 3;
682 mask = (1 << plane);
683 if (s->sr[2] & mask) {
684 s->vram_ptr[addr] = val;
685 #ifdef DEBUG_VGA_MEM
686 printf("vga: chain4: [0x%x]\n", addr);
687 #endif
688 s->plane_updated |= mask; /* only used to detect font change */
689 cpu_physical_memory_set_dirty(s->vram_offset + addr);
690 }
691 } else if (s->gr[5] & 0x10) {
692 /* odd/even mode (aka text mode mapping) */
693 plane = (s->gr[4] & 2) | (addr & 1);
694 mask = (1 << plane);
695 if (s->sr[2] & mask) {
696 addr = ((addr & ~1) << 1) | plane;
697 s->vram_ptr[addr] = val;
698 #ifdef DEBUG_VGA_MEM
699 printf("vga: odd/even: [0x%x]\n", addr);
700 #endif
701 s->plane_updated |= mask; /* only used to detect font change */
702 cpu_physical_memory_set_dirty(s->vram_offset + addr);
703 }
704 } else {
705 /* standard VGA latched access */
706 write_mode = s->gr[5] & 3;
707 switch(write_mode) {
708 default:
709 case 0:
710 /* rotate */
711 b = s->gr[3] & 7;
712 val = ((val >> b) | (val << (8 - b))) & 0xff;
713 val |= val << 8;
714 val |= val << 16;
716 /* apply set/reset mask */
717 set_mask = mask16[s->gr[1]];
718 val = (val & ~set_mask) | (mask16[s->gr[0]] & set_mask);
719 bit_mask = s->gr[8];
720 break;
721 case 1:
722 val = s->latch;
723 goto do_write;
724 case 2:
725 val = mask16[val & 0x0f];
726 bit_mask = s->gr[8];
727 break;
728 case 3:
729 /* rotate */
730 b = s->gr[3] & 7;
731 val = (val >> b) | (val << (8 - b));
733 bit_mask = s->gr[8] & val;
734 val = mask16[s->gr[0]];
735 break;
736 }
738 /* apply logical operation */
739 func_select = s->gr[3] >> 3;
740 switch(func_select) {
741 case 0:
742 default:
743 /* nothing to do */
744 break;
745 case 1:
746 /* and */
747 val &= s->latch;
748 break;
749 case 2:
750 /* or */
751 val |= s->latch;
752 break;
753 case 3:
754 /* xor */
755 val ^= s->latch;
756 break;
757 }
759 /* apply bit mask */
760 bit_mask |= bit_mask << 8;
761 bit_mask |= bit_mask << 16;
762 val = (val & bit_mask) | (s->latch & ~bit_mask);
764 do_write:
765 /* mask data according to sr[2] */
766 mask = s->sr[2];
767 s->plane_updated |= mask; /* only used to detect font change */
768 write_mask = mask16[mask];
769 ((uint32_t *)s->vram_ptr)[addr] =
770 (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
771 (val & write_mask);
772 #ifdef DEBUG_VGA_MEM
773 printf("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n",
774 addr * 4, write_mask, val);
775 #endif
776 cpu_physical_memory_set_dirty(s->vram_offset + (addr << 2));
777 }
778 }
780 static void vga_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
781 {
782 #ifdef TARGET_WORDS_BIGENDIAN
783 vga_mem_writeb(opaque, addr, (val >> 8) & 0xff);
784 vga_mem_writeb(opaque, addr + 1, val & 0xff);
785 #else
786 vga_mem_writeb(opaque, addr, val & 0xff);
787 vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
788 #endif
789 }
791 static void vga_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
792 {
793 #ifdef TARGET_WORDS_BIGENDIAN
794 vga_mem_writeb(opaque, addr, (val >> 24) & 0xff);
795 vga_mem_writeb(opaque, addr + 1, (val >> 16) & 0xff);
796 vga_mem_writeb(opaque, addr + 2, (val >> 8) & 0xff);
797 vga_mem_writeb(opaque, addr + 3, val & 0xff);
798 #else
799 vga_mem_writeb(opaque, addr, val & 0xff);
800 vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
801 vga_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff);
802 vga_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff);
803 #endif
804 }
806 typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
807 const uint8_t *font_ptr, int h,
808 uint32_t fgcol, uint32_t bgcol);
809 typedef void vga_draw_glyph9_func(uint8_t *d, int linesize,
810 const uint8_t *font_ptr, int h,
811 uint32_t fgcol, uint32_t bgcol, int dup9);
812 typedef void vga_draw_line_func(VGAState *s1, uint8_t *d,
813 const uint8_t *s, int width);
815 static inline unsigned int rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b)
816 {
817 return ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6);
818 }
820 static inline unsigned int rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b)
821 {
822 return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
823 }
825 static inline unsigned int rgb_to_pixel16(unsigned int r, unsigned int g, unsigned b)
826 {
827 return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
828 }
830 static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b)
831 {
832 return (r << 16) | (g << 8) | b;
833 }
835 static inline unsigned int rgb_to_pixel32bgr(unsigned int r, unsigned int g, unsigned b)
836 {
837 return (b << 16) | (g << 8) | r;
838 }
840 #define DEPTH 8
841 #include "vga_template.h"
843 #define DEPTH 15
844 #include "vga_template.h"
846 #define DEPTH 16
847 #include "vga_template.h"
849 #define DEPTH 32
850 #include "vga_template.h"
852 #define BGR_FORMAT
853 #define DEPTH 32
854 #include "vga_template.h"
856 static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
857 {
858 unsigned int col;
859 col = rgb_to_pixel8(r, g, b);
860 col |= col << 8;
861 col |= col << 16;
862 return col;
863 }
865 static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b)
866 {
867 unsigned int col;
868 col = rgb_to_pixel15(r, g, b);
869 col |= col << 16;
870 return col;
871 }
873 static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
874 {
875 unsigned int col;
876 col = rgb_to_pixel16(r, g, b);
877 col |= col << 16;
878 return col;
879 }
881 static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
882 {
883 unsigned int col;
884 col = rgb_to_pixel32(r, g, b);
885 return col;
886 }
888 static unsigned int rgb_to_pixel32bgr_dup(unsigned int r, unsigned int g, unsigned b)
889 {
890 unsigned int col;
891 col = rgb_to_pixel32bgr(r, g, b);
892 return col;
893 }
895 /* return true if the palette was modified */
896 static int update_palette16(VGAState *s)
897 {
898 int full_update, i;
899 uint32_t v, col, *palette;
901 full_update = 0;
902 palette = s->last_palette;
903 for(i = 0; i < 16; i++) {
904 v = s->ar[i];
905 if (s->ar[0x10] & 0x80)
906 v = ((s->ar[0x14] & 0xf) << 4) | (v & 0xf);
907 else
908 v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f);
909 v = v * 3;
910 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
911 c6_to_8(s->palette[v + 1]),
912 c6_to_8(s->palette[v + 2]));
913 if (col != palette[i]) {
914 full_update = 1;
915 palette[i] = col;
916 }
917 }
918 return full_update;
919 }
921 /* return true if the palette was modified */
922 static int update_palette256(VGAState *s)
923 {
924 int full_update, i;
925 uint32_t v, col, *palette;
927 full_update = 0;
928 palette = s->last_palette;
929 v = 0;
930 for(i = 0; i < 256; i++) {
931 if (s->dac_8bit) {
932 col = s->rgb_to_pixel(s->palette[v],
933 s->palette[v + 1],
934 s->palette[v + 2]);
935 } else {
936 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
937 c6_to_8(s->palette[v + 1]),
938 c6_to_8(s->palette[v + 2]));
939 }
940 if (col != palette[i]) {
941 full_update = 1;
942 palette[i] = col;
943 }
944 v += 3;
945 }
946 return full_update;
947 }
949 static void vga_get_offsets(VGAState *s,
950 uint32_t *pline_offset,
951 uint32_t *pstart_addr,
952 uint32_t *pline_compare)
953 {
954 uint32_t start_addr, line_offset, line_compare;
955 #ifdef CONFIG_BOCHS_VBE
956 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
957 line_offset = s->vbe_line_offset;
958 start_addr = s->vbe_start_addr;
959 line_compare = 65535;
960 } else
961 #endif
962 {
963 /* compute line_offset in bytes */
964 line_offset = s->cr[0x13];
965 line_offset <<= 3;
967 /* starting address */
968 start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8);
970 /* line compare */
971 line_compare = s->cr[0x18] |
972 ((s->cr[0x07] & 0x10) << 4) |
973 ((s->cr[0x09] & 0x40) << 3);
974 }
975 *pline_offset = line_offset;
976 *pstart_addr = start_addr;
977 *pline_compare = line_compare;
978 }
980 /* update start_addr and line_offset. Return TRUE if modified */
981 static int update_basic_params(VGAState *s)
982 {
983 int full_update;
984 uint32_t start_addr, line_offset, line_compare;
986 full_update = 0;
988 s->get_offsets(s, &line_offset, &start_addr, &line_compare);
990 if (line_offset != s->line_offset ||
991 start_addr != s->start_addr ||
992 line_compare != s->line_compare) {
993 s->line_offset = line_offset;
994 s->start_addr = start_addr;
995 s->line_compare = line_compare;
996 full_update = 1;
997 }
998 return full_update;
999 }
1001 #define NB_DEPTHS 5
1003 static inline int get_depth_index(DisplayState *s)
1005 switch(s->depth) {
1006 default:
1007 case 8:
1008 return 0;
1009 case 15:
1010 return 1;
1011 case 16:
1012 return 2;
1013 case 32:
1014 if (s->bgr)
1015 return 4;
1016 else
1017 return 3;
1021 static vga_draw_glyph8_func *vga_draw_glyph8_table[NB_DEPTHS] = {
1022 vga_draw_glyph8_8,
1023 vga_draw_glyph8_16,
1024 vga_draw_glyph8_16,
1025 vga_draw_glyph8_32,
1026 vga_draw_glyph8_32,
1027 };
1029 static vga_draw_glyph8_func *vga_draw_glyph16_table[NB_DEPTHS] = {
1030 vga_draw_glyph16_8,
1031 vga_draw_glyph16_16,
1032 vga_draw_glyph16_16,
1033 vga_draw_glyph16_32,
1034 vga_draw_glyph16_32,
1035 };
1037 static vga_draw_glyph9_func *vga_draw_glyph9_table[NB_DEPTHS] = {
1038 vga_draw_glyph9_8,
1039 vga_draw_glyph9_16,
1040 vga_draw_glyph9_16,
1041 vga_draw_glyph9_32,
1042 vga_draw_glyph9_32,
1043 };
1045 static const uint8_t cursor_glyph[32 * 4] = {
1046 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1047 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1048 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1049 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1050 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1051 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1052 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1053 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1054 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1055 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1056 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1057 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1058 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1059 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1060 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1061 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1062 };
1064 typedef unsigned int rgb_to_pixel_dup_func(unsigned int r, unsigned int g, unsigned b);
1066 static rgb_to_pixel_dup_func *rgb_to_pixel_dup_table[NB_DEPTHS];
1068 static int old_depth = 0;
1070 /*
1071 * Text mode update
1072 * Missing:
1073 * - double scan
1074 * - double width
1075 * - underline
1076 * - flashing
1077 */
1078 static void vga_draw_text(VGAState *s, int full_update)
1080 int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
1081 int cx_min, cx_max, linesize, x_incr;
1082 uint32_t offset, fgcol, bgcol, v, cursor_offset;
1083 uint8_t *d1, *d, *src, *s1, *dest, *cursor_ptr;
1084 const uint8_t *font_ptr, *font_base[2];
1085 int dup9, line_offset, depth_index;
1086 uint32_t *palette;
1087 uint32_t *ch_attr_ptr;
1088 vga_draw_glyph8_func *vga_draw_glyph8;
1089 vga_draw_glyph9_func *vga_draw_glyph9;
1091 /* Disable dirty bit tracking */
1092 xc_hvm_track_dirty_vram(xc_handle, domid, 0, 0, NULL);
1094 /* total width & height */
1095 cheight = (s->cr[9] & 0x1f) + 1;
1096 cw = 8;
1097 if (!(s->sr[1] & 0x01))
1098 cw = 9;
1099 if (s->sr[1] & 0x08)
1100 cw = 16; /* NOTE: no 18 pixel wide */
1101 width = (s->cr[0x01] + 1);
1102 if (s->cr[0x06] == 100) {
1103 /* ugly hack for CGA 160x100x16 - explain me the logic */
1104 height = 100;
1105 } else {
1106 height = s->cr[0x12] |
1107 ((s->cr[0x07] & 0x02) << 7) |
1108 ((s->cr[0x07] & 0x40) << 3);
1109 height = (height + 1) / cheight;
1111 if ((height * width) > CH_ATTR_SIZE) {
1112 /* better than nothing: exit if transient size is too big */
1113 return;
1116 s->last_scr_width = width * cw;
1117 s->last_scr_height = height * cheight;
1118 if (s->ds->dpy_resize_shared && old_depth) {
1119 dpy_resize_shared(s->ds, s->last_scr_width, s->last_scr_height, 0, s->last_scr_width * (s->ds->depth / 8), NULL);
1120 old_depth = 0;
1121 full_update = 1;
1122 } else if (width != s->last_width || height != s->last_height ||
1123 cw != s->last_cw || cheight != s->last_ch) {
1124 dpy_resize(s->ds, s->last_scr_width, s->last_scr_height);
1125 full_update = 1;
1127 s->last_width = width;
1128 s->last_height = height;
1129 s->last_ch = cheight;
1130 s->last_cw = cw;
1132 s->rgb_to_pixel =
1133 rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1135 full_update |= update_palette16(s);
1136 palette = s->last_palette;
1138 x_incr = cw * ((s->ds->depth + 7) >> 3);
1139 /* compute font data address (in plane 2) */
1140 v = s->sr[3];
1141 offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
1142 if (offset != s->font_offsets[0]) {
1143 s->font_offsets[0] = offset;
1144 full_update = 1;
1146 font_base[0] = s->vram_ptr + offset;
1148 offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
1149 font_base[1] = s->vram_ptr + offset;
1150 if (offset != s->font_offsets[1]) {
1151 s->font_offsets[1] = offset;
1152 full_update = 1;
1154 if (s->plane_updated & (1 << 2)) {
1155 /* if the plane 2 was modified since the last display, it
1156 indicates the font may have been modified */
1157 s->plane_updated = 0;
1158 full_update = 1;
1160 full_update |= update_basic_params(s);
1162 line_offset = s->line_offset;
1163 s1 = s->vram_ptr + (s->start_addr * 4);
1165 cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
1166 if (cursor_offset != s->cursor_offset ||
1167 s->cr[0xa] != s->cursor_start ||
1168 s->cr[0xb] != s->cursor_end) {
1169 /* if the cursor position changed, we update the old and new
1170 chars */
1171 if (s->cursor_offset < CH_ATTR_SIZE)
1172 s->last_ch_attr[s->cursor_offset] = -1;
1173 if (cursor_offset < CH_ATTR_SIZE)
1174 s->last_ch_attr[cursor_offset] = -1;
1175 s->cursor_offset = cursor_offset;
1176 s->cursor_start = s->cr[0xa];
1177 s->cursor_end = s->cr[0xb];
1179 cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
1181 depth_index = get_depth_index(s->ds);
1182 if (cw == 16)
1183 vga_draw_glyph8 = vga_draw_glyph16_table[depth_index];
1184 else
1185 vga_draw_glyph8 = vga_draw_glyph8_table[depth_index];
1186 vga_draw_glyph9 = vga_draw_glyph9_table[depth_index];
1188 dest = s->ds->data;
1189 linesize = s->ds->linesize;
1190 ch_attr_ptr = s->last_ch_attr;
1191 for(cy = 0; cy < height; cy++) {
1192 d1 = dest;
1193 src = s1;
1194 cx_min = width;
1195 cx_max = -1;
1196 for(cx = 0; cx < width; cx++) {
1197 ch_attr = *(uint16_t *)src;
1198 if (full_update || ch_attr != *ch_attr_ptr) {
1199 if (cx < cx_min)
1200 cx_min = cx;
1201 if (cx > cx_max)
1202 cx_max = cx;
1203 *ch_attr_ptr = ch_attr;
1204 #ifdef WORDS_BIGENDIAN
1205 ch = ch_attr >> 8;
1206 cattr = ch_attr & 0xff;
1207 #else
1208 ch = ch_attr & 0xff;
1209 cattr = ch_attr >> 8;
1210 #endif
1211 font_ptr = font_base[(cattr >> 3) & 1];
1212 font_ptr += 32 * 4 * ch;
1213 bgcol = palette[cattr >> 4];
1214 fgcol = palette[cattr & 0x0f];
1215 if (cw != 9) {
1216 vga_draw_glyph8(d1, linesize,
1217 font_ptr, cheight, fgcol, bgcol);
1218 } else {
1219 dup9 = 0;
1220 if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))
1221 dup9 = 1;
1222 vga_draw_glyph9(d1, linesize,
1223 font_ptr, cheight, fgcol, bgcol, dup9);
1225 if (src == cursor_ptr &&
1226 !(s->cr[0x0a] & 0x20)) {
1227 int line_start, line_last, h;
1228 /* draw the cursor */
1229 line_start = s->cr[0x0a] & 0x1f;
1230 line_last = s->cr[0x0b] & 0x1f;
1231 /* XXX: check that */
1232 if (line_last > cheight - 1)
1233 line_last = cheight - 1;
1234 if (line_last >= line_start && line_start < cheight) {
1235 h = line_last - line_start + 1;
1236 d = d1 + linesize * line_start;
1237 if (cw != 9) {
1238 vga_draw_glyph8(d, linesize,
1239 cursor_glyph, h, fgcol, bgcol);
1240 } else {
1241 vga_draw_glyph9(d, linesize,
1242 cursor_glyph, h, fgcol, bgcol, 1);
1247 d1 += x_incr;
1248 src += 4;
1249 ch_attr_ptr++;
1251 if (cx_max != -1) {
1252 dpy_update(s->ds, cx_min * cw, cy * cheight,
1253 (cx_max - cx_min + 1) * cw, cheight);
1255 dest += linesize * cheight;
1256 s1 += line_offset;
1260 enum {
1261 VGA_DRAW_LINE2,
1262 VGA_DRAW_LINE2D2,
1263 VGA_DRAW_LINE4,
1264 VGA_DRAW_LINE4D2,
1265 VGA_DRAW_LINE8D2,
1266 VGA_DRAW_LINE8,
1267 VGA_DRAW_LINE15,
1268 VGA_DRAW_LINE16,
1269 VGA_DRAW_LINE24,
1270 VGA_DRAW_LINE32,
1271 VGA_DRAW_LINE_NB,
1272 };
1274 static vga_draw_line_func *vga_draw_line_table[NB_DEPTHS * VGA_DRAW_LINE_NB] = {
1275 vga_draw_line2_8,
1276 vga_draw_line2_16,
1277 vga_draw_line2_16,
1278 vga_draw_line2_32,
1279 vga_draw_line2_32,
1281 vga_draw_line2d2_8,
1282 vga_draw_line2d2_16,
1283 vga_draw_line2d2_16,
1284 vga_draw_line2d2_32,
1285 vga_draw_line2d2_32,
1287 vga_draw_line4_8,
1288 vga_draw_line4_16,
1289 vga_draw_line4_16,
1290 vga_draw_line4_32,
1291 vga_draw_line4_32,
1293 vga_draw_line4d2_8,
1294 vga_draw_line4d2_16,
1295 vga_draw_line4d2_16,
1296 vga_draw_line4d2_32,
1297 vga_draw_line4d2_32,
1299 vga_draw_line8d2_8,
1300 vga_draw_line8d2_16,
1301 vga_draw_line8d2_16,
1302 vga_draw_line8d2_32,
1303 vga_draw_line8d2_32,
1305 vga_draw_line8_8,
1306 vga_draw_line8_16,
1307 vga_draw_line8_16,
1308 vga_draw_line8_32,
1309 vga_draw_line8_32,
1311 vga_draw_line15_8,
1312 vga_draw_line15_15,
1313 vga_draw_line15_16,
1314 vga_draw_line15_32,
1315 vga_draw_line15_32bgr,
1317 vga_draw_line16_8,
1318 vga_draw_line16_15,
1319 vga_draw_line16_16,
1320 vga_draw_line16_32,
1321 vga_draw_line16_32bgr,
1323 vga_draw_line24_8,
1324 vga_draw_line24_15,
1325 vga_draw_line24_16,
1326 vga_draw_line24_32,
1327 vga_draw_line24_32bgr,
1329 vga_draw_line32_8,
1330 vga_draw_line32_15,
1331 vga_draw_line32_16,
1332 vga_draw_line32_32,
1333 vga_draw_line32_32bgr,
1334 };
1336 static rgb_to_pixel_dup_func *rgb_to_pixel_dup_table[NB_DEPTHS] = {
1337 rgb_to_pixel8_dup,
1338 rgb_to_pixel15_dup,
1339 rgb_to_pixel16_dup,
1340 rgb_to_pixel32_dup,
1341 rgb_to_pixel32bgr_dup,
1342 };
1344 static int vga_get_bpp(VGAState *s)
1346 int ret;
1347 #ifdef CONFIG_BOCHS_VBE
1348 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1349 ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
1350 } else
1351 #endif
1353 ret = 0;
1355 return ret;
1358 static void vga_get_resolution(VGAState *s, int *pwidth, int *pheight)
1360 int width, height;
1362 #ifdef CONFIG_BOCHS_VBE
1363 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1364 width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
1365 height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
1366 } else
1367 #endif
1369 width = (s->cr[0x01] + 1) * 8;
1370 height = s->cr[0x12] |
1371 ((s->cr[0x07] & 0x02) << 7) |
1372 ((s->cr[0x07] & 0x40) << 3);
1373 height = (height + 1);
1375 *pwidth = width;
1376 *pheight = height;
1379 void vga_invalidate_scanlines(VGAState *s, int y1, int y2)
1381 int y;
1382 if (y1 >= VGA_MAX_HEIGHT)
1383 return;
1384 if (y2 >= VGA_MAX_HEIGHT)
1385 y2 = VGA_MAX_HEIGHT;
1386 for(y = y1; y < y2; y++) {
1387 s->invalidated_y_table[y >> 5] |= 1 << (y & 0x1f);
1391 static inline int cmp_vram(VGAState *s, int offset, int n)
1393 long *vp, *sp;
1395 if (s->vram_shadow == NULL)
1396 return 1;
1397 vp = (long *)(s->vram_ptr + offset);
1398 sp = (long *)(s->vram_shadow + offset);
1399 while ((n -= sizeof(*vp)) >= 0) {
1400 if (*vp++ != *sp++) {
1401 memcpy(sp - 1, vp - 1, n + sizeof(*vp));
1402 return 1;
1405 return 0;
1408 #ifdef USE_SSE2
1410 #include <signal.h>
1411 #include <setjmp.h>
1412 #include <emmintrin.h>
1414 int sse2_ok = 1;
1416 static inline unsigned int cpuid_edx(unsigned int op)
1418 unsigned int eax, edx;
1420 #ifdef __x86_64__
1421 #define __bx "rbx"
1422 #else
1423 #define __bx "ebx"
1424 #endif
1425 __asm__("push %%"__bx"; cpuid; pop %%"__bx
1426 : "=a" (eax), "=d" (edx)
1427 : "0" (op)
1428 : "cx");
1429 #undef __bx
1431 return edx;
1434 jmp_buf sse_jbuf;
1436 void intr(int sig)
1438 sse2_ok = 0;
1439 longjmp(sse_jbuf, 1);
1442 void check_sse2(void)
1444 /* Check 1: What does CPUID say? */
1445 if ((cpuid_edx(1) & 0x4000000) == 0) {
1446 sse2_ok = 0;
1447 return;
1450 /* Check 2: Can we use SSE2 in anger? */
1451 signal(SIGILL, intr);
1452 if (setjmp(sse_jbuf) == 0)
1453 __asm__("xorps %xmm0,%xmm0\n");
1456 int vram_dirty(VGAState *s, int offset, int n)
1458 __m128i *sp, *vp;
1460 if (s->vram_shadow == NULL)
1461 return 1;
1462 if (sse2_ok == 0)
1463 return cmp_vram(s, offset, n);
1464 vp = (__m128i *)(s->vram_ptr + offset);
1465 sp = (__m128i *)(s->vram_shadow + offset);
1466 while ((n -= sizeof(*vp)) >= 0) {
1467 if (_mm_movemask_epi8(_mm_cmpeq_epi8(*sp, *vp)) != 0xffff) {
1468 while (n >= 0) {
1469 _mm_store_si128(sp++, _mm_load_si128(vp++));
1470 n -= sizeof(*vp);
1472 return 1;
1474 sp++;
1475 vp++;
1477 return 0;
1479 #else /* !USE_SSE2 */
1480 int vram_dirty(VGAState *s, int offset, int n)
1482 return cmp_vram(s, offset, n);
1485 void check_sse2(void)
1488 #endif /* !USE_SSE2 */
1490 /*
1491 * graphic modes
1492 */
1493 static void vga_draw_graphic(VGAState *s, int full_update)
1495 int y1, y, update, linesize, y_start, double_scan, mask, depth;
1496 int width, height, shift_control, line_offset, bwidth, ds_depth, bits;
1497 ram_addr_t page0, page1;
1498 int disp_width, multi_scan, multi_run;
1499 uint8_t *d;
1500 uint32_t v, addr1, addr;
1501 vga_draw_line_func *vga_draw_line;
1502 ram_addr_t page_min, page_max;
1504 full_update |= update_basic_params(s);
1506 s->get_resolution(s, &width, &height);
1507 disp_width = width;
1509 shift_control = (s->gr[0x05] >> 5) & 3;
1510 double_scan = (s->cr[0x09] >> 7);
1511 if (shift_control != 1) {
1512 multi_scan = (((s->cr[0x09] & 0x1f) + 1) << double_scan) - 1;
1513 } else {
1514 /* in CGA modes, multi_scan is ignored */
1515 /* XXX: is it correct ? */
1516 multi_scan = double_scan;
1518 multi_run = multi_scan;
1519 if (shift_control != s->shift_control ||
1520 double_scan != s->double_scan) {
1521 full_update = 1;
1522 s->shift_control = shift_control;
1523 s->double_scan = double_scan;
1525 if (shift_control == 1 && (s->sr[0x01] & 8)) {
1526 disp_width <<= 1;
1529 ds_depth = s->ds->depth;
1530 depth = s->get_bpp(s);
1531 if (s->ds->dpy_resize_shared) {
1532 if (s->line_offset != s->last_line_offset ||
1533 disp_width != s->last_width ||
1534 height != s->last_height ||
1535 old_depth != depth) {
1536 dpy_resize_shared(s->ds, disp_width, height, depth, s->line_offset, s->vram_ptr + (s->start_addr * 4));
1537 s->last_scr_width = disp_width;
1538 s->last_scr_height = height;
1539 s->last_width = disp_width;
1540 s->last_height = height;
1541 s->last_line_offset = s->line_offset;
1542 old_depth = depth;
1543 full_update = 1;
1544 } else if (s->ds->shared_buf && (full_update || s->ds->data != s->vram_ptr + (s->start_addr * 4)))
1545 s->ds->dpy_setdata(s->ds, s->vram_ptr + (s->start_addr * 4));
1546 } else if (disp_width != s->last_width ||
1547 height != s->last_height) {
1548 dpy_resize(s->ds, disp_width, height);
1549 s->last_scr_width = disp_width;
1550 s->last_scr_height = height;
1551 s->last_width = disp_width;
1552 s->last_height = height;
1553 full_update = 1;
1556 s->rgb_to_pixel =
1557 rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1559 if (shift_control == 0) {
1560 full_update |= update_palette16(s);
1561 if (s->sr[0x01] & 8) {
1562 v = VGA_DRAW_LINE4D2;
1563 } else {
1564 v = VGA_DRAW_LINE4;
1566 bits = 4;
1567 } else if (shift_control == 1) {
1568 full_update |= update_palette16(s);
1569 if (s->sr[0x01] & 8) {
1570 v = VGA_DRAW_LINE2D2;
1571 } else {
1572 v = VGA_DRAW_LINE2;
1574 bits = 4;
1575 } else {
1576 switch(s->get_bpp(s)) {
1577 default:
1578 case 0:
1579 full_update |= update_palette256(s);
1580 v = VGA_DRAW_LINE8D2;
1581 bits = 4;
1582 break;
1583 case 8:
1584 full_update |= update_palette256(s);
1585 v = VGA_DRAW_LINE8;
1586 bits = 8;
1587 break;
1588 case 15:
1589 v = VGA_DRAW_LINE15;
1590 bits = 16;
1591 break;
1592 case 16:
1593 v = VGA_DRAW_LINE16;
1594 bits = 16;
1595 break;
1596 case 24:
1597 v = VGA_DRAW_LINE24;
1598 bits = 24;
1599 break;
1600 case 32:
1601 v = VGA_DRAW_LINE32;
1602 bits = 32;
1603 break;
1607 vga_draw_line = vga_draw_line_table[v * NB_DEPTHS + get_depth_index(s->ds)];
1608 if (!s->ds->shared_buf && s->cursor_invalidate)
1609 s->cursor_invalidate(s);
1611 line_offset = s->line_offset;
1612 #if 0
1613 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",
1614 width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]);
1615 #endif
1617 y = 0;
1619 if (height - 1 > s->line_compare || multi_run || (s->cr[0x17] & 3) != 3
1620 || !s->lfb_addr) {
1621 /* Tricky things happen, disable dirty bit tracking */
1622 xc_hvm_track_dirty_vram(xc_handle, domid, 0, 0, NULL);
1624 for ( ; y < s->vram_size; y += TARGET_PAGE_SIZE)
1625 if (vram_dirty(s, y, TARGET_PAGE_SIZE))
1626 cpu_physical_memory_set_dirty(s->vram_offset + y);
1627 } else {
1628 /* Tricky things won't have any effect, i.e. we are in the very simple
1629 * (and very usual) case of a linear buffer. */
1630 unsigned long end;
1632 for ( ; y < ((s->start_addr * 4) & TARGET_PAGE_MASK); y += TARGET_PAGE_SIZE)
1633 /* We will not read that anyway. */
1634 cpu_physical_memory_set_dirty(s->vram_offset + y);
1636 if (y < (s->start_addr * 4)) {
1637 /* start address not aligned on a page, track dirtyness by hand. */
1638 if (vram_dirty(s, y, TARGET_PAGE_SIZE))
1639 cpu_physical_memory_set_dirty(s->vram_offset + y);
1640 y += TARGET_PAGE_SIZE;
1643 /* use page table dirty bit tracking for the inner of the LFB */
1644 end = s->start_addr * 4 + height * line_offset;
1646 unsigned long npages = ((end & TARGET_PAGE_MASK) - y) / TARGET_PAGE_SIZE;
1647 const int width = sizeof(unsigned long) * 8;
1648 unsigned long bitmap[(npages + width - 1) / width];
1649 int err;
1651 if (!(err = xc_hvm_track_dirty_vram(xc_handle, domid,
1652 (s->lfb_addr + y) / TARGET_PAGE_SIZE, npages, bitmap))) {
1653 int i, j;
1654 for (i = 0; i < sizeof(bitmap) / sizeof(*bitmap); i++) {
1655 unsigned long map = bitmap[i];
1656 for (j = i * width; map && j < npages; map >>= 1, j++)
1657 if (map & 1)
1658 cpu_physical_memory_set_dirty(s->vram_offset + y
1659 + j * TARGET_PAGE_SIZE);
1661 y += npages * TARGET_PAGE_SIZE;
1662 } else {
1663 /* ENODATA just means we have changed mode and will succeed
1664 * next time */
1665 if (err != -ENODATA)
1666 fprintf(stderr, "track_dirty_vram(%lx, %lx) failed (%d)\n", s->lfb_addr + y, npages, err);
1670 for ( ; y < s->vram_size && y < end; y += TARGET_PAGE_SIZE)
1671 /* failed or end address not aligned on a page, track dirtyness by
1672 * hand. */
1673 if (vram_dirty(s, y, TARGET_PAGE_SIZE))
1674 cpu_physical_memory_set_dirty(s->vram_offset + y);
1676 for ( ; y < s->vram_size; y += TARGET_PAGE_SIZE)
1677 /* We will not read that anyway. */
1678 cpu_physical_memory_set_dirty(s->vram_offset + y);
1681 addr1 = (s->start_addr * 4);
1682 bwidth = (width * bits + 7) / 8;
1683 y_start = -1;
1684 page_min = 0;
1685 page_max = 0;
1686 d = s->ds->data;
1687 linesize = s->ds->linesize;
1688 y1 = 0;
1689 for(y = 0; y < height; y++) {
1690 addr = addr1;
1691 if (!(s->cr[0x17] & 1)) {
1692 int shift;
1693 /* CGA compatibility handling */
1694 shift = 14 + ((s->cr[0x17] >> 6) & 1);
1695 addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
1697 if (!(s->cr[0x17] & 2)) {
1698 addr = (addr & ~0x8000) | ((y1 & 2) << 14);
1700 page0 = s->vram_offset + (addr & TARGET_PAGE_MASK);
1701 page1 = s->vram_offset + ((addr + bwidth - 1) & TARGET_PAGE_MASK);
1702 update = full_update |
1703 cpu_physical_memory_get_dirty(page0, VGA_DIRTY_FLAG) |
1704 cpu_physical_memory_get_dirty(page1, VGA_DIRTY_FLAG);
1705 if ((page1 - page0) > TARGET_PAGE_SIZE) {
1706 /* if wide line, can use another page */
1707 update |= cpu_physical_memory_get_dirty(page0 + TARGET_PAGE_SIZE,
1708 VGA_DIRTY_FLAG);
1710 /* explicit invalidation for the hardware cursor */
1711 update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
1712 if (update) {
1713 if (y_start < 0)
1714 y_start = y;
1715 if (page_min == 0 || page0 < page_min)
1716 page_min = page0;
1717 if (page_max == 0 || page1 > page_max)
1718 page_max = page1;
1719 if (!s->ds->shared_buf) {
1720 vga_draw_line(s, d, s->vram_ptr + addr, width);
1721 if (s->cursor_draw_line)
1722 s->cursor_draw_line(s, d, y);
1724 } else {
1725 if (y_start >= 0) {
1726 /* flush to display */
1727 dpy_update(s->ds, 0, y_start,
1728 disp_width, y - y_start);
1729 y_start = -1;
1732 if (!multi_run) {
1733 mask = (s->cr[0x17] & 3) ^ 3;
1734 if ((y1 & mask) == mask)
1735 addr1 += line_offset;
1736 y1++;
1737 multi_run = multi_scan;
1738 } else {
1739 multi_run--;
1741 /* line compare acts on the displayed lines */
1742 if (y == s->line_compare)
1743 addr1 = 0;
1744 d += linesize;
1746 if (y_start >= 0) {
1747 /* flush to display */
1748 dpy_update(s->ds, 0, y_start,
1749 disp_width, y - y_start);
1751 /* reset modified pages */
1752 if (page_max != -1) {
1753 cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
1754 VGA_DIRTY_FLAG);
1756 memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
1759 static void vga_draw_blank(VGAState *s, int full_update)
1761 int i, w, val;
1762 uint8_t *d;
1764 if (!full_update)
1765 return;
1766 if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
1767 return;
1769 /* Disable dirty bit tracking */
1770 xc_hvm_track_dirty_vram(xc_handle, domid, 0, 0, NULL);
1772 s->rgb_to_pixel =
1773 rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1774 if (s->ds->depth == 8)
1775 val = s->rgb_to_pixel(0, 0, 0);
1776 else
1777 val = 0;
1778 w = s->last_scr_width * ((s->ds->depth + 7) >> 3);
1779 d = s->ds->data;
1780 for(i = 0; i < s->last_scr_height; i++) {
1781 memset(d, val, w);
1782 d += s->ds->linesize;
1784 dpy_update(s->ds, 0, 0,
1785 s->last_scr_width, s->last_scr_height);
1788 #define GMODE_TEXT 0
1789 #define GMODE_GRAPH 1
1790 #define GMODE_BLANK 2
1792 static void vga_update_display(void *opaque)
1794 VGAState *s = (VGAState *)opaque;
1795 int full_update, graphic_mode;
1797 if (s->ds->depth == 0) {
1798 /* nothing to do */
1799 } else {
1800 full_update = 0;
1801 if (!(s->ar_index & 0x20)) {
1802 graphic_mode = GMODE_BLANK;
1803 } else {
1804 graphic_mode = s->gr[6] & 1;
1806 if (graphic_mode != s->graphic_mode) {
1807 s->graphic_mode = graphic_mode;
1808 full_update = 1;
1810 switch(graphic_mode) {
1811 case GMODE_TEXT:
1812 vga_draw_text(s, full_update);
1813 break;
1814 case GMODE_GRAPH:
1815 vga_draw_graphic(s, full_update);
1816 break;
1817 case GMODE_BLANK:
1818 default:
1819 vga_draw_blank(s, full_update);
1820 break;
1825 /* force a full display refresh */
1826 static void vga_invalidate_display(void *opaque)
1828 VGAState *s = (VGAState *)opaque;
1830 s->last_width = -1;
1831 s->last_height = -1;
1834 static void vga_reset(VGAState *s)
1836 memset(s, 0, sizeof(VGAState));
1837 s->graphic_mode = -1; /* force full update */
1840 static CPUReadMemoryFunc *vga_mem_read[3] = {
1841 vga_mem_readb,
1842 vga_mem_readw,
1843 vga_mem_readl,
1844 };
1846 static CPUWriteMemoryFunc *vga_mem_write[3] = {
1847 vga_mem_writeb,
1848 vga_mem_writew,
1849 vga_mem_writel,
1850 };
1852 static void vga_save(QEMUFile *f, void *opaque)
1854 VGAState *s = opaque;
1855 uint32_t vram_size;
1856 #ifdef CONFIG_BOCHS_VBE
1857 int i;
1858 #endif
1860 if (s->pci_dev)
1861 pci_device_save(s->pci_dev, f);
1863 qemu_put_be32s(f, &s->latch);
1864 qemu_put_8s(f, &s->sr_index);
1865 qemu_put_buffer(f, s->sr, 8);
1866 qemu_put_8s(f, &s->gr_index);
1867 qemu_put_buffer(f, s->gr, 16);
1868 qemu_put_8s(f, &s->ar_index);
1869 qemu_put_buffer(f, s->ar, 21);
1870 qemu_put_be32s(f, &s->ar_flip_flop);
1871 qemu_put_8s(f, &s->cr_index);
1872 qemu_put_buffer(f, s->cr, 256);
1873 qemu_put_8s(f, &s->msr);
1874 qemu_put_8s(f, &s->fcr);
1875 qemu_put_8s(f, &s->st00);
1876 qemu_put_8s(f, &s->st01);
1878 qemu_put_8s(f, &s->dac_state);
1879 qemu_put_8s(f, &s->dac_sub_index);
1880 qemu_put_8s(f, &s->dac_read_index);
1881 qemu_put_8s(f, &s->dac_write_index);
1882 qemu_put_buffer(f, s->dac_cache, 3);
1883 qemu_put_buffer(f, s->palette, 768);
1885 qemu_put_be32s(f, &s->bank_offset);
1886 #ifdef CONFIG_BOCHS_VBE
1887 qemu_put_byte(f, 1);
1888 qemu_put_be16s(f, &s->vbe_index);
1889 for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
1890 qemu_put_be16s(f, &s->vbe_regs[i]);
1891 qemu_put_be32s(f, &s->vbe_start_addr);
1892 qemu_put_be32s(f, &s->vbe_line_offset);
1893 qemu_put_be32s(f, &s->vbe_bank_mask);
1894 #else
1895 qemu_put_byte(f, 0);
1896 #endif
1897 vram_size = s->vram_size;
1898 qemu_put_be32s(f, &vram_size);
1899 qemu_put_buffer(f, s->vram_ptr, s->vram_size);
1902 static int vga_load(QEMUFile *f, void *opaque, int version_id)
1904 VGAState *s = opaque;
1905 int is_vbe, ret;
1906 uint32_t vram_size;
1907 #ifdef CONFIG_BOCHS_VBE
1908 int i;
1909 #endif
1911 if (version_id > 3)
1912 return -EINVAL;
1914 if (s->pci_dev && version_id >= 2) {
1915 ret = pci_device_load(s->pci_dev, f);
1916 if (ret < 0)
1917 return ret;
1920 qemu_get_be32s(f, &s->latch);
1921 qemu_get_8s(f, &s->sr_index);
1922 qemu_get_buffer(f, s->sr, 8);
1923 qemu_get_8s(f, &s->gr_index);
1924 qemu_get_buffer(f, s->gr, 16);
1925 qemu_get_8s(f, &s->ar_index);
1926 qemu_get_buffer(f, s->ar, 21);
1927 qemu_get_be32s(f, &s->ar_flip_flop);
1928 qemu_get_8s(f, &s->cr_index);
1929 qemu_get_buffer(f, s->cr, 256);
1930 qemu_get_8s(f, &s->msr);
1931 qemu_get_8s(f, &s->fcr);
1932 qemu_get_8s(f, &s->st00);
1933 qemu_get_8s(f, &s->st01);
1935 qemu_get_8s(f, &s->dac_state);
1936 qemu_get_8s(f, &s->dac_sub_index);
1937 qemu_get_8s(f, &s->dac_read_index);
1938 qemu_get_8s(f, &s->dac_write_index);
1939 qemu_get_buffer(f, s->dac_cache, 3);
1940 qemu_get_buffer(f, s->palette, 768);
1942 qemu_get_be32s(f, &s->bank_offset);
1943 is_vbe = qemu_get_byte(f);
1944 #ifdef CONFIG_BOCHS_VBE
1945 if (!is_vbe)
1946 return -EINVAL;
1947 qemu_get_be16s(f, &s->vbe_index);
1948 for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
1949 qemu_get_be16s(f, &s->vbe_regs[i]);
1950 qemu_get_be32s(f, &s->vbe_start_addr);
1951 qemu_get_be32s(f, &s->vbe_line_offset);
1952 qemu_get_be32s(f, &s->vbe_bank_mask);
1953 #else
1954 if (is_vbe)
1955 return -EINVAL;
1956 #endif
1957 if (version_id >= 3) {
1958 /* people who restore old images may be lucky ... */
1959 qemu_get_be32s(f, &vram_size);
1960 if (vram_size != s->vram_size)
1961 return -EINVAL;
1962 qemu_get_buffer(f, s->vram_ptr, s->vram_size);
1965 /* force refresh */
1966 s->graphic_mode = -1;
1967 return 0;
1970 typedef struct PCIVGAState {
1971 PCIDevice dev;
1972 VGAState vga_state;
1973 } PCIVGAState;
1975 static void vga_map(PCIDevice *pci_dev, int region_num,
1976 uint32_t addr, uint32_t size, int type)
1978 PCIVGAState *d = (PCIVGAState *)pci_dev;
1979 VGAState *s = &d->vga_state;
1980 if (region_num == PCI_ROM_SLOT) {
1981 cpu_register_physical_memory(addr, s->bios_size, s->bios_offset);
1982 } else {
1983 cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
1987 /* do the same job as vgabios before vgabios get ready - yeah */
1988 void vga_bios_init(VGAState *s)
1990 uint8_t palette_model[192] = {
1991 0, 0, 0, 0, 0, 170, 0, 170,
1992 0, 0, 170, 170, 170, 0, 0, 170,
1993 0, 170, 170, 85, 0, 170, 170, 170,
1994 85, 85, 85, 85, 85, 255, 85, 255,
1995 85, 85, 255, 255, 255, 85, 85, 255,
1996 85, 255, 255, 255, 85, 255, 255, 255,
1997 0, 21, 0, 0, 21, 42, 0, 63,
1998 0, 0, 63, 42, 42, 21, 0, 42,
1999 21, 42, 42, 63, 0, 42, 63, 42,
2000 0, 21, 21, 0, 21, 63, 0, 63,
2001 21, 0, 63, 63, 42, 21, 21, 42,
2002 21, 63, 42, 63, 21, 42, 63, 63,
2003 21, 0, 0, 21, 0, 42, 21, 42,
2004 0, 21, 42, 42, 63, 0, 0, 63,
2005 0, 42, 63, 42, 0, 63, 42, 42,
2006 21, 0, 21, 21, 0, 63, 21, 42,
2007 21, 21, 42, 63, 63, 0, 21, 63,
2008 0, 63, 63, 42, 21, 63, 42, 63,
2009 21, 21, 0, 21, 21, 42, 21, 63,
2010 0, 21, 63, 42, 63, 21, 0, 63,
2011 21, 42, 63, 63, 0, 63, 63, 42,
2012 21, 21, 21, 21, 21, 63, 21, 63,
2013 21, 21, 63, 63, 63, 21, 21, 63,
2014 21, 63, 63, 63, 21, 63, 63, 63
2015 };
2017 s->latch = 0;
2019 s->sr_index = 3;
2020 s->sr[0] = 3;
2021 s->sr[1] = 0;
2022 s->sr[2] = 3;
2023 s->sr[3] = 0;
2024 s->sr[4] = 2;
2025 s->sr[5] = 0;
2026 s->sr[6] = 0;
2027 s->sr[7] = 0;
2029 s->gr_index = 5;
2030 s->gr[0] = 0;
2031 s->gr[1] = 0;
2032 s->gr[2] = 0;
2033 s->gr[3] = 0;
2034 s->gr[4] = 0;
2035 s->gr[5] = 16;
2036 s->gr[6] = 14;
2037 s->gr[7] = 15;
2038 s->gr[8] = 255;
2040 /* changed by out 0x03c0 */
2041 s->ar_index = 32;
2042 s->ar[0] = 0;
2043 s->ar[1] = 1;
2044 s->ar[2] = 2;
2045 s->ar[3] = 3;
2046 s->ar[4] = 4;
2047 s->ar[5] = 5;
2048 s->ar[6] = 6;
2049 s->ar[7] = 7;
2050 s->ar[8] = 8;
2051 s->ar[9] = 9;
2052 s->ar[10] = 10;
2053 s->ar[11] = 11;
2054 s->ar[12] = 12;
2055 s->ar[13] = 13;
2056 s->ar[14] = 14;
2057 s->ar[15] = 15;
2058 s->ar[16] = 12;
2059 s->ar[17] = 0;
2060 s->ar[18] = 15;
2061 s->ar[19] = 8;
2062 s->ar[20] = 0;
2064 s->ar_flip_flop = 1;
2066 s->cr_index = 15;
2067 s->cr[0] = 95;
2068 s->cr[1] = 79;
2069 s->cr[2] = 80;
2070 s->cr[3] = 130;
2071 s->cr[4] = 85;
2072 s->cr[5] = 129;
2073 s->cr[6] = 191;
2074 s->cr[7] = 31;
2075 s->cr[8] = 0;
2076 s->cr[9] = 79;
2077 s->cr[10] = 14;
2078 s->cr[11] = 15;
2079 s->cr[12] = 0;
2080 s->cr[13] = 0;
2081 s->cr[14] = 5;
2082 s->cr[15] = 160;
2083 s->cr[16] = 156;
2084 s->cr[17] = 142;
2085 s->cr[18] = 143;
2086 s->cr[19] = 40;
2087 s->cr[20] = 31;
2088 s->cr[21] = 150;
2089 s->cr[22] = 185;
2090 s->cr[23] = 163;
2091 s->cr[24] = 255;
2093 s->msr = 103;
2094 s->fcr = 0;
2095 s->st00 = 0;
2096 s->st01 = 0;
2098 /* dac_* & palette will be initialized by os through out 0x03c8 &
2099 * out 0c03c9(1:3) */
2100 s->dac_state = 0;
2101 s->dac_sub_index = 0;
2102 s->dac_read_index = 0;
2103 s->dac_write_index = 16;
2104 s->dac_cache[0] = 255;
2105 s->dac_cache[1] = 255;
2106 s->dac_cache[2] = 255;
2108 /* palette */
2109 memcpy(s->palette, palette_model, 192);
2111 s->bank_offset = 0;
2112 s->graphic_mode = -1;
2114 /* TODO: add vbe support if enabled */
2117 /* when used on xen environment, the vga_ram_base is not used */
2118 void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base,
2119 unsigned long vga_ram_offset, int vga_ram_size)
2121 int i, j, v, b;
2123 for(i = 0;i < 256; i++) {
2124 v = 0;
2125 for(j = 0; j < 8; j++) {
2126 v |= ((i >> j) & 1) << (j * 4);
2128 expand4[i] = v;
2130 v = 0;
2131 for(j = 0; j < 4; j++) {
2132 v |= ((i >> (2 * j)) & 3) << (j * 4);
2134 expand2[i] = v;
2136 for(i = 0; i < 16; i++) {
2137 v = 0;
2138 for(j = 0; j < 4; j++) {
2139 b = ((i >> j) & 1);
2140 v |= b << (2 * j);
2141 v |= b << (2 * j + 1);
2143 expand4to8[i] = v;
2146 vga_reset(s);
2148 check_sse2();
2149 s->vram_shadow = qemu_malloc(vga_ram_size+TARGET_PAGE_SIZE+1);
2150 if (s->vram_shadow == NULL)
2151 fprintf(stderr, "Cannot allocate %d bytes for VRAM shadow, "
2152 "mouse will be slow\n", vga_ram_size);
2153 s->vram_shadow = (uint8_t *)((long)(s->vram_shadow + TARGET_PAGE_SIZE - 1)
2154 & ~(TARGET_PAGE_SIZE - 1));
2156 /* Video RAM must be 128-bit aligned for SSE optimizations later */
2157 /* and page-aligned for PVFB memory sharing */
2158 s->vram_ptr = s->vram_alloc = qemu_memalign(TARGET_PAGE_SIZE, vga_ram_size);
2160 #ifdef CONFIG_STUBDOM
2161 if (!cirrus_vga_enabled)
2162 xenfb_pv_display_start(s->vram_ptr);
2163 #endif
2165 s->vram_offset = vga_ram_offset;
2166 s->vram_size = vga_ram_size;
2167 s->ds = ds;
2168 ds->palette = s->last_palette;
2169 s->get_bpp = vga_get_bpp;
2170 s->get_offsets = vga_get_offsets;
2171 s->get_resolution = vga_get_resolution;
2172 graphic_console_init(s->ds, vga_update_display, vga_invalidate_display,
2173 vga_screen_dump, s);
2175 vga_bios_init(s);
2178 /* used by both ISA and PCI */
2179 static void vga_init(VGAState *s)
2181 int vga_io_memory;
2183 register_savevm("vga", 0, 3, vga_save, vga_load, s);
2185 register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
2187 register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
2188 register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);
2189 register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);
2190 register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);
2192 register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
2194 register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);
2195 register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);
2196 register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
2197 register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
2198 s->bank_offset = 0;
2200 #ifdef CONFIG_BOCHS_VBE
2201 s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0;
2202 s->vbe_bank_mask = ((s->vram_size >> 16) - 1);
2203 #if defined (TARGET_I386)
2204 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
2205 register_ioport_read(0x1cf, 1, 2, vbe_ioport_read_data, s);
2207 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
2208 register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data, s);
2210 /* old Bochs IO ports */
2211 register_ioport_read(0xff80, 1, 2, vbe_ioport_read_index, s);
2212 register_ioport_read(0xff81, 1, 2, vbe_ioport_read_data, s);
2214 register_ioport_write(0xff80, 1, 2, vbe_ioport_write_index, s);
2215 register_ioport_write(0xff81, 1, 2, vbe_ioport_write_data, s);
2216 #else
2217 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
2218 register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data, s);
2220 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
2221 register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data, s);
2222 #endif
2223 #endif /* CONFIG_BOCHS_VBE */
2225 vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s);
2226 cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
2227 vga_io_memory);
2230 int isa_vga_init(DisplayState *ds, uint8_t *vga_ram_base,
2231 unsigned long vga_ram_offset, int vga_ram_size)
2233 VGAState *s;
2235 s = qemu_mallocz(sizeof(VGAState));
2236 if (!s)
2237 return -1;
2239 vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size);
2240 vga_init(s);
2242 #ifdef CONFIG_BOCHS_VBE
2243 /* XXX: use optimized standard vga accesses */
2244 cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
2245 vga_ram_size, vga_ram_offset);
2246 #endif
2247 return 0;
2250 int pci_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base,
2251 unsigned long vga_ram_offset, int vga_ram_size,
2252 unsigned long vga_bios_offset, int vga_bios_size)
2254 PCIVGAState *d;
2255 VGAState *s;
2256 uint8_t *pci_conf;
2258 d = (PCIVGAState *)pci_register_device(bus, "VGA",
2259 sizeof(PCIVGAState),
2260 -1, NULL, NULL);
2261 if (!d)
2262 return -1;
2263 s = &d->vga_state;
2265 vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size);
2266 vga_init(s);
2267 s->pci_dev = &d->dev;
2269 pci_conf = d->dev.config;
2270 pci_conf[0x00] = 0x34; // dummy VGA (same as Bochs ID)
2271 pci_conf[0x01] = 0x12;
2272 pci_conf[0x02] = 0x11;
2273 pci_conf[0x03] = 0x11;
2274 pci_conf[0x0a] = 0x00; // VGA controller
2275 pci_conf[0x0b] = 0x03;
2276 pci_conf[0x0e] = 0x00; // header_type
2278 /* XXX: vga_ram_size must be a power of two */
2279 pci_register_io_region(&d->dev, 0, vga_ram_size,
2280 PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
2281 if (vga_bios_size != 0) {
2282 unsigned int bios_total_size;
2283 s->bios_offset = vga_bios_offset;
2284 s->bios_size = vga_bios_size;
2285 /* must be a power of two */
2286 bios_total_size = 1;
2287 while (bios_total_size < vga_bios_size)
2288 bios_total_size <<= 1;
2289 pci_register_io_region(&d->dev, PCI_ROM_SLOT, bios_total_size,
2290 PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
2292 return 0;
2295 void *vga_update_vram(VGAState *s, void *vga_ram_base, int vga_ram_size)
2297 uint8_t *old_pointer;
2299 if (s->vram_size != vga_ram_size) {
2300 fprintf(stderr, "No support to change vga_ram_size\n");
2301 return NULL;
2304 if (!vga_ram_base) {
2305 vga_ram_base = qemu_memalign(TARGET_PAGE_SIZE, vga_ram_size + TARGET_PAGE_SIZE + 1);
2306 if (!vga_ram_base) {
2307 fprintf(stderr, "reallocate error\n");
2308 return NULL;
2312 /* XXX lock needed? */
2313 old_pointer = s->vram_alloc;
2314 s->vram_alloc = vga_ram_base;
2315 vga_ram_base = (uint8_t *)((long)(vga_ram_base + 15) & ~15L);
2316 memcpy(vga_ram_base, s->vram_ptr, vga_ram_size);
2317 s->vram_ptr = vga_ram_base;
2319 return old_pointer;
2322 /********************************************************/
2323 /* vga screen dump */
2325 static int vga_save_w, vga_save_h;
2327 static void vga_save_dpy_update(DisplayState *s,
2328 int x, int y, int w, int h)
2332 static void vga_save_dpy_resize(DisplayState *s, int w, int h)
2334 s->linesize = w * 4;
2335 s->data = qemu_malloc(h * s->linesize);
2336 vga_save_w = w;
2337 vga_save_h = h;
2340 static void vga_save_dpy_refresh(DisplayState *s)
2344 static int ppm_save(const char *filename, uint8_t *data,
2345 int w, int h, int linesize)
2347 FILE *f;
2348 uint8_t *d, *d1;
2349 unsigned int v;
2350 int y, x;
2352 f = fopen(filename, "wb");
2353 if (!f)
2354 return -1;
2355 fprintf(f, "P6\n%d %d\n%d\n",
2356 w, h, 255);
2357 d1 = data;
2358 for(y = 0; y < h; y++) {
2359 d = d1;
2360 for(x = 0; x < w; x++) {
2361 v = *(uint32_t *)d;
2362 fputc((v >> 16) & 0xff, f);
2363 fputc((v >> 8) & 0xff, f);
2364 fputc((v) & 0xff, f);
2365 d += 4;
2367 d1 += linesize;
2369 fclose(f);
2370 return 0;
2373 /* save the vga display in a PPM image even if no display is
2374 available */
2375 static void vga_screen_dump(void *opaque, const char *filename)
2377 VGAState *s = (VGAState *)opaque;
2378 DisplayState *saved_ds, ds1, *ds = &ds1;
2380 /* XXX: this is a little hackish */
2381 vga_invalidate_display(s);
2382 saved_ds = s->ds;
2384 memset(ds, 0, sizeof(DisplayState));
2385 ds->dpy_update = vga_save_dpy_update;
2386 ds->dpy_resize = vga_save_dpy_resize;
2387 ds->dpy_refresh = vga_save_dpy_refresh;
2388 ds->depth = 32;
2390 s->ds = ds;
2391 s->graphic_mode = -1;
2392 vga_update_display(s);
2394 if (ds->data) {
2395 ppm_save(filename, ds->data, vga_save_w, vga_save_h,
2396 s->ds->linesize);
2397 qemu_free(ds->data);
2399 s->ds = saved_ds;