ia64/xen-unstable

view tools/ioemu/hw/vga.c @ 9662:c89d62e7015a

Fix push/pop usage in tools/ioemu for x86/64.

Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Mon Apr 10 17:25:42 2006 +0100 (2006-04-10)
parents bdec77028194
children 7a41b35d73f4
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_S3
32 //#define DEBUG_BOCHS_VBE
34 /* S3 VGA is deprecated - another graphic card will be emulated */
35 //#define CONFIG_S3VGA
37 /* force some bits to zero */
38 const uint8_t sr_mask[8] = {
39 (uint8_t)~0xfc,
40 (uint8_t)~0xc2,
41 (uint8_t)~0xf0,
42 (uint8_t)~0xc0,
43 (uint8_t)~0xf1,
44 (uint8_t)~0xff,
45 (uint8_t)~0xff,
46 (uint8_t)~0x00,
47 };
49 const uint8_t gr_mask[16] = {
50 (uint8_t)~0xf0, /* 0x00 */
51 (uint8_t)~0xf0, /* 0x01 */
52 (uint8_t)~0xf0, /* 0x02 */
53 (uint8_t)~0xe0, /* 0x03 */
54 (uint8_t)~0xfc, /* 0x04 */
55 (uint8_t)~0x84, /* 0x05 */
56 (uint8_t)~0xf0, /* 0x06 */
57 (uint8_t)~0xf0, /* 0x07 */
58 (uint8_t)~0x00, /* 0x08 */
59 (uint8_t)~0xff, /* 0x09 */
60 (uint8_t)~0xff, /* 0x0a */
61 (uint8_t)~0xff, /* 0x0b */
62 (uint8_t)~0xff, /* 0x0c */
63 (uint8_t)~0xff, /* 0x0d */
64 (uint8_t)~0xff, /* 0x0e */
65 (uint8_t)~0xff, /* 0x0f */
66 };
68 #define cbswap_32(__x) \
69 ((uint32_t)( \
70 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
71 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
72 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
73 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
75 #ifdef WORDS_BIGENDIAN
76 #define PAT(x) cbswap_32(x)
77 #else
78 #define PAT(x) (x)
79 #endif
81 #ifdef WORDS_BIGENDIAN
82 #define BIG 1
83 #else
84 #define BIG 0
85 #endif
87 #ifdef WORDS_BIGENDIAN
88 #define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
89 #else
90 #define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
91 #endif
93 static const uint32_t mask16[16] = {
94 PAT(0x00000000),
95 PAT(0x000000ff),
96 PAT(0x0000ff00),
97 PAT(0x0000ffff),
98 PAT(0x00ff0000),
99 PAT(0x00ff00ff),
100 PAT(0x00ffff00),
101 PAT(0x00ffffff),
102 PAT(0xff000000),
103 PAT(0xff0000ff),
104 PAT(0xff00ff00),
105 PAT(0xff00ffff),
106 PAT(0xffff0000),
107 PAT(0xffff00ff),
108 PAT(0xffffff00),
109 PAT(0xffffffff),
110 };
112 #undef PAT
114 #ifdef WORDS_BIGENDIAN
115 #define PAT(x) (x)
116 #else
117 #define PAT(x) cbswap_32(x)
118 #endif
120 static const uint32_t dmask16[16] = {
121 PAT(0x00000000),
122 PAT(0x000000ff),
123 PAT(0x0000ff00),
124 PAT(0x0000ffff),
125 PAT(0x00ff0000),
126 PAT(0x00ff00ff),
127 PAT(0x00ffff00),
128 PAT(0x00ffffff),
129 PAT(0xff000000),
130 PAT(0xff0000ff),
131 PAT(0xff00ff00),
132 PAT(0xff00ffff),
133 PAT(0xffff0000),
134 PAT(0xffff00ff),
135 PAT(0xffffff00),
136 PAT(0xffffffff),
137 };
139 static const uint32_t dmask4[4] = {
140 PAT(0x00000000),
141 PAT(0x0000ffff),
142 PAT(0xffff0000),
143 PAT(0xffffffff),
144 };
146 static uint32_t expand4[256];
147 static uint16_t expand2[256];
148 static uint8_t expand4to8[16];
150 VGAState *vga_state;
151 int vga_io_memory;
153 static uint32_t vga_ioport_read(void *opaque, uint32_t addr)
154 {
155 VGAState *s = opaque;
156 int val, index;
158 /* check port range access depending on color/monochrome mode */
159 if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
160 (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION))) {
161 val = 0xff;
162 } else {
163 switch(addr) {
164 case 0x3c0:
165 if (s->ar_flip_flop == 0) {
166 val = s->ar_index;
167 } else {
168 val = 0;
169 }
170 break;
171 case 0x3c1:
172 index = s->ar_index & 0x1f;
173 if (index < 21)
174 val = s->ar[index];
175 else
176 val = 0;
177 break;
178 case 0x3c2:
179 val = s->st00;
180 break;
181 case 0x3c4:
182 val = s->sr_index;
183 break;
184 case 0x3c5:
185 val = s->sr[s->sr_index];
186 #ifdef DEBUG_VGA_REG
187 printf("vga: read SR%x = 0x%02x\n", s->sr_index, val);
188 #endif
189 break;
190 case 0x3c7:
191 val = s->dac_state;
192 break;
193 case 0x3c8:
194 val = s->dac_write_index;
195 break;
196 case 0x3c9:
197 val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
198 if (++s->dac_sub_index == 3) {
199 s->dac_sub_index = 0;
200 s->dac_read_index++;
201 }
202 break;
203 case 0x3ca:
204 val = s->fcr;
205 break;
206 case 0x3cc:
207 val = s->msr;
208 break;
209 case 0x3ce:
210 val = s->gr_index;
211 break;
212 case 0x3cf:
213 val = s->gr[s->gr_index];
214 #ifdef DEBUG_VGA_REG
215 printf("vga: read GR%x = 0x%02x\n", s->gr_index, val);
216 #endif
217 break;
218 case 0x3b4:
219 case 0x3d4:
220 val = s->cr_index;
221 break;
222 case 0x3b5:
223 case 0x3d5:
224 val = s->cr[s->cr_index];
225 #ifdef DEBUG_VGA_REG
226 printf("vga: read CR%x = 0x%02x\n", s->cr_index, val);
227 #endif
228 #ifdef DEBUG_S3
229 if (s->cr_index >= 0x20)
230 printf("S3: CR read index=0x%x val=0x%x\n",
231 s->cr_index, val);
232 #endif
233 break;
234 case 0x3ba:
235 case 0x3da:
236 /* just toggle to fool polling */
237 s->st01 ^= ST01_V_RETRACE | ST01_DISP_ENABLE;
238 val = s->st01;
239 s->ar_flip_flop = 0;
240 break;
241 default:
242 val = 0x00;
243 break;
244 }
245 }
246 #if defined(DEBUG_VGA)
247 printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
248 #endif
249 return val;
250 }
252 static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
253 {
254 VGAState *s = opaque;
255 int index;
257 /* check port range access depending on color/monochrome mode */
258 if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
259 (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION)))
260 return;
262 #ifdef DEBUG_VGA
263 printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
264 #endif
266 switch(addr) {
267 case 0x3c0:
268 if (s->ar_flip_flop == 0) {
269 val &= 0x3f;
270 s->ar_index = val;
271 } else {
272 index = s->ar_index & 0x1f;
273 switch(index) {
274 case 0x00 ... 0x0f:
275 s->ar[index] = val & 0x3f;
276 break;
277 case 0x10:
278 s->ar[index] = val & ~0x10;
279 break;
280 case 0x11:
281 s->ar[index] = val;
282 break;
283 case 0x12:
284 s->ar[index] = val & ~0xc0;
285 break;
286 case 0x13:
287 s->ar[index] = val & ~0xf0;
288 break;
289 case 0x14:
290 s->ar[index] = val & ~0xf0;
291 break;
292 default:
293 break;
294 }
295 }
296 s->ar_flip_flop ^= 1;
297 break;
298 case 0x3c2:
299 s->msr = val & ~0x10;
300 break;
301 case 0x3c4:
302 s->sr_index = val & 7;
303 break;
304 case 0x3c5:
305 #ifdef DEBUG_VGA_REG
306 printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
307 #endif
308 s->sr[s->sr_index] = val & sr_mask[s->sr_index];
309 break;
310 case 0x3c7:
311 s->dac_read_index = val;
312 s->dac_sub_index = 0;
313 s->dac_state = 3;
314 break;
315 case 0x3c8:
316 s->dac_write_index = val;
317 s->dac_sub_index = 0;
318 s->dac_state = 0;
319 break;
320 case 0x3c9:
321 s->dac_cache[s->dac_sub_index] = val;
322 if (++s->dac_sub_index == 3) {
323 memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
324 s->dac_sub_index = 0;
325 s->dac_write_index++;
326 }
327 break;
328 case 0x3ce:
329 s->gr_index = val & 0x0f;
330 break;
331 case 0x3cf:
332 #ifdef DEBUG_VGA_REG
333 printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
334 #endif
335 s->gr[s->gr_index] = val & gr_mask[s->gr_index];
336 break;
337 case 0x3b4:
338 case 0x3d4:
339 s->cr_index = val;
340 break;
341 case 0x3b5:
342 case 0x3d5:
343 #ifdef DEBUG_VGA_REG
344 printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
345 #endif
346 /* handle CR0-7 protection */
347 if ((s->cr[0x11] & 0x80) && s->cr_index <= 7) {
348 /* can always write bit 4 of CR7 */
349 if (s->cr_index == 7)
350 s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
351 return;
352 }
353 switch(s->cr_index) {
354 case 0x01: /* horizontal display end */
355 case 0x07:
356 case 0x09:
357 case 0x0c:
358 case 0x0d:
359 case 0x12: /* veritcal display end */
360 s->cr[s->cr_index] = val;
361 break;
363 #ifdef CONFIG_S3VGA
364 /* S3 registers */
365 case 0x2d:
366 case 0x2e:
367 case 0x2f:
368 case 0x30:
369 /* chip ID, cannot write */
370 break;
371 case 0x31:
372 /* update start address */
373 {
374 int v;
375 s->cr[s->cr_index] = val;
376 v = (val >> 4) & 3;
377 s->cr[0x69] = (s->cr[69] & ~0x03) | v;
378 }
379 break;
380 case 0x51:
381 /* update start address */
382 {
383 int v;
384 s->cr[s->cr_index] = val;
385 v = val & 3;
386 s->cr[0x69] = (s->cr[69] & ~0x0c) | (v << 2);
387 }
388 break;
389 #endif
390 default:
391 s->cr[s->cr_index] = val;
392 break;
393 }
394 #ifdef DEBUG_S3
395 if (s->cr_index >= 0x20)
396 printf("S3: CR write index=0x%x val=0x%x\n",
397 s->cr_index, val);
398 #endif
399 break;
400 case 0x3ba:
401 case 0x3da:
402 s->fcr = val & 0x10;
403 break;
404 }
405 }
407 #ifdef CONFIG_BOCHS_VBE
408 static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
409 {
410 VGAState *s = opaque;
411 uint32_t val;
412 val = s->vbe_index;
413 return val;
414 }
416 static uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr)
417 {
418 VGAState *s = opaque;
419 uint32_t val;
421 if (s->vbe_index <= VBE_DISPI_INDEX_NB)
422 val = s->vbe_regs[s->vbe_index];
423 else
424 val = 0;
425 #ifdef DEBUG_BOCHS_VBE
426 printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val);
427 #endif
428 return val;
429 }
431 static void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val)
432 {
433 VGAState *s = opaque;
434 s->vbe_index = val;
435 }
437 static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
438 {
439 VGAState *s = opaque;
441 if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
442 #ifdef DEBUG_BOCHS_VBE
443 printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val);
444 #endif
445 switch(s->vbe_index) {
446 case VBE_DISPI_INDEX_ID:
447 if (val == VBE_DISPI_ID0 ||
448 val == VBE_DISPI_ID1 ||
449 val == VBE_DISPI_ID2) {
450 s->vbe_regs[s->vbe_index] = val;
451 }
452 break;
453 case VBE_DISPI_INDEX_XRES:
454 if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) {
455 s->vbe_regs[s->vbe_index] = val;
456 }
457 break;
458 case VBE_DISPI_INDEX_YRES:
459 if (val <= VBE_DISPI_MAX_YRES) {
460 s->vbe_regs[s->vbe_index] = val;
461 }
462 break;
463 case VBE_DISPI_INDEX_BPP:
464 if (val == 0)
465 val = 8;
466 if (val == 4 || val == 8 || val == 15 ||
467 val == 16 || val == 24 || val == 32) {
468 s->vbe_regs[s->vbe_index] = val;
469 }
470 break;
471 case VBE_DISPI_INDEX_BANK:
472 val &= s->vbe_bank_mask;
473 s->vbe_regs[s->vbe_index] = val;
474 s->bank_offset = (val << 16);
475 break;
476 case VBE_DISPI_INDEX_ENABLE:
477 if (val & VBE_DISPI_ENABLED) {
478 int h, shift_control;
480 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] =
481 s->vbe_regs[VBE_DISPI_INDEX_XRES];
482 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] =
483 s->vbe_regs[VBE_DISPI_INDEX_YRES];
484 s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
485 s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
487 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
488 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1;
489 else
490 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] *
491 ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
492 s->vbe_start_addr = 0;
494 /* clear the screen (should be done in BIOS) */
495 if (!(val & VBE_DISPI_NOCLEARMEM)) {
496 memset(s->vram_ptr, 0,
497 s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
498 }
500 /* we initialize the VGA graphic mode (should be done
501 in BIOS) */
502 s->gr[0x06] = (s->gr[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
503 s->cr[0x17] |= 3; /* no CGA modes */
504 s->cr[0x13] = s->vbe_line_offset >> 3;
505 /* width */
506 s->cr[0x01] = (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
507 /* height */
508 h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
509 s->cr[0x12] = h;
510 s->cr[0x07] = (s->cr[0x07] & ~0x42) |
511 ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
512 /* line compare to 1023 */
513 s->cr[0x18] = 0xff;
514 s->cr[0x07] |= 0x10;
515 s->cr[0x09] |= 0x40;
517 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
518 shift_control = 0;
519 s->sr[0x01] &= ~8; /* no double line */
520 } else {
521 shift_control = 2;
522 s->sr[4] |= 0x08; /* set chain 4 mode */
523 s->sr[2] |= 0x0f; /* activate all planes */
524 }
525 s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5);
526 s->cr[0x09] &= ~0x9f; /* no double scan */
527 } else {
528 /* XXX: the bios should do that */
529 s->bank_offset = 0;
530 }
531 s->vbe_regs[s->vbe_index] = val;
532 break;
533 case VBE_DISPI_INDEX_VIRT_WIDTH:
534 {
535 int w, h, line_offset;
537 if (val < s->vbe_regs[VBE_DISPI_INDEX_XRES])
538 return;
539 w = val;
540 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
541 line_offset = w >> 1;
542 else
543 line_offset = w * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
544 h = s->vram_size / line_offset;
545 /* XXX: support weird bochs semantics ? */
546 if (h < s->vbe_regs[VBE_DISPI_INDEX_YRES])
547 return;
548 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = w;
549 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h;
550 s->vbe_line_offset = line_offset;
551 }
552 break;
553 case VBE_DISPI_INDEX_X_OFFSET:
554 case VBE_DISPI_INDEX_Y_OFFSET:
555 {
556 int x;
557 s->vbe_regs[s->vbe_index] = val;
558 s->vbe_start_addr = s->vbe_line_offset * s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET];
559 x = s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET];
560 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
561 s->vbe_start_addr += x >> 1;
562 else
563 s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
564 s->vbe_start_addr >>= 2;
565 }
566 break;
567 default:
568 break;
569 }
570 }
571 }
572 #endif
574 extern FILE *logfile;
575 /* called for accesses between 0xa0000 and 0xc0000 */
576 uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr)
577 {
578 VGAState *s = opaque;
579 int memory_map_mode, plane;
580 uint32_t ret;
582 /* convert to VGA memory offset */
583 memory_map_mode = (s->gr[6] >> 2) & 3;
584 addr &= 0x1ffff;
585 switch(memory_map_mode) {
586 case 0:
587 break;
588 case 1:
589 if (addr >= 0x10000)
590 return 0xff;
591 addr += s->bank_offset;
592 break;
593 case 2:
594 addr -= 0x10000;
595 if (addr >= 0x8000)
596 return 0xff;
597 break;
598 default:
599 case 3:
600 addr -= 0x18000;
601 if (addr >= 0x8000)
602 return 0xff;
603 break;
604 }
606 if (s->sr[4] & 0x08) {
607 /* chain 4 mode : simplest access */
608 ret = s->vram_ptr[addr];
609 } else if (s->gr[5] & 0x10) {
610 /* odd/even mode (aka text mode mapping) */
611 plane = (s->gr[4] & 2) | (addr & 1);
612 ret = s->vram_ptr[((addr & ~1) << 1) | plane];
613 } else {
614 /* standard VGA latched access */
615 s->latch = ((uint32_t *)s->vram_ptr)[addr];
617 if (!(s->gr[5] & 0x08)) {
618 /* read mode 0 */
619 plane = s->gr[4];
620 ret = GET_PLANE(s->latch, plane);
621 } else {
622 /* read mode 1 */
623 ret = (s->latch ^ mask16[s->gr[2]]) & mask16[s->gr[7]];
624 ret |= ret >> 16;
625 ret |= ret >> 8;
626 ret = (~ret) & 0xff;
627 }
628 }
629 return ret;
630 }
632 static uint32_t vga_mem_readw(void *opaque, target_phys_addr_t addr)
633 {
634 uint32_t v;
635 #ifdef TARGET_WORDS_BIGENDIAN
636 v = vga_mem_readb(opaque, addr) << 8;
637 v |= vga_mem_readb(opaque, addr + 1);
638 #else
639 v = vga_mem_readb(opaque, addr);
640 v |= vga_mem_readb(opaque, addr + 1) << 8;
641 #endif
642 return v;
643 }
645 static uint32_t vga_mem_readl(void *opaque, target_phys_addr_t addr)
646 {
647 uint32_t v;
648 #ifdef TARGET_WORDS_BIGENDIAN
649 v = vga_mem_readb(opaque, addr) << 24;
650 v |= vga_mem_readb(opaque, addr + 1) << 16;
651 v |= vga_mem_readb(opaque, addr + 2) << 8;
652 v |= vga_mem_readb(opaque, addr + 3);
653 #else
654 v = vga_mem_readb(opaque, addr);
655 v |= vga_mem_readb(opaque, addr + 1) << 8;
656 v |= vga_mem_readb(opaque, addr + 2) << 16;
657 v |= vga_mem_readb(opaque, addr + 3) << 24;
658 #endif
659 return v;
660 }
662 /* called for accesses between 0xa0000 and 0xc0000 */
663 void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
664 {
665 VGAState *s = opaque;
666 int memory_map_mode, plane, write_mode, b, func_select, mask;
667 uint32_t write_mask, bit_mask, set_mask;
669 #ifdef DEBUG_VGA_MEM
670 printf("vga: [0x%x] = 0x%02x\n", addr, val);
671 #endif
672 /* convert to VGA memory offset */
673 memory_map_mode = (s->gr[6] >> 2) & 3;
674 addr &= 0x1ffff;
675 switch(memory_map_mode) {
676 case 0:
677 break;
678 case 1:
679 if (addr >= 0x10000)
680 return;
681 addr += s->bank_offset;
682 break;
683 case 2:
684 addr -= 0x10000;
685 if (addr >= 0x8000)
686 return;
687 break;
688 default:
689 case 3:
690 addr -= 0x18000;
691 if (addr >= 0x8000)
692 return;
693 break;
694 }
696 if (s->sr[4] & 0x08) {
697 /* chain 4 mode : simplest access */
698 plane = addr & 3;
699 mask = (1 << plane);
700 if (s->sr[2] & mask) {
701 s->vram_ptr[addr] = val;
702 #ifdef DEBUG_VGA_MEM
703 printf("vga: chain4: [0x%x]\n", addr);
704 #endif
705 s->plane_updated |= mask; /* only used to detect font change */
706 cpu_physical_memory_set_dirty(s->vram_offset + addr);
707 }
708 } else if (s->gr[5] & 0x10) {
709 /* odd/even mode (aka text mode mapping) */
710 plane = (s->gr[4] & 2) | (addr & 1);
711 mask = (1 << plane);
712 if (s->sr[2] & mask) {
713 addr = ((addr & ~1) << 1) | plane;
714 s->vram_ptr[addr] = val;
715 #ifdef DEBUG_VGA_MEM
716 printf("vga: odd/even: [0x%x]\n", addr);
717 #endif
718 s->plane_updated |= mask; /* only used to detect font change */
719 cpu_physical_memory_set_dirty(s->vram_offset + addr);
720 }
721 } else {
722 /* standard VGA latched access */
723 write_mode = s->gr[5] & 3;
724 switch(write_mode) {
725 default:
726 case 0:
727 /* rotate */
728 b = s->gr[3] & 7;
729 val = ((val >> b) | (val << (8 - b))) & 0xff;
730 val |= val << 8;
731 val |= val << 16;
733 /* apply set/reset mask */
734 set_mask = mask16[s->gr[1]];
735 val = (val & ~set_mask) | (mask16[s->gr[0]] & set_mask);
736 bit_mask = s->gr[8];
737 break;
738 case 1:
739 val = s->latch;
740 goto do_write;
741 case 2:
742 val = mask16[val & 0x0f];
743 bit_mask = s->gr[8];
744 break;
745 case 3:
746 /* rotate */
747 b = s->gr[3] & 7;
748 val = (val >> b) | (val << (8 - b));
750 bit_mask = s->gr[8] & val;
751 val = mask16[s->gr[0]];
752 break;
753 }
755 /* apply logical operation */
756 func_select = s->gr[3] >> 3;
757 switch(func_select) {
758 case 0:
759 default:
760 /* nothing to do */
761 break;
762 case 1:
763 /* and */
764 val &= s->latch;
765 break;
766 case 2:
767 /* or */
768 val |= s->latch;
769 break;
770 case 3:
771 /* xor */
772 val ^= s->latch;
773 break;
774 }
776 /* apply bit mask */
777 bit_mask |= bit_mask << 8;
778 bit_mask |= bit_mask << 16;
779 val = (val & bit_mask) | (s->latch & ~bit_mask);
781 do_write:
782 /* mask data according to sr[2] */
783 mask = s->sr[2];
784 s->plane_updated |= mask; /* only used to detect font change */
785 write_mask = mask16[mask];
786 ((uint32_t *)s->vram_ptr)[addr] =
787 (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
788 (val & write_mask);
789 #ifdef DEBUG_VGA_MEM
790 printf("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n",
791 addr * 4, write_mask, val);
792 #endif
793 cpu_physical_memory_set_dirty(s->vram_offset + (addr << 2));
794 }
795 }
797 static void vga_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
798 {
799 #ifdef TARGET_WORDS_BIGENDIAN
800 vga_mem_writeb(opaque, addr, (val >> 8) & 0xff);
801 vga_mem_writeb(opaque, addr + 1, val & 0xff);
802 #else
803 vga_mem_writeb(opaque, addr, val & 0xff);
804 vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
805 #endif
806 }
808 static void vga_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
809 {
810 #ifdef TARGET_WORDS_BIGENDIAN
811 vga_mem_writeb(opaque, addr, (val >> 24) & 0xff);
812 vga_mem_writeb(opaque, addr + 1, (val >> 16) & 0xff);
813 vga_mem_writeb(opaque, addr + 2, (val >> 8) & 0xff);
814 vga_mem_writeb(opaque, addr + 3, val & 0xff);
815 #else
816 vga_mem_writeb(opaque, addr, val & 0xff);
817 vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
818 vga_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff);
819 vga_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff);
820 #endif
821 }
823 typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
824 const uint8_t *font_ptr, int h,
825 uint32_t fgcol, uint32_t bgcol);
826 typedef void vga_draw_glyph9_func(uint8_t *d, int linesize,
827 const uint8_t *font_ptr, int h,
828 uint32_t fgcol, uint32_t bgcol, int dup9);
829 typedef void vga_draw_line_func(VGAState *s1, uint8_t *d,
830 const uint8_t *s, int width);
832 static inline unsigned int rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b)
833 {
834 return ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6);
835 }
837 static inline unsigned int rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b)
838 {
839 return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
840 }
842 static inline unsigned int rgb_to_pixel16(unsigned int r, unsigned int g, unsigned b)
843 {
844 return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
845 }
847 static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b)
848 {
849 return (r << 16) | (g << 8) | b;
850 }
852 #define DEPTH 8
853 #include "vga_template.h"
855 #define DEPTH 15
856 #include "vga_template.h"
858 #define DEPTH 16
859 #include "vga_template.h"
861 #define DEPTH 32
862 #include "vga_template.h"
864 static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
865 {
866 unsigned int col;
867 col = rgb_to_pixel8(r, g, b);
868 col |= col << 8;
869 col |= col << 16;
870 return col;
871 }
873 static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b)
874 {
875 unsigned int col;
876 col = rgb_to_pixel15(r, g, b);
877 col |= col << 16;
878 return col;
879 }
881 static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
882 {
883 unsigned int col;
884 col = rgb_to_pixel16(r, g, b);
885 col |= col << 16;
886 return col;
887 }
889 static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
890 {
891 unsigned int col;
892 col = rgb_to_pixel32(r, g, b);
893 return col;
894 }
896 /* return true if the palette was modified */
897 static int update_palette16(VGAState *s)
898 {
899 int full_update, i;
900 uint32_t v, col, *palette;
902 full_update = 0;
903 palette = s->last_palette;
904 for(i = 0; i < 16; i++) {
905 v = s->ar[i];
906 if (s->ar[0x10] & 0x80)
907 v = ((s->ar[0x14] & 0xf) << 4) | (v & 0xf);
908 else
909 v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f);
910 v = v * 3;
911 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
912 c6_to_8(s->palette[v + 1]),
913 c6_to_8(s->palette[v + 2]));
914 if (col != palette[i]) {
915 full_update = 1;
916 palette[i] = col;
917 }
918 }
919 return full_update;
920 }
922 /* return true if the palette was modified */
923 static int update_palette256(VGAState *s)
924 {
925 int full_update, i;
926 uint32_t v, col, *palette;
928 full_update = 0;
929 palette = s->last_palette;
930 v = 0;
931 for(i = 0; i < 256; i++) {
932 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
933 c6_to_8(s->palette[v + 1]),
934 c6_to_8(s->palette[v + 2]));
935 if (col != palette[i]) {
936 full_update = 1;
937 palette[i] = col;
938 }
939 v += 3;
940 }
941 return full_update;
942 }
944 static void vga_get_offsets(VGAState *s,
945 uint32_t *pline_offset,
946 uint32_t *pstart_addr)
947 {
948 uint32_t start_addr, line_offset;
949 #ifdef CONFIG_BOCHS_VBE
950 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
951 line_offset = s->vbe_line_offset;
952 start_addr = s->vbe_start_addr;
953 } else
954 #endif
955 {
956 /* compute line_offset in bytes */
957 line_offset = s->cr[0x13];
958 #ifdef CONFIG_S3VGA
959 {
960 uinr32_t v;
961 v = (s->cr[0x51] >> 4) & 3; /* S3 extension */
962 if (v == 0)
963 v = (s->cr[0x43] >> 2) & 1; /* S3 extension */
964 line_offset |= (v << 8);
965 }
966 #endif
967 line_offset <<= 3;
969 /* starting address */
970 start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8);
971 #ifdef CONFIG_S3VGA
972 start_addr |= (s->cr[0x69] & 0x1f) << 16; /* S3 extension */
973 #endif
974 }
975 *pline_offset = line_offset;
976 *pstart_addr = start_addr;
977 }
979 /* update start_addr and line_offset. Return TRUE if modified */
980 static int update_basic_params(VGAState *s)
981 {
982 int full_update;
983 uint32_t start_addr, line_offset, line_compare;
985 full_update = 0;
987 s->get_offsets(s, &line_offset, &start_addr);
988 /* line compare */
989 line_compare = s->cr[0x18] |
990 ((s->cr[0x07] & 0x10) << 4) |
991 ((s->cr[0x09] & 0x40) << 3);
993 if (line_offset != s->line_offset ||
994 start_addr != s->start_addr ||
995 line_compare != s->line_compare) {
996 s->line_offset = line_offset;
997 s->start_addr = start_addr;
998 s->line_compare = line_compare;
999 full_update = 1;
1001 return full_update;
1004 static inline int get_depth_index(int depth)
1006 switch(depth) {
1007 default:
1008 case 8:
1009 return 0;
1010 case 15:
1011 return 1;
1012 case 16:
1013 return 2;
1014 case 32:
1015 return 3;
1019 static vga_draw_glyph8_func *vga_draw_glyph8_table[4] = {
1020 vga_draw_glyph8_8,
1021 vga_draw_glyph8_16,
1022 vga_draw_glyph8_16,
1023 vga_draw_glyph8_32,
1024 };
1026 static vga_draw_glyph8_func *vga_draw_glyph16_table[4] = {
1027 vga_draw_glyph16_8,
1028 vga_draw_glyph16_16,
1029 vga_draw_glyph16_16,
1030 vga_draw_glyph16_32,
1031 };
1033 static vga_draw_glyph9_func *vga_draw_glyph9_table[4] = {
1034 vga_draw_glyph9_8,
1035 vga_draw_glyph9_16,
1036 vga_draw_glyph9_16,
1037 vga_draw_glyph9_32,
1038 };
1040 static const uint8_t cursor_glyph[32 * 4] = {
1041 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1042 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1043 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1044 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1045 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
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 };
1059 /*
1060 * Text mode update
1061 * Missing:
1062 * - double scan
1063 * - double width
1064 * - underline
1065 * - flashing
1066 */
1067 static void vga_draw_text(VGAState *s, int full_update)
1069 int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
1070 int cx_min, cx_max, linesize, x_incr;
1071 uint32_t offset, fgcol, bgcol, v, cursor_offset;
1072 uint8_t *d1, *d, *src, *s1, *dest, *cursor_ptr;
1073 const uint8_t *font_ptr, *font_base[2];
1074 int dup9, line_offset, depth_index;
1075 uint32_t *palette;
1076 uint32_t *ch_attr_ptr;
1077 vga_draw_glyph8_func *vga_draw_glyph8;
1078 vga_draw_glyph9_func *vga_draw_glyph9;
1080 full_update |= update_palette16(s);
1081 palette = s->last_palette;
1083 /* compute font data address (in plane 2) */
1084 v = s->sr[3];
1085 offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
1086 if (offset != s->font_offsets[0]) {
1087 s->font_offsets[0] = offset;
1088 full_update = 1;
1090 font_base[0] = s->vram_ptr + offset;
1092 offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
1093 font_base[1] = s->vram_ptr + offset;
1094 if (offset != s->font_offsets[1]) {
1095 s->font_offsets[1] = offset;
1096 full_update = 1;
1098 if (s->plane_updated & (1 << 2)) {
1099 /* if the plane 2 was modified since the last display, it
1100 indicates the font may have been modified */
1101 s->plane_updated = 0;
1102 full_update = 1;
1104 full_update |= update_basic_params(s);
1106 line_offset = s->line_offset;
1107 s1 = s->vram_ptr + (s->start_addr * 4);
1109 /* total width & height */
1110 cheight = (s->cr[9] & 0x1f) + 1;
1111 cw = 8;
1112 if (!(s->sr[1] & 0x01))
1113 cw = 9;
1114 if (s->sr[1] & 0x08)
1115 cw = 16; /* NOTE: no 18 pixel wide */
1116 x_incr = cw * ((s->ds->depth + 7) >> 3);
1117 width = (s->cr[0x01] + 1);
1118 if (s->cr[0x06] == 100) {
1119 /* ugly hack for CGA 160x100x16 - explain me the logic */
1120 height = 100;
1121 } else {
1122 height = s->cr[0x12] |
1123 ((s->cr[0x07] & 0x02) << 7) |
1124 ((s->cr[0x07] & 0x40) << 3);
1125 height = (height + 1) / cheight;
1127 if ((height * width) > CH_ATTR_SIZE) {
1128 /* better than nothing: exit if transient size is too big */
1129 return;
1132 if (width != s->last_width || height != s->last_height ||
1133 cw != s->last_cw || cheight != s->last_ch) {
1134 s->last_scr_width = width * cw;
1135 s->last_scr_height = height * cheight;
1136 dpy_resize(s->ds, s->last_scr_width, s->last_scr_height);
1137 s->last_width = width;
1138 s->last_height = height;
1139 s->last_ch = cheight;
1140 s->last_cw = cw;
1141 full_update = 1;
1143 cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
1144 if (cursor_offset != s->cursor_offset ||
1145 s->cr[0xa] != s->cursor_start ||
1146 s->cr[0xb] != s->cursor_end) {
1147 /* if the cursor position changed, we update the old and new
1148 chars */
1149 if (s->cursor_offset < CH_ATTR_SIZE)
1150 s->last_ch_attr[s->cursor_offset] = -1;
1151 if (cursor_offset < CH_ATTR_SIZE)
1152 s->last_ch_attr[cursor_offset] = -1;
1153 s->cursor_offset = cursor_offset;
1154 s->cursor_start = s->cr[0xa];
1155 s->cursor_end = s->cr[0xb];
1157 cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
1159 depth_index = get_depth_index(s->ds->depth);
1160 if (cw == 16)
1161 vga_draw_glyph8 = vga_draw_glyph16_table[depth_index];
1162 else
1163 vga_draw_glyph8 = vga_draw_glyph8_table[depth_index];
1164 vga_draw_glyph9 = vga_draw_glyph9_table[depth_index];
1166 dest = s->ds->data;
1167 linesize = s->ds->linesize;
1168 ch_attr_ptr = s->last_ch_attr;
1169 for(cy = 0; cy < height; cy++) {
1170 d1 = dest;
1171 src = s1;
1172 cx_min = width;
1173 cx_max = -1;
1174 for(cx = 0; cx < width; cx++) {
1175 ch_attr = *(uint16_t *)src;
1176 if (full_update || ch_attr != *ch_attr_ptr) {
1177 if (cx < cx_min)
1178 cx_min = cx;
1179 if (cx > cx_max)
1180 cx_max = cx;
1181 *ch_attr_ptr = ch_attr;
1182 #ifdef WORDS_BIGENDIAN
1183 ch = ch_attr >> 8;
1184 cattr = ch_attr & 0xff;
1185 #else
1186 ch = ch_attr & 0xff;
1187 cattr = ch_attr >> 8;
1188 #endif
1189 font_ptr = font_base[(cattr >> 3) & 1];
1190 font_ptr += 32 * 4 * ch;
1191 bgcol = palette[cattr >> 4];
1192 fgcol = palette[cattr & 0x0f];
1193 if (cw != 9) {
1194 vga_draw_glyph8(d1, linesize,
1195 font_ptr, cheight, fgcol, bgcol);
1196 } else {
1197 dup9 = 0;
1198 if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))
1199 dup9 = 1;
1200 vga_draw_glyph9(d1, linesize,
1201 font_ptr, cheight, fgcol, bgcol, dup9);
1203 if (src == cursor_ptr &&
1204 !(s->cr[0x0a] & 0x20)) {
1205 int line_start, line_last, h;
1206 /* draw the cursor */
1207 line_start = s->cr[0x0a] & 0x1f;
1208 line_last = s->cr[0x0b] & 0x1f;
1209 /* XXX: check that */
1210 if (line_last > cheight - 1)
1211 line_last = cheight - 1;
1212 if (line_last >= line_start && line_start < cheight) {
1213 h = line_last - line_start + 1;
1214 d = d1 + linesize * line_start;
1215 if (cw != 9) {
1216 vga_draw_glyph8(d, linesize,
1217 cursor_glyph, h, fgcol, bgcol);
1218 } else {
1219 vga_draw_glyph9(d, linesize,
1220 cursor_glyph, h, fgcol, bgcol, 1);
1225 d1 += x_incr;
1226 src += 4;
1227 ch_attr_ptr++;
1229 if (cx_max != -1) {
1230 dpy_update(s->ds, cx_min * cw, cy * cheight,
1231 (cx_max - cx_min + 1) * cw, cheight);
1233 dest += linesize * cheight;
1234 s1 += line_offset;
1238 enum {
1239 VGA_DRAW_LINE2,
1240 VGA_DRAW_LINE2D2,
1241 VGA_DRAW_LINE4,
1242 VGA_DRAW_LINE4D2,
1243 VGA_DRAW_LINE8D2,
1244 VGA_DRAW_LINE8,
1245 VGA_DRAW_LINE15,
1246 VGA_DRAW_LINE16,
1247 VGA_DRAW_LINE24,
1248 VGA_DRAW_LINE32,
1249 VGA_DRAW_LINE_NB,
1250 };
1252 static vga_draw_line_func *vga_draw_line_table[4 * VGA_DRAW_LINE_NB] = {
1253 vga_draw_line2_8,
1254 vga_draw_line2_16,
1255 vga_draw_line2_16,
1256 vga_draw_line2_32,
1258 vga_draw_line2d2_8,
1259 vga_draw_line2d2_16,
1260 vga_draw_line2d2_16,
1261 vga_draw_line2d2_32,
1263 vga_draw_line4_8,
1264 vga_draw_line4_16,
1265 vga_draw_line4_16,
1266 vga_draw_line4_32,
1268 vga_draw_line4d2_8,
1269 vga_draw_line4d2_16,
1270 vga_draw_line4d2_16,
1271 vga_draw_line4d2_32,
1273 vga_draw_line8d2_8,
1274 vga_draw_line8d2_16,
1275 vga_draw_line8d2_16,
1276 vga_draw_line8d2_32,
1278 vga_draw_line8_8,
1279 vga_draw_line8_16,
1280 vga_draw_line8_16,
1281 vga_draw_line8_32,
1283 vga_draw_line15_8,
1284 vga_draw_line15_15,
1285 vga_draw_line15_16,
1286 vga_draw_line15_32,
1288 vga_draw_line16_8,
1289 vga_draw_line16_15,
1290 vga_draw_line16_16,
1291 vga_draw_line16_32,
1293 vga_draw_line24_8,
1294 vga_draw_line24_15,
1295 vga_draw_line24_16,
1296 vga_draw_line24_32,
1298 vga_draw_line32_8,
1299 vga_draw_line32_15,
1300 vga_draw_line32_16,
1301 vga_draw_line32_32,
1302 };
1304 static int vga_get_bpp(VGAState *s)
1306 int ret;
1307 #ifdef CONFIG_BOCHS_VBE
1308 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1309 ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
1310 } else
1311 #endif
1313 ret = 0;
1315 return ret;
1318 static void vga_get_resolution(VGAState *s, int *pwidth, int *pheight)
1320 int width, height;
1322 width = (s->cr[0x01] + 1) * 8;
1323 height = s->cr[0x12] |
1324 ((s->cr[0x07] & 0x02) << 7) |
1325 ((s->cr[0x07] & 0x40) << 3);
1326 height = (height + 1);
1327 *pwidth = width;
1328 *pheight = height;
1331 void vga_invalidate_scanlines(VGAState *s, int y1, int y2)
1333 int y;
1334 if (y1 >= VGA_MAX_HEIGHT)
1335 return;
1336 if (y2 >= VGA_MAX_HEIGHT)
1337 y2 = VGA_MAX_HEIGHT;
1338 for(y = y1; y < y2; y++) {
1339 s->invalidated_y_table[y >> 5] |= 1 << (y & 0x1f);
1343 static inline int cmp_vram(VGAState *s, int offset, int n)
1345 long *vp, *sp;
1347 if (s->vram_shadow == NULL)
1348 return 1;
1349 vp = (long *)(s->vram_ptr + offset);
1350 sp = (long *)(s->vram_shadow + offset);
1351 while ((n -= sizeof(*vp)) >= 0) {
1352 if (*vp++ != *sp++) {
1353 memcpy(sp - 1, vp - 1, n + sizeof(*vp));
1354 return 1;
1357 return 0;
1360 #ifdef USE_SSE2
1362 #include <signal.h>
1363 #include <setjmp.h>
1364 #include <emmintrin.h>
1366 int sse2_ok = 1;
1368 static inline unsigned int cpuid_edx(unsigned int op)
1370 unsigned int eax, edx;
1372 #ifdef __x86_64__
1373 #define __bx "rbx"
1374 #else
1375 #define __bx "ebx"
1376 #endif
1377 __asm__("push %%"__bx"; cpuid; pop %%"__bx
1378 : "=a" (eax), "=d" (edx)
1379 : "0" (op)
1380 : "cx");
1381 #undef __ebx
1383 return edx;
1386 jmp_buf sse_jbuf;
1388 void intr(int sig)
1390 sse2_ok = 0;
1391 longjmp(sse_jbuf, 1);
1394 void check_sse2(void)
1396 /* Check 1: What does CPUID say? */
1397 if ((cpuid_edx(1) & 0x4000000) == 0) {
1398 sse2_ok = 0;
1399 return;
1402 /* Check 2: Can we use SSE2 in anger? */
1403 signal(SIGILL, intr);
1404 if (setjmp(sse_jbuf) == 0)
1405 __asm__("xorps %xmm0,%xmm0\n");
1408 int vram_dirty(VGAState *s, int offset, int n)
1410 __m128i *sp, *vp;
1412 if (s->vram_shadow == NULL)
1413 return 1;
1414 if (sse2_ok == 0)
1415 return cmp_vram(s, offset, n);
1416 vp = (__m128i *)(s->vram_ptr + offset);
1417 sp = (__m128i *)(s->vram_shadow + offset);
1418 while ((n -= sizeof(*vp)) >= 0) {
1419 if (_mm_movemask_epi8(_mm_cmpeq_epi8(*sp, *vp)) != 0xffff) {
1420 while (n >= 0) {
1421 _mm_store_si128(sp++, _mm_load_si128(vp++));
1422 n -= sizeof(*vp);
1424 return 1;
1426 sp++;
1427 vp++;
1429 return 0;
1431 #else /* !USE_SSE2 */
1432 int vram_dirty(VGAState *s, int offset, int n)
1434 return cmp_vram(s, offset, n);
1437 void check_sse2(void)
1440 #endif /* !USE_SSE2 */
1442 /*
1443 * graphic modes
1444 */
1445 static void vga_draw_graphic(VGAState *s, int full_update)
1447 int y1, y, update, page_min, page_max, linesize, y_start, double_scan, mask;
1448 int width, height, shift_control, line_offset, page0, page1, bwidth;
1449 int disp_width, multi_scan, multi_run;
1450 uint8_t *d;
1451 uint32_t v, addr1, addr;
1452 vga_draw_line_func *vga_draw_line;
1454 full_update |= update_basic_params(s);
1456 s->get_resolution(s, &width, &height);
1457 disp_width = width;
1459 shift_control = (s->gr[0x05] >> 5) & 3;
1460 double_scan = (s->cr[0x09] >> 7);
1461 if (shift_control != 1) {
1462 multi_scan = (((s->cr[0x09] & 0x1f) + 1) << double_scan) - 1;
1463 } else {
1464 /* in CGA modes, multi_scan is ignored */
1465 /* XXX: is it correct ? */
1466 multi_scan = double_scan;
1468 multi_run = multi_scan;
1469 if (shift_control != s->shift_control ||
1470 double_scan != s->double_scan) {
1471 full_update = 1;
1472 s->shift_control = shift_control;
1473 s->double_scan = double_scan;
1476 if (shift_control == 0) {
1477 full_update |= update_palette16(s);
1478 if (s->sr[0x01] & 8) {
1479 v = VGA_DRAW_LINE4D2;
1480 disp_width <<= 1;
1481 } else {
1482 v = VGA_DRAW_LINE4;
1484 } else if (shift_control == 1) {
1485 full_update |= update_palette16(s);
1486 if (s->sr[0x01] & 8) {
1487 v = VGA_DRAW_LINE2D2;
1488 disp_width <<= 1;
1489 } else {
1490 v = VGA_DRAW_LINE2;
1492 } else {
1493 switch(s->get_bpp(s)) {
1494 default:
1495 case 0:
1496 full_update |= update_palette256(s);
1497 v = VGA_DRAW_LINE8D2;
1498 break;
1499 case 8:
1500 full_update |= update_palette256(s);
1501 v = VGA_DRAW_LINE8;
1502 break;
1503 case 15:
1504 v = VGA_DRAW_LINE15;
1505 break;
1506 case 16:
1507 v = VGA_DRAW_LINE16;
1508 break;
1509 case 24:
1510 v = VGA_DRAW_LINE24;
1511 break;
1512 case 32:
1513 v = VGA_DRAW_LINE32;
1514 break;
1517 vga_draw_line = vga_draw_line_table[v * 4 + get_depth_index(s->ds->depth)];
1519 if (disp_width != s->last_width ||
1520 height != s->last_height) {
1521 dpy_resize(s->ds, disp_width, height);
1522 s->last_scr_width = disp_width;
1523 s->last_scr_height = height;
1524 s->last_width = disp_width;
1525 s->last_height = height;
1526 full_update = 1;
1528 if (s->cursor_invalidate)
1529 s->cursor_invalidate(s);
1531 line_offset = s->line_offset;
1532 #if 0
1533 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",
1534 width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]);
1535 #endif
1536 for (y = 0; y < s->vram_size; y += TARGET_PAGE_SIZE)
1537 if (vram_dirty(s, y, TARGET_PAGE_SIZE))
1538 cpu_physical_memory_set_dirty(s->vram_offset + y);
1539 addr1 = (s->start_addr * 4);
1540 bwidth = width * 4;
1541 y_start = -1;
1542 page_min = 0x7fffffff;
1543 page_max = -1;
1544 d = s->ds->data;
1545 linesize = s->ds->linesize;
1546 y1 = 0;
1547 for(y = 0; y < height; y++) {
1548 addr = addr1;
1549 if (!(s->cr[0x17] & 1)) {
1550 int shift;
1551 /* CGA compatibility handling */
1552 shift = 14 + ((s->cr[0x17] >> 6) & 1);
1553 addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
1555 if (!(s->cr[0x17] & 2)) {
1556 addr = (addr & ~0x8000) | ((y1 & 2) << 14);
1558 page0 = s->vram_offset + (addr & TARGET_PAGE_MASK);
1559 page1 = s->vram_offset + ((addr + bwidth - 1) & TARGET_PAGE_MASK);
1560 update = full_update | cpu_physical_memory_is_dirty(page0) |
1561 cpu_physical_memory_is_dirty(page1);
1562 if ((page1 - page0) > TARGET_PAGE_SIZE) {
1563 /* if wide line, can use another page */
1564 update |= cpu_physical_memory_is_dirty(page0 + TARGET_PAGE_SIZE);
1566 /* explicit invalidation for the hardware cursor */
1567 update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
1568 if (update) {
1569 if (y_start < 0)
1570 y_start = y;
1571 if (page0 < page_min)
1572 page_min = page0;
1573 if (page1 > page_max)
1574 page_max = page1;
1575 vga_draw_line(s, d, s->vram_ptr + addr, width);
1576 if (s->cursor_draw_line)
1577 s->cursor_draw_line(s, d, y);
1578 } else {
1579 if (y_start >= 0) {
1580 /* flush to display */
1581 dpy_update(s->ds, 0, y_start,
1582 disp_width, y - y_start);
1583 y_start = -1;
1586 if (!multi_run) {
1587 mask = (s->cr[0x17] & 3) ^ 3;
1588 if ((y1 & mask) == mask)
1589 addr1 += line_offset;
1590 y1++;
1591 multi_run = multi_scan;
1592 } else {
1593 multi_run--;
1595 /* line compare acts on the displayed lines */
1596 if (y == s->line_compare)
1597 addr1 = 0;
1598 d += linesize;
1600 if (y_start >= 0) {
1601 /* flush to display */
1602 dpy_update(s->ds, 0, y_start,
1603 disp_width, y - y_start);
1605 /* reset modified pages */
1606 if (page_max != -1) {
1607 cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE);
1609 memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
1612 static void vga_draw_blank(VGAState *s, int full_update)
1614 int i, w, val;
1615 uint8_t *d;
1617 if (!full_update)
1618 return;
1619 if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
1620 return;
1621 if (s->ds->depth == 8)
1622 val = s->rgb_to_pixel(0, 0, 0);
1623 else
1624 val = 0;
1625 w = s->last_scr_width * ((s->ds->depth + 7) >> 3);
1626 d = s->ds->data;
1627 for(i = 0; i < s->last_scr_height; i++) {
1628 memset(d, val, w);
1629 d += s->ds->linesize;
1631 dpy_update(s->ds, 0, 0,
1632 s->last_scr_width, s->last_scr_height);
1635 #define GMODE_TEXT 0
1636 #define GMODE_GRAPH 1
1637 #define GMODE_BLANK 2
1639 void vga_update_display(void)
1641 static int loop;
1642 VGAState *s = vga_state;
1643 int full_update, graphic_mode;
1645 /*
1646 * Only update the display every other time. The responsiveness is
1647 * acceptable and it cuts down on the overhead of the VRAM compare
1648 * in `vram_dirty'.
1649 */
1650 if (loop++ & 1)
1651 return;
1653 if (s->ds->depth == 0) {
1654 /* nothing to do */
1655 } else {
1656 switch(s->ds->depth) {
1657 case 8:
1658 s->rgb_to_pixel = rgb_to_pixel8_dup;
1659 break;
1660 case 15:
1661 s->rgb_to_pixel = rgb_to_pixel15_dup;
1662 break;
1663 default:
1664 case 16:
1665 s->rgb_to_pixel = rgb_to_pixel16_dup;
1666 break;
1667 case 32:
1668 s->rgb_to_pixel = rgb_to_pixel32_dup;
1669 break;
1672 full_update = 0;
1673 if (!(s->ar_index & 0x20)) {
1674 graphic_mode = GMODE_BLANK;
1675 } else {
1676 graphic_mode = s->gr[6] & 1;
1678 if (graphic_mode != s->graphic_mode) {
1679 s->graphic_mode = graphic_mode;
1680 full_update = 1;
1683 switch(graphic_mode) {
1684 case GMODE_TEXT:
1685 vga_draw_text(s, full_update);
1686 break;
1687 case GMODE_GRAPH:
1688 vga_draw_graphic(s, full_update);
1689 break;
1690 case GMODE_BLANK:
1691 default:
1692 vga_draw_blank(s, full_update);
1693 break;
1698 /* force a full display refresh */
1699 void vga_invalidate_display(void)
1701 VGAState *s = vga_state;
1703 s->last_width = -1;
1704 s->last_height = -1;
1707 static void vga_reset(VGAState *s)
1709 memset(s, 0, sizeof(VGAState));
1710 #ifdef CONFIG_S3VGA
1711 /* chip ID for 8c968 */
1712 s->cr[0x2d] = 0x88;
1713 s->cr[0x2e] = 0xb0;
1714 s->cr[0x2f] = 0x01; /* XXX: check revision code */
1715 s->cr[0x30] = 0xe1;
1716 #endif
1717 s->graphic_mode = -1; /* force full update */
1720 static CPUReadMemoryFunc *vga_mem_read[3] = {
1721 vga_mem_readb,
1722 vga_mem_readw,
1723 vga_mem_readl,
1724 };
1726 static CPUWriteMemoryFunc *vga_mem_write[3] = {
1727 vga_mem_writeb,
1728 vga_mem_writew,
1729 vga_mem_writel,
1730 };
1732 static void vga_save(QEMUFile *f, void *opaque)
1734 VGAState *s = opaque;
1736 qemu_put_be32s(f, &s->latch);
1737 qemu_put_8s(f, &s->sr_index);
1738 qemu_put_buffer(f, s->sr, 8);
1739 qemu_put_8s(f, &s->gr_index);
1740 qemu_put_buffer(f, s->gr, 16);
1741 qemu_put_8s(f, &s->ar_index);
1742 qemu_put_buffer(f, s->ar, 21);
1743 qemu_put_be32s(f, &s->ar_flip_flop);
1744 qemu_put_8s(f, &s->cr_index);
1745 qemu_put_buffer(f, s->cr, 256);
1746 qemu_put_8s(f, &s->msr);
1747 qemu_put_8s(f, &s->fcr);
1748 qemu_put_8s(f, &s->st00);
1749 qemu_put_8s(f, &s->st01);
1751 qemu_put_8s(f, &s->dac_state);
1752 qemu_put_8s(f, &s->dac_sub_index);
1753 qemu_put_8s(f, &s->dac_read_index);
1754 qemu_put_8s(f, &s->dac_write_index);
1755 qemu_put_buffer(f, s->dac_cache, 3);
1756 qemu_put_buffer(f, s->palette, 768);
1758 qemu_put_be32s(f, &s->bank_offset);
1759 #ifdef CONFIG_BOCHS_VBE
1760 qemu_put_byte(f, 1);
1761 qemu_put_be16s(f, &s->vbe_index);
1762 for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
1763 qemu_put_be16s(f, &s->vbe_regs[i]);
1764 qemu_put_be32s(f, &s->vbe_start_addr);
1765 qemu_put_be32s(f, &s->vbe_line_offset);
1766 qemu_put_be32s(f, &s->vbe_bank_mask);
1767 #else
1768 qemu_put_byte(f, 0);
1769 #endif
1772 static int vga_load(QEMUFile *f, void *opaque, int version_id)
1774 VGAState *s = opaque;
1775 int is_vbe;
1777 if (version_id != 1)
1778 return -EINVAL;
1780 qemu_get_be32s(f, &s->latch);
1781 qemu_get_8s(f, &s->sr_index);
1782 qemu_get_buffer(f, s->sr, 8);
1783 qemu_get_8s(f, &s->gr_index);
1784 qemu_get_buffer(f, s->gr, 16);
1785 qemu_get_8s(f, &s->ar_index);
1786 qemu_get_buffer(f, s->ar, 21);
1787 qemu_get_be32s(f, &s->ar_flip_flop);
1788 qemu_get_8s(f, &s->cr_index);
1789 qemu_get_buffer(f, s->cr, 256);
1790 qemu_get_8s(f, &s->msr);
1791 qemu_get_8s(f, &s->fcr);
1792 qemu_get_8s(f, &s->st00);
1793 qemu_get_8s(f, &s->st01);
1795 qemu_get_8s(f, &s->dac_state);
1796 qemu_get_8s(f, &s->dac_sub_index);
1797 qemu_get_8s(f, &s->dac_read_index);
1798 qemu_get_8s(f, &s->dac_write_index);
1799 qemu_get_buffer(f, s->dac_cache, 3);
1800 qemu_get_buffer(f, s->palette, 768);
1802 qemu_get_be32s(f, &s->bank_offset);
1803 is_vbe = qemu_get_byte(f);
1804 #ifdef CONFIG_BOCHS_VBE
1805 if (!is_vbe)
1806 return -EINVAL;
1807 qemu_get_be16s(f, &s->vbe_index);
1808 for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
1809 qemu_get_be16s(f, &s->vbe_regs[i]);
1810 qemu_get_be32s(f, &s->vbe_start_addr);
1811 qemu_get_be32s(f, &s->vbe_line_offset);
1812 qemu_get_be32s(f, &s->vbe_bank_mask);
1813 #else
1814 if (is_vbe)
1815 return -EINVAL;
1816 #endif
1818 /* force refresh */
1819 s->graphic_mode = -1;
1820 return 0;
1823 static void vga_map(PCIDevice *pci_dev, int region_num,
1824 uint32_t addr, uint32_t size, int type)
1826 VGAState *s = vga_state;
1828 cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
1831 /* do the same job as vgabios before vgabios get ready */
1832 void vga_bios_init(VGAState *s)
1834 uint8_t palette_model[192] = {
1835 0, 0, 0, 0, 0, 170, 0, 170, 0, 0, 170, 170, 170, 0, 0, 170,
1836 0, 170, 170, 85, 0, 170, 170, 170, 85, 85, 85, 85, 85, 255, 85, 255,
1837 85, 85, 255, 255, 255, 85, 85, 255, 85, 255, 255, 255, 85, 255, 255, 255,
1838 0, 21, 0, 0, 21, 42, 0, 63, 0, 0, 63, 42, 42, 21, 0, 42,
1839 21, 42, 42, 63, 0, 42, 63, 42, 0, 21, 21, 0, 21, 63, 0, 63,
1840 21, 0, 63, 63, 42, 21, 21, 42, 21, 63, 42, 63, 21, 42, 63, 63,
1841 21, 0, 0, 21, 0, 42, 21, 42, 0, 21, 42, 42, 63, 0, 0, 63,
1842 0, 42, 63, 42, 0, 63, 42, 42, 21, 0, 21, 21, 0, 63, 21, 42,
1843 21, 21, 42, 63, 63, 0, 21, 63, 0, 63, 63, 42, 21, 63, 42, 63,
1844 21, 21, 0, 21, 21, 42, 21, 63, 0, 21, 63, 42, 63, 21, 0, 63,
1845 21, 42, 63, 63, 0, 63, 63, 42, 21, 21, 21, 21, 21, 63, 21, 63,
1846 21, 21, 63, 63, 63, 21, 21, 63, 21, 63, 63, 63, 21, 63, 63, 63
1847 };
1849 s->latch = 0;
1851 s->sr_index = 3;
1852 s->sr[0] = 3;
1853 s->sr[1] = 0;
1854 s->sr[2] = 3;
1855 s->sr[3] = 0;
1856 s->sr[4] = 2;
1857 s->sr[5] = 0;
1858 s->sr[6] = 0;
1859 s->sr[7] = 0;
1861 s->gr_index = 5;
1862 s->gr[0] = 0;
1863 s->gr[1] = 0;
1864 s->gr[2] = 0;
1865 s->gr[3] = 0;
1866 s->gr[4] = 0;
1867 s->gr[5] = 16;
1868 s->gr[6] = 14;
1869 s->gr[7] = 15;
1870 s->gr[8] = 255;
1872 /*changed by out 0x03c0*/
1873 s->ar_index = 32;
1874 s->ar[0] = 0;
1875 s->ar[1] = 1;
1876 s->ar[2] = 2;
1877 s->ar[3] = 3;
1878 s->ar[4] = 4;
1879 s->ar[5] = 5;
1880 s->ar[6] = 6;
1881 s->ar[7] = 7;
1882 s->ar[8] = 8;
1883 s->ar[9] = 9;
1884 s->ar[10] = 10;
1885 s->ar[11] = 11;
1886 s->ar[12] = 12;
1887 s->ar[13] = 13;
1888 s->ar[14] = 14;
1889 s->ar[15] = 15;
1890 s->ar[16] = 12;
1891 s->ar[17] = 0;
1892 s->ar[18] = 15;
1893 s->ar[19] = 8;
1894 s->ar[20] = 0;
1896 s->ar_flip_flop = 1;
1898 s->cr_index = 15;
1899 s->cr[0] = 95;
1900 s->cr[1] = 79;
1901 s->cr[2] = 80;
1902 s->cr[3] = 130;
1903 s->cr[4] = 85;
1904 s->cr[5] = 129;
1905 s->cr[6] = 191;
1906 s->cr[7] = 31;
1907 s->cr[8] = 0;
1908 s->cr[9] = 79;
1909 s->cr[10] = 14;
1910 s->cr[11] = 15;
1911 s->cr[12] = 0;
1912 s->cr[13] = 0;
1913 s->cr[14] = 5;
1914 s->cr[15] = 160;
1915 s->cr[16] = 156;
1916 s->cr[17] = 142;
1917 s->cr[18] = 143;
1918 s->cr[19] = 40;
1919 s->cr[20] = 31;
1920 s->cr[21] = 150;
1921 s->cr[22] = 185;
1922 s->cr[23] = 163;
1923 s->cr[24] = 255;
1925 s->msr = 103;
1926 s->fcr = 0;
1927 s->st00 = 0;
1928 s->st01 = 0;
1930 /*dac_* & platte will be initialized by os through out 0x03c8 & out 0c03c9(1:3) */
1931 s->dac_state = 0;
1932 s->dac_sub_index = 0;
1933 s->dac_read_index = 0;
1934 s->dac_write_index = 16;
1935 s->dac_cache[0] = 255;
1936 s->dac_cache[1] = 255;
1937 s->dac_cache[2] = 255;
1939 /*platte*/
1940 memcpy(s->palette, palette_model, 192);
1942 s->bank_offset= 0;
1943 s->graphic_mode = -1;
1945 /* TODO:add vbe support if enable it */
1949 void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base,
1950 unsigned long vga_ram_offset, int vga_ram_size)
1952 int i, j, v, b;
1953 extern void* shared_vram;
1955 for(i = 0;i < 256; i++) {
1956 v = 0;
1957 for(j = 0; j < 8; j++) {
1958 v |= ((i >> j) & 1) << (j * 4);
1960 expand4[i] = v;
1962 v = 0;
1963 for(j = 0; j < 4; j++) {
1964 v |= ((i >> (2 * j)) & 3) << (j * 4);
1966 expand2[i] = v;
1968 for(i = 0; i < 16; i++) {
1969 v = 0;
1970 for(j = 0; j < 4; j++) {
1971 b = ((i >> j) & 1);
1972 v |= b << (2 * j);
1973 v |= b << (2 * j + 1);
1975 expand4to8[i] = v;
1978 vga_reset(s);
1980 /* qemu's vga mem is not detached from phys_ram_base and can cause DM abort
1981 * when guest write vga mem, so allocate a new one */
1982 #if defined(__i386__) || defined(__x86_64__)
1983 s->vram_ptr = shared_vram;
1984 #else
1985 s->vram_ptr = qemu_malloc(vga_ram_size);
1986 #endif
1987 check_sse2();
1988 s->vram_shadow = qemu_malloc(vga_ram_size+TARGET_PAGE_SIZE+1);
1989 if (s->vram_shadow == NULL)
1990 fprintf(stderr, "Cannot allocate %d bytes for VRAM shadow, "
1991 "mouse will be slow\n", vga_ram_size);
1992 s->vram_shadow = (uint8_t *)((long)(s->vram_shadow + TARGET_PAGE_SIZE - 1)
1993 & ~(TARGET_PAGE_SIZE - 1));
1994 s->vram_offset = vga_ram_offset;
1995 s->vram_size = vga_ram_size;
1996 s->ds = ds;
1997 s->get_bpp = vga_get_bpp;
1998 s->get_offsets = vga_get_offsets;
1999 s->get_resolution = vga_get_resolution;
2000 /* XXX: currently needed for display */
2001 vga_state = s;
2005 int vga_initialize(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base,
2006 unsigned long vga_ram_offset, int vga_ram_size)
2008 VGAState *s;
2010 s = qemu_mallocz(sizeof(VGAState));
2011 if (!s)
2012 return -1;
2014 vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size);
2016 register_savevm("vga", 0, 1, vga_save, vga_load, s);
2018 register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
2020 register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
2021 register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);
2022 register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);
2023 register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);
2025 register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
2027 register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);
2028 register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);
2029 register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
2030 register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
2031 s->bank_offset = 0;
2033 #ifdef CONFIG_BOCHS_VBE
2034 s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0;
2035 s->vbe_bank_mask = ((s->vram_size >> 16) - 1);
2036 #if defined (TARGET_I386)
2037 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
2038 register_ioport_read(0x1cf, 1, 2, vbe_ioport_read_data, s);
2040 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
2041 register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data, s);
2043 /* old Bochs IO ports */
2044 register_ioport_read(0xff80, 1, 2, vbe_ioport_read_index, s);
2045 register_ioport_read(0xff81, 1, 2, vbe_ioport_read_data, s);
2047 register_ioport_write(0xff80, 1, 2, vbe_ioport_write_index, s);
2048 register_ioport_write(0xff81, 1, 2, vbe_ioport_write_data, s);
2049 #else
2050 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
2051 register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data, s);
2053 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
2054 register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data, s);
2055 #endif
2056 #endif /* CONFIG_BOCHS_VBE */
2058 vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s);
2059 cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
2060 vga_io_memory);
2062 if (bus) {
2063 PCIDevice *d;
2064 uint8_t *pci_conf;
2066 d = pci_register_device(bus, "VGA",
2067 sizeof(PCIDevice),
2068 -1, NULL, NULL);
2069 pci_conf = d->config;
2070 pci_conf[0x00] = 0x34; // dummy VGA (same as Bochs ID)
2071 pci_conf[0x01] = 0x12;
2072 pci_conf[0x02] = 0x11;
2073 pci_conf[0x03] = 0x11;
2074 pci_conf[0x0a] = 0x00; // VGA controller
2075 pci_conf[0x0b] = 0x03;
2076 pci_conf[0x0e] = 0x00; // header_type
2078 /* XXX: vga_ram_size must be a power of two */
2079 pci_register_io_region(d, 0, vga_ram_size,
2080 PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
2081 } else {
2082 #ifdef CONFIG_BOCHS_VBE
2083 /* XXX: use optimized standard vga accesses */
2084 cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
2085 vga_ram_size, vga_ram_offset);
2086 #endif
2089 vga_bios_init(s);
2090 return 0;
2093 int vga_update_vram(VGAState *s, void *vga_ram_base, int vga_ram_size)
2095 if (s->vram_size != vga_ram_size)
2097 fprintf(stderr, "No support to change vga_ram_size\n");
2098 return -1;
2101 if ( !vga_ram_base )
2103 vga_ram_base = qemu_malloc(vga_ram_size);
2104 if (!vga_ram_base)
2106 fprintf(stderr, "reallocate error\n");
2107 return -1;
2111 /* XXX lock needed? */
2112 memcpy(vga_ram_base, s->vram_ptr, vga_ram_size);
2113 s->vram_ptr = vga_ram_base;
2115 return 0;
2118 /********************************************************/
2119 /* vga screen dump */
2121 static int vga_save_w, vga_save_h;
2123 static void vga_save_dpy_update(DisplayState *s,
2124 int x, int y, int w, int h)
2128 static void vga_save_dpy_resize(DisplayState *s, int w, int h)
2130 s->linesize = w * 4;
2131 s->data = qemu_malloc(h * s->linesize);
2132 vga_save_w = w;
2133 vga_save_h = h;
2136 static void vga_save_dpy_refresh(DisplayState *s)
2140 static int ppm_save(const char *filename, uint8_t *data,
2141 int w, int h, int linesize)
2143 FILE *f;
2144 uint8_t *d, *d1;
2145 unsigned int v;
2146 int y, x;
2148 f = fopen(filename, "wb");
2149 if (!f)
2150 return -1;
2151 fprintf(f, "P6\n%d %d\n%d\n",
2152 w, h, 255);
2153 d1 = data;
2154 for(y = 0; y < h; y++) {
2155 d = d1;
2156 for(x = 0; x < w; x++) {
2157 v = *(uint32_t *)d;
2158 fputc((v >> 16) & 0xff, f);
2159 fputc((v >> 8) & 0xff, f);
2160 fputc((v) & 0xff, f);
2161 d += 4;
2163 d1 += linesize;
2165 fclose(f);
2166 return 0;
2169 /* save the vga display in a PPM image even if no display is
2170 available */
2171 void vga_screen_dump(const char *filename)
2173 VGAState *s = vga_state;
2174 DisplayState *saved_ds, ds1, *ds = &ds1;
2176 /* XXX: this is a little hackish */
2177 vga_invalidate_display();
2178 saved_ds = s->ds;
2180 memset(ds, 0, sizeof(DisplayState));
2181 ds->dpy_update = vga_save_dpy_update;
2182 ds->dpy_resize = vga_save_dpy_resize;
2183 ds->dpy_refresh = vga_save_dpy_refresh;
2184 ds->depth = 32;
2186 s->ds = ds;
2187 s->graphic_mode = -1;
2188 vga_update_display();
2190 if (ds->data) {
2191 ppm_save(filename, ds->data, vga_save_w, vga_save_h,
2192 s->ds->linesize);
2193 qemu_free(ds->data);
2195 s->ds = saved_ds;