ia64/xen-unstable

view tools/ioemu/hw/vga.c @ 18394:dade7f0bdc8d

hvm: Use main memory for video memory.

When creating an HVM domain, if e.g. another domain is created before
qemu allocates video memory, the extra 8MB memory ballooning is not
available any more, because it got consumed by the other domain.

This fixes it by taking video memory from the main memory:

- make hvmloader use e820_malloc to reserve some of the main memory
and notify ioemu of its address through the Xen platform PCI card.
- add XENMAPSPACE_mfn to the xen_add_to_physmap memory op, to allow
ioemu to move the MFNs between the original position and the PCI
mapping, when LFB acceleration is disabled/enabled
- add a remove_from_physmap memory op, to allow ioemu to unmap it
completely for the case of old guests with acceleration disabled.
- add xc_domain_memory_translate_gpfn_list to libxc to allow ioemu to
get the MFNs of the video memory.
- have xend save the PCI memory space instead of ioemu: if a memory
page is there, the guest can access it like usual memory, so xend
can safely be responsible to save it. The extra benefit is that
live migration will apply the logdirty optimization there too.
- handle old saved images, populating the video memory from ioemu if
really needed.

Signed-off-by: Samuel Thibault <samuel.thibault@eu.citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Aug 27 14:53:39 2008 +0100 (2008-08-27)
parents 707569df20e1
children 33d907ff2b04
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"
26 #include <sys/mman.h>
28 //#define DEBUG_VGA
29 //#define DEBUG_VGA_MEM
30 //#define DEBUG_VGA_REG
32 //#define DEBUG_BOCHS_VBE
34 /* force some bits to zero */
35 const uint8_t sr_mask[8] = {
36 (uint8_t)~0xfc,
37 (uint8_t)~0xc2,
38 (uint8_t)~0xf0,
39 (uint8_t)~0xc0,
40 (uint8_t)~0xf1,
41 (uint8_t)~0xff,
42 (uint8_t)~0xff,
43 (uint8_t)~0x00,
44 };
46 const uint8_t gr_mask[16] = {
47 (uint8_t)~0xf0, /* 0x00 */
48 (uint8_t)~0xf0, /* 0x01 */
49 (uint8_t)~0xf0, /* 0x02 */
50 (uint8_t)~0xe0, /* 0x03 */
51 (uint8_t)~0xfc, /* 0x04 */
52 (uint8_t)~0x84, /* 0x05 */
53 (uint8_t)~0xf0, /* 0x06 */
54 (uint8_t)~0xf0, /* 0x07 */
55 (uint8_t)~0x00, /* 0x08 */
56 (uint8_t)~0xff, /* 0x09 */
57 (uint8_t)~0xff, /* 0x0a */
58 (uint8_t)~0xff, /* 0x0b */
59 (uint8_t)~0xff, /* 0x0c */
60 (uint8_t)~0xff, /* 0x0d */
61 (uint8_t)~0xff, /* 0x0e */
62 (uint8_t)~0xff, /* 0x0f */
63 };
65 #define cbswap_32(__x) \
66 ((uint32_t)( \
67 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
68 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
69 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
70 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
72 #ifdef WORDS_BIGENDIAN
73 #define PAT(x) cbswap_32(x)
74 #else
75 #define PAT(x) (x)
76 #endif
78 #ifdef WORDS_BIGENDIAN
79 #define BIG 1
80 #else
81 #define BIG 0
82 #endif
84 #ifdef WORDS_BIGENDIAN
85 #define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
86 #else
87 #define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
88 #endif
90 static const uint32_t mask16[16] = {
91 PAT(0x00000000),
92 PAT(0x000000ff),
93 PAT(0x0000ff00),
94 PAT(0x0000ffff),
95 PAT(0x00ff0000),
96 PAT(0x00ff00ff),
97 PAT(0x00ffff00),
98 PAT(0x00ffffff),
99 PAT(0xff000000),
100 PAT(0xff0000ff),
101 PAT(0xff00ff00),
102 PAT(0xff00ffff),
103 PAT(0xffff0000),
104 PAT(0xffff00ff),
105 PAT(0xffffff00),
106 PAT(0xffffffff),
107 };
109 #undef PAT
111 #ifdef WORDS_BIGENDIAN
112 #define PAT(x) (x)
113 #else
114 #define PAT(x) cbswap_32(x)
115 #endif
117 static const uint32_t dmask16[16] = {
118 PAT(0x00000000),
119 PAT(0x000000ff),
120 PAT(0x0000ff00),
121 PAT(0x0000ffff),
122 PAT(0x00ff0000),
123 PAT(0x00ff00ff),
124 PAT(0x00ffff00),
125 PAT(0x00ffffff),
126 PAT(0xff000000),
127 PAT(0xff0000ff),
128 PAT(0xff00ff00),
129 PAT(0xff00ffff),
130 PAT(0xffff0000),
131 PAT(0xffff00ff),
132 PAT(0xffffff00),
133 PAT(0xffffffff),
134 };
136 static const uint32_t dmask4[4] = {
137 PAT(0x00000000),
138 PAT(0x0000ffff),
139 PAT(0xffff0000),
140 PAT(0xffffffff),
141 };
143 static uint32_t expand4[256];
144 static uint16_t expand2[256];
145 static uint8_t expand4to8[16];
147 static void vga_screen_dump(void *opaque, const char *filename);
149 static uint32_t vga_ioport_read(void *opaque, uint32_t addr)
150 {
151 VGAState *s = opaque;
152 int val, index;
154 /* check port range access depending on color/monochrome mode */
155 if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
156 (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION))) {
157 val = 0xff;
158 } else {
159 switch(addr) {
160 case 0x3c0:
161 if (s->ar_flip_flop == 0) {
162 val = s->ar_index;
163 } else {
164 val = 0;
165 }
166 break;
167 case 0x3c1:
168 index = s->ar_index & 0x1f;
169 if (index < 21)
170 val = s->ar[index];
171 else
172 val = 0;
173 break;
174 case 0x3c2:
175 val = s->st00;
176 break;
177 case 0x3c4:
178 val = s->sr_index;
179 break;
180 case 0x3c5:
181 val = s->sr[s->sr_index];
182 #ifdef DEBUG_VGA_REG
183 printf("vga: read SR%x = 0x%02x\n", s->sr_index, val);
184 #endif
185 break;
186 case 0x3c7:
187 val = s->dac_state;
188 break;
189 case 0x3c8:
190 val = s->dac_write_index;
191 break;
192 case 0x3c9:
193 val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
194 if (++s->dac_sub_index == 3) {
195 s->dac_sub_index = 0;
196 s->dac_read_index++;
197 }
198 break;
199 case 0x3ca:
200 val = s->fcr;
201 break;
202 case 0x3cc:
203 val = s->msr;
204 break;
205 case 0x3ce:
206 val = s->gr_index;
207 break;
208 case 0x3cf:
209 val = s->gr[s->gr_index];
210 #ifdef DEBUG_VGA_REG
211 printf("vga: read GR%x = 0x%02x\n", s->gr_index, val);
212 #endif
213 break;
214 case 0x3b4:
215 case 0x3d4:
216 val = s->cr_index;
217 break;
218 case 0x3b5:
219 case 0x3d5:
220 val = s->cr[s->cr_index];
221 #ifdef DEBUG_VGA_REG
222 printf("vga: read CR%x = 0x%02x\n", s->cr_index, val);
223 #endif
224 break;
225 case 0x3ba:
226 case 0x3da:
227 /* just toggle to fool polling */
228 s->st01 ^= ST01_V_RETRACE | ST01_DISP_ENABLE;
229 val = s->st01;
230 s->ar_flip_flop = 0;
231 break;
232 default:
233 val = 0x00;
234 break;
235 }
236 }
237 #if defined(DEBUG_VGA)
238 printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
239 #endif
240 return val;
241 }
243 static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
244 {
245 VGAState *s = opaque;
246 int index;
248 /* check port range access depending on color/monochrome mode */
249 if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
250 (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION)))
251 return;
253 #ifdef DEBUG_VGA
254 printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
255 #endif
257 switch(addr) {
258 case 0x3c0:
259 if (s->ar_flip_flop == 0) {
260 val &= 0x3f;
261 s->ar_index = val;
262 } else {
263 index = s->ar_index & 0x1f;
264 switch(index) {
265 case 0x00 ... 0x0f:
266 s->ar[index] = val & 0x3f;
267 break;
268 case 0x10:
269 s->ar[index] = val & ~0x10;
270 break;
271 case 0x11:
272 s->ar[index] = val;
273 break;
274 case 0x12:
275 s->ar[index] = val & ~0xc0;
276 break;
277 case 0x13:
278 s->ar[index] = val & ~0xf0;
279 break;
280 case 0x14:
281 s->ar[index] = val & ~0xf0;
282 break;
283 default:
284 break;
285 }
286 }
287 s->ar_flip_flop ^= 1;
288 break;
289 case 0x3c2:
290 s->msr = val & ~0x10;
291 break;
292 case 0x3c4:
293 s->sr_index = val & 7;
294 break;
295 case 0x3c5:
296 #ifdef DEBUG_VGA_REG
297 printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
298 #endif
299 s->sr[s->sr_index] = val & sr_mask[s->sr_index];
300 break;
301 case 0x3c7:
302 s->dac_read_index = val;
303 s->dac_sub_index = 0;
304 s->dac_state = 3;
305 break;
306 case 0x3c8:
307 s->dac_write_index = val;
308 s->dac_sub_index = 0;
309 s->dac_state = 0;
310 break;
311 case 0x3c9:
312 s->dac_cache[s->dac_sub_index] = val;
313 if (++s->dac_sub_index == 3) {
314 memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
315 s->dac_sub_index = 0;
316 s->dac_write_index++;
317 }
318 break;
319 case 0x3ce:
320 s->gr_index = val & 0x0f;
321 break;
322 case 0x3cf:
323 #ifdef DEBUG_VGA_REG
324 printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
325 #endif
326 s->gr[s->gr_index] = val & gr_mask[s->gr_index];
327 break;
328 case 0x3b4:
329 case 0x3d4:
330 s->cr_index = val;
331 break;
332 case 0x3b5:
333 case 0x3d5:
334 #ifdef DEBUG_VGA_REG
335 printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
336 #endif
337 /* handle CR0-7 protection */
338 if ((s->cr[0x11] & 0x80) && s->cr_index <= 7) {
339 /* can always write bit 4 of CR7 */
340 if (s->cr_index == 7)
341 s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
342 return;
343 }
344 switch(s->cr_index) {
345 case 0x01: /* horizontal display end */
346 case 0x07:
347 case 0x09:
348 case 0x0c:
349 case 0x0d:
350 case 0x12: /* veritcal display end */
351 s->cr[s->cr_index] = val;
352 break;
353 default:
354 s->cr[s->cr_index] = val;
355 break;
356 }
357 break;
358 case 0x3ba:
359 case 0x3da:
360 s->fcr = val & 0x10;
361 break;
362 }
363 }
365 #ifdef CONFIG_BOCHS_VBE
366 static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
367 {
368 VGAState *s = opaque;
369 uint32_t val;
370 val = s->vbe_index;
371 return val;
372 }
374 static uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr)
375 {
376 VGAState *s = opaque;
377 uint32_t val;
379 if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
380 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_GETCAPS) {
381 switch(s->vbe_index) {
382 /* XXX: do not hardcode ? */
383 case VBE_DISPI_INDEX_XRES:
384 val = VBE_DISPI_MAX_XRES;
385 break;
386 case VBE_DISPI_INDEX_YRES:
387 val = VBE_DISPI_MAX_YRES;
388 break;
389 case VBE_DISPI_INDEX_BPP:
390 val = VBE_DISPI_MAX_BPP;
391 break;
392 default:
393 val = s->vbe_regs[s->vbe_index];
394 break;
395 }
396 } else {
397 val = s->vbe_regs[s->vbe_index];
398 }
399 } else {
400 val = 0;
401 }
402 #ifdef DEBUG_BOCHS_VBE
403 printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val);
404 #endif
405 return val;
406 }
408 static void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val)
409 {
410 VGAState *s = opaque;
411 s->vbe_index = val;
412 }
414 static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
415 {
416 VGAState *s = opaque;
418 if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
419 #ifdef DEBUG_BOCHS_VBE
420 printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val);
421 #endif
422 switch(s->vbe_index) {
423 case VBE_DISPI_INDEX_ID:
424 if (val == VBE_DISPI_ID0 ||
425 val == VBE_DISPI_ID1 ||
426 val == VBE_DISPI_ID2 ||
427 val == VBE_DISPI_ID3 ||
428 val == VBE_DISPI_ID4) {
429 s->vbe_regs[s->vbe_index] = val;
430 }
431 break;
432 case VBE_DISPI_INDEX_XRES:
433 if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) {
434 s->vbe_regs[s->vbe_index] = val;
435 }
436 break;
437 case VBE_DISPI_INDEX_YRES:
438 if (val <= VBE_DISPI_MAX_YRES) {
439 s->vbe_regs[s->vbe_index] = val;
440 }
441 break;
442 case VBE_DISPI_INDEX_BPP:
443 if (val == 0)
444 val = 8;
445 if (val == 4 || val == 8 || val == 15 ||
446 val == 16 || val == 24 || val == 32) {
447 s->vbe_regs[s->vbe_index] = val;
448 }
449 break;
450 case VBE_DISPI_INDEX_BANK:
451 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
452 val &= (s->vbe_bank_mask >> 2);
453 } else {
454 val &= s->vbe_bank_mask;
455 }
456 s->vbe_regs[s->vbe_index] = val;
457 s->bank_offset = (val << 16);
458 break;
459 case VBE_DISPI_INDEX_ENABLE:
460 if ((val & VBE_DISPI_ENABLED) &&
461 !(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
462 int h, shift_control;
464 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] =
465 s->vbe_regs[VBE_DISPI_INDEX_XRES];
466 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] =
467 s->vbe_regs[VBE_DISPI_INDEX_YRES];
468 s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
469 s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
471 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
472 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1;
473 else
474 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] *
475 ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
476 s->vbe_start_addr = 0;
478 /* clear the screen (should be done in BIOS) */
479 if (!(val & VBE_DISPI_NOCLEARMEM)) {
480 memset(s->vram_ptr, 0,
481 s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
482 }
484 /* we initialize the VGA graphic mode (should be done
485 in BIOS) */
486 s->gr[0x06] = (s->gr[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
487 s->cr[0x17] |= 3; /* no CGA modes */
488 s->cr[0x13] = s->vbe_line_offset >> 3;
489 /* width */
490 s->cr[0x01] = (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
491 /* height (only meaningful if < 1024) */
492 h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
493 s->cr[0x12] = h;
494 s->cr[0x07] = (s->cr[0x07] & ~0x42) |
495 ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
496 /* line compare to 1023 */
497 s->cr[0x18] = 0xff;
498 s->cr[0x07] |= 0x10;
499 s->cr[0x09] |= 0x40;
501 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
502 shift_control = 0;
503 s->sr[0x01] &= ~8; /* no double line */
504 } else {
505 shift_control = 2;
506 s->sr[4] |= 0x08; /* set chain 4 mode */
507 s->sr[2] |= 0x0f; /* activate all planes */
508 }
509 s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5);
510 s->cr[0x09] &= ~0x9f; /* no double scan */
511 } else {
512 /* XXX: the bios should do that */
513 s->bank_offset = 0;
514 }
515 s->dac_8bit = (val & VBE_DISPI_8BIT_DAC) > 0;
516 s->vbe_regs[s->vbe_index] = val;
517 break;
518 case VBE_DISPI_INDEX_VIRT_WIDTH:
519 {
520 int w, h, line_offset;
522 if (val < s->vbe_regs[VBE_DISPI_INDEX_XRES])
523 return;
524 w = val;
525 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
526 line_offset = w >> 1;
527 else
528 line_offset = w * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
529 h = s->vram_size / line_offset;
530 /* XXX: support weird bochs semantics ? */
531 if (h < s->vbe_regs[VBE_DISPI_INDEX_YRES])
532 return;
533 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = w;
534 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h;
535 s->vbe_line_offset = line_offset;
536 }
537 break;
538 case VBE_DISPI_INDEX_X_OFFSET:
539 case VBE_DISPI_INDEX_Y_OFFSET:
540 {
541 int x;
542 s->vbe_regs[s->vbe_index] = val;
543 s->vbe_start_addr = s->vbe_line_offset * s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET];
544 x = s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET];
545 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
546 s->vbe_start_addr += x >> 1;
547 else
548 s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
549 s->vbe_start_addr >>= 2;
550 }
551 break;
552 default:
553 break;
554 }
555 }
556 }
557 #endif
559 /* called for accesses between 0xa0000 and 0xc0000 */
560 uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr)
561 {
562 VGAState *s = opaque;
563 int memory_map_mode, plane;
564 uint32_t ret;
566 /* convert to VGA memory offset */
567 memory_map_mode = (s->gr[6] >> 2) & 3;
568 addr &= 0x1ffff;
569 switch(memory_map_mode) {
570 case 0:
571 break;
572 case 1:
573 if (addr >= 0x10000)
574 return 0xff;
575 addr += s->bank_offset;
576 break;
577 case 2:
578 addr -= 0x10000;
579 if (addr >= 0x8000)
580 return 0xff;
581 break;
582 default:
583 case 3:
584 addr -= 0x18000;
585 if (addr >= 0x8000)
586 return 0xff;
587 break;
588 }
590 if (s->sr[4] & 0x08) {
591 /* chain 4 mode : simplest access */
592 ret = s->vram_ptr[addr];
593 } else if (s->gr[5] & 0x10) {
594 /* odd/even mode (aka text mode mapping) */
595 plane = (s->gr[4] & 2) | (addr & 1);
596 ret = s->vram_ptr[((addr & ~1) << 1) | plane];
597 } else {
598 /* standard VGA latched access */
599 s->latch = ((uint32_t *)s->vram_ptr)[addr];
601 if (!(s->gr[5] & 0x08)) {
602 /* read mode 0 */
603 plane = s->gr[4];
604 ret = GET_PLANE(s->latch, plane);
605 } else {
606 /* read mode 1 */
607 ret = (s->latch ^ mask16[s->gr[2]]) & mask16[s->gr[7]];
608 ret |= ret >> 16;
609 ret |= ret >> 8;
610 ret = (~ret) & 0xff;
611 }
612 }
613 return ret;
614 }
616 static uint32_t vga_mem_readw(void *opaque, target_phys_addr_t addr)
617 {
618 uint32_t v;
619 #ifdef TARGET_WORDS_BIGENDIAN
620 v = vga_mem_readb(opaque, addr) << 8;
621 v |= vga_mem_readb(opaque, addr + 1);
622 #else
623 v = vga_mem_readb(opaque, addr);
624 v |= vga_mem_readb(opaque, addr + 1) << 8;
625 #endif
626 return v;
627 }
629 static uint32_t vga_mem_readl(void *opaque, target_phys_addr_t addr)
630 {
631 uint32_t v;
632 #ifdef TARGET_WORDS_BIGENDIAN
633 v = vga_mem_readb(opaque, addr) << 24;
634 v |= vga_mem_readb(opaque, addr + 1) << 16;
635 v |= vga_mem_readb(opaque, addr + 2) << 8;
636 v |= vga_mem_readb(opaque, addr + 3);
637 #else
638 v = vga_mem_readb(opaque, addr);
639 v |= vga_mem_readb(opaque, addr + 1) << 8;
640 v |= vga_mem_readb(opaque, addr + 2) << 16;
641 v |= vga_mem_readb(opaque, addr + 3) << 24;
642 #endif
643 return v;
644 }
646 /* called for accesses between 0xa0000 and 0xc0000 */
647 void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
648 {
649 VGAState *s = opaque;
650 int memory_map_mode, plane, write_mode, b, func_select, mask;
651 uint32_t write_mask, bit_mask, set_mask;
653 #ifdef DEBUG_VGA_MEM
654 printf("vga: [0x%x] = 0x%02x\n", addr, val);
655 #endif
656 /* convert to VGA memory offset */
657 memory_map_mode = (s->gr[6] >> 2) & 3;
658 addr &= 0x1ffff;
659 switch(memory_map_mode) {
660 case 0:
661 break;
662 case 1:
663 if (addr >= 0x10000)
664 return;
665 addr += s->bank_offset;
666 break;
667 case 2:
668 addr -= 0x10000;
669 if (addr >= 0x8000)
670 return;
671 break;
672 default:
673 case 3:
674 addr -= 0x18000;
675 if (addr >= 0x8000)
676 return;
677 break;
678 }
680 if (s->sr[4] & 0x08) {
681 /* chain 4 mode : simplest access */
682 plane = addr & 3;
683 mask = (1 << plane);
684 if (s->sr[2] & mask) {
685 s->vram_ptr[addr] = val;
686 #ifdef DEBUG_VGA_MEM
687 printf("vga: chain4: [0x%x]\n", addr);
688 #endif
689 s->plane_updated |= mask; /* only used to detect font change */
690 cpu_physical_memory_set_dirty(s->vram_offset + addr);
691 }
692 } else if (s->gr[5] & 0x10) {
693 /* odd/even mode (aka text mode mapping) */
694 plane = (s->gr[4] & 2) | (addr & 1);
695 mask = (1 << plane);
696 if (s->sr[2] & mask) {
697 addr = ((addr & ~1) << 1) | plane;
698 s->vram_ptr[addr] = val;
699 #ifdef DEBUG_VGA_MEM
700 printf("vga: odd/even: [0x%x]\n", addr);
701 #endif
702 s->plane_updated |= mask; /* only used to detect font change */
703 cpu_physical_memory_set_dirty(s->vram_offset + addr);
704 }
705 } else {
706 /* standard VGA latched access */
707 write_mode = s->gr[5] & 3;
708 switch(write_mode) {
709 default:
710 case 0:
711 /* rotate */
712 b = s->gr[3] & 7;
713 val = ((val >> b) | (val << (8 - b))) & 0xff;
714 val |= val << 8;
715 val |= val << 16;
717 /* apply set/reset mask */
718 set_mask = mask16[s->gr[1]];
719 val = (val & ~set_mask) | (mask16[s->gr[0]] & set_mask);
720 bit_mask = s->gr[8];
721 break;
722 case 1:
723 val = s->latch;
724 goto do_write;
725 case 2:
726 val = mask16[val & 0x0f];
727 bit_mask = s->gr[8];
728 break;
729 case 3:
730 /* rotate */
731 b = s->gr[3] & 7;
732 val = (val >> b) | (val << (8 - b));
734 bit_mask = s->gr[8] & val;
735 val = mask16[s->gr[0]];
736 break;
737 }
739 /* apply logical operation */
740 func_select = s->gr[3] >> 3;
741 switch(func_select) {
742 case 0:
743 default:
744 /* nothing to do */
745 break;
746 case 1:
747 /* and */
748 val &= s->latch;
749 break;
750 case 2:
751 /* or */
752 val |= s->latch;
753 break;
754 case 3:
755 /* xor */
756 val ^= s->latch;
757 break;
758 }
760 /* apply bit mask */
761 bit_mask |= bit_mask << 8;
762 bit_mask |= bit_mask << 16;
763 val = (val & bit_mask) | (s->latch & ~bit_mask);
765 do_write:
766 /* mask data according to sr[2] */
767 mask = s->sr[2];
768 s->plane_updated |= mask; /* only used to detect font change */
769 write_mask = mask16[mask];
770 ((uint32_t *)s->vram_ptr)[addr] =
771 (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
772 (val & write_mask);
773 #ifdef DEBUG_VGA_MEM
774 printf("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n",
775 addr * 4, write_mask, val);
776 #endif
777 cpu_physical_memory_set_dirty(s->vram_offset + (addr << 2));
778 }
779 }
781 static void vga_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
782 {
783 #ifdef TARGET_WORDS_BIGENDIAN
784 vga_mem_writeb(opaque, addr, (val >> 8) & 0xff);
785 vga_mem_writeb(opaque, addr + 1, val & 0xff);
786 #else
787 vga_mem_writeb(opaque, addr, val & 0xff);
788 vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
789 #endif
790 }
792 static void vga_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
793 {
794 #ifdef TARGET_WORDS_BIGENDIAN
795 vga_mem_writeb(opaque, addr, (val >> 24) & 0xff);
796 vga_mem_writeb(opaque, addr + 1, (val >> 16) & 0xff);
797 vga_mem_writeb(opaque, addr + 2, (val >> 8) & 0xff);
798 vga_mem_writeb(opaque, addr + 3, val & 0xff);
799 #else
800 vga_mem_writeb(opaque, addr, val & 0xff);
801 vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
802 vga_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff);
803 vga_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff);
804 #endif
805 }
807 typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
808 const uint8_t *font_ptr, int h,
809 uint32_t fgcol, uint32_t bgcol);
810 typedef void vga_draw_glyph9_func(uint8_t *d, int linesize,
811 const uint8_t *font_ptr, int h,
812 uint32_t fgcol, uint32_t bgcol, int dup9);
813 typedef void vga_draw_line_func(VGAState *s1, uint8_t *d,
814 const uint8_t *s, int width);
816 static inline unsigned int rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b)
817 {
818 return ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6);
819 }
821 static inline unsigned int rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b)
822 {
823 return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
824 }
826 static inline unsigned int rgb_to_pixel16(unsigned int r, unsigned int g, unsigned b)
827 {
828 return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
829 }
831 static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b)
832 {
833 return (r << 16) | (g << 8) | b;
834 }
836 static inline unsigned int rgb_to_pixel32bgr(unsigned int r, unsigned int g, unsigned b)
837 {
838 return (b << 16) | (g << 8) | r;
839 }
841 #define DEPTH 8
842 #include "vga_template.h"
844 #define DEPTH 15
845 #include "vga_template.h"
847 #define DEPTH 16
848 #include "vga_template.h"
850 #define DEPTH 32
851 #include "vga_template.h"
853 #define BGR_FORMAT
854 #define DEPTH 32
855 #include "vga_template.h"
857 static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
858 {
859 unsigned int col;
860 col = rgb_to_pixel8(r, g, b);
861 col |= col << 8;
862 col |= col << 16;
863 return col;
864 }
866 static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b)
867 {
868 unsigned int col;
869 col = rgb_to_pixel15(r, g, b);
870 col |= col << 16;
871 return col;
872 }
874 static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
875 {
876 unsigned int col;
877 col = rgb_to_pixel16(r, g, b);
878 col |= col << 16;
879 return col;
880 }
882 static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
883 {
884 unsigned int col;
885 col = rgb_to_pixel32(r, g, b);
886 return col;
887 }
889 static unsigned int rgb_to_pixel32bgr_dup(unsigned int r, unsigned int g, unsigned b)
890 {
891 unsigned int col;
892 col = rgb_to_pixel32bgr(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 if (s->dac_8bit) {
933 col = s->rgb_to_pixel(s->palette[v],
934 s->palette[v + 1],
935 s->palette[v + 2]);
936 } else {
937 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
938 c6_to_8(s->palette[v + 1]),
939 c6_to_8(s->palette[v + 2]));
940 }
941 if (col != palette[i]) {
942 full_update = 1;
943 palette[i] = col;
944 }
945 v += 3;
946 }
947 return full_update;
948 }
950 static void vga_get_offsets(VGAState *s,
951 uint32_t *pline_offset,
952 uint32_t *pstart_addr,
953 uint32_t *pline_compare)
954 {
955 uint32_t start_addr, line_offset, line_compare;
956 #ifdef CONFIG_BOCHS_VBE
957 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
958 line_offset = s->vbe_line_offset;
959 start_addr = s->vbe_start_addr;
960 line_compare = 65535;
961 } else
962 #endif
963 {
964 /* compute line_offset in bytes */
965 line_offset = s->cr[0x13];
966 line_offset <<= 3;
968 /* starting address */
969 start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8);
971 /* line compare */
972 line_compare = s->cr[0x18] |
973 ((s->cr[0x07] & 0x10) << 4) |
974 ((s->cr[0x09] & 0x40) << 3);
975 }
976 *pline_offset = line_offset;
977 *pstart_addr = start_addr;
978 *pline_compare = line_compare;
979 }
981 /* update start_addr and line_offset. Return TRUE if modified */
982 static int update_basic_params(VGAState *s)
983 {
984 int full_update;
985 uint32_t start_addr, line_offset, line_compare;
987 full_update = 0;
989 s->get_offsets(s, &line_offset, &start_addr, &line_compare);
991 if (line_offset != s->line_offset ||
992 start_addr != s->start_addr ||
993 line_compare != s->line_compare) {
994 s->line_offset = line_offset;
995 s->start_addr = start_addr;
996 s->line_compare = line_compare;
997 full_update = 1;
998 }
999 return full_update;
1002 #define NB_DEPTHS 5
1004 static inline int get_depth_index(DisplayState *s)
1006 switch(s->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 if (s->bgr)
1016 return 4;
1017 else
1018 return 3;
1022 static vga_draw_glyph8_func *vga_draw_glyph8_table[NB_DEPTHS] = {
1023 vga_draw_glyph8_8,
1024 vga_draw_glyph8_16,
1025 vga_draw_glyph8_16,
1026 vga_draw_glyph8_32,
1027 vga_draw_glyph8_32,
1028 };
1030 static vga_draw_glyph8_func *vga_draw_glyph16_table[NB_DEPTHS] = {
1031 vga_draw_glyph16_8,
1032 vga_draw_glyph16_16,
1033 vga_draw_glyph16_16,
1034 vga_draw_glyph16_32,
1035 vga_draw_glyph16_32,
1036 };
1038 static vga_draw_glyph9_func *vga_draw_glyph9_table[NB_DEPTHS] = {
1039 vga_draw_glyph9_8,
1040 vga_draw_glyph9_16,
1041 vga_draw_glyph9_16,
1042 vga_draw_glyph9_32,
1043 vga_draw_glyph9_32,
1044 };
1046 static const uint8_t cursor_glyph[32 * 4] = {
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 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1063 };
1065 typedef unsigned int rgb_to_pixel_dup_func(unsigned int r, unsigned int g, unsigned b);
1067 static rgb_to_pixel_dup_func *rgb_to_pixel_dup_table[NB_DEPTHS];
1069 /*
1070 * Text mode update
1071 * Missing:
1072 * - double scan
1073 * - double width
1074 * - underline
1075 * - flashing
1076 */
1077 static void vga_draw_text(VGAState *s, int full_update)
1079 int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
1080 int cx_min, cx_max, linesize, x_incr;
1081 uint32_t offset, fgcol, bgcol, v, cursor_offset;
1082 uint8_t *d1, *d, *src, *s1, *dest, *cursor_ptr;
1083 const uint8_t *font_ptr, *font_base[2];
1084 int dup9, line_offset, depth_index;
1085 uint32_t *palette;
1086 uint32_t *ch_attr_ptr;
1087 vga_draw_glyph8_func *vga_draw_glyph8;
1088 vga_draw_glyph9_func *vga_draw_glyph9;
1090 /* Disable dirty bit tracking */
1091 xc_hvm_track_dirty_vram(xc_handle, domid, 0, 0, NULL);
1093 /* total width & height */
1094 cheight = (s->cr[9] & 0x1f) + 1;
1095 cw = 8;
1096 if (!(s->sr[1] & 0x01))
1097 cw = 9;
1098 if (s->sr[1] & 0x08)
1099 cw = 16; /* NOTE: no 18 pixel wide */
1100 width = (s->cr[0x01] + 1);
1101 if (s->cr[0x06] == 100) {
1102 /* ugly hack for CGA 160x100x16 - explain me the logic */
1103 height = 100;
1104 } else {
1105 height = s->cr[0x12] |
1106 ((s->cr[0x07] & 0x02) << 7) |
1107 ((s->cr[0x07] & 0x40) << 3);
1108 height = (height + 1) / cheight;
1110 if ((height * width) > CH_ATTR_SIZE) {
1111 /* better than nothing: exit if transient size is too big */
1112 return;
1115 s->last_scr_width = width * cw;
1116 s->last_scr_height = height * cheight;
1117 if (width != s->last_width || height != s->last_height ||
1118 cw != s->last_cw || cheight != s->last_ch || s->last_depth) {
1119 dpy_resize(s->ds, s->last_scr_width, s->last_scr_height);
1120 s->last_depth = 0;
1121 full_update = 1;
1123 s->last_width = width;
1124 s->last_height = height;
1125 s->last_ch = cheight;
1126 s->last_cw = cw;
1128 s->rgb_to_pixel =
1129 rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1131 full_update |= update_palette16(s);
1132 palette = s->last_palette;
1134 x_incr = cw * ((s->ds->depth + 7) >> 3);
1135 /* compute font data address (in plane 2) */
1136 v = s->sr[3];
1137 offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
1138 if (offset != s->font_offsets[0]) {
1139 s->font_offsets[0] = offset;
1140 full_update = 1;
1142 font_base[0] = s->vram_ptr + offset;
1144 offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
1145 font_base[1] = s->vram_ptr + offset;
1146 if (offset != s->font_offsets[1]) {
1147 s->font_offsets[1] = offset;
1148 full_update = 1;
1150 if (s->plane_updated & (1 << 2)) {
1151 /* if the plane 2 was modified since the last display, it
1152 indicates the font may have been modified */
1153 s->plane_updated = 0;
1154 full_update = 1;
1156 full_update |= update_basic_params(s);
1158 line_offset = s->line_offset;
1159 s1 = s->vram_ptr + (s->start_addr * 4);
1161 cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
1162 if (cursor_offset != s->cursor_offset ||
1163 s->cr[0xa] != s->cursor_start ||
1164 s->cr[0xb] != s->cursor_end) {
1165 /* if the cursor position changed, we update the old and new
1166 chars */
1167 if (s->cursor_offset < CH_ATTR_SIZE)
1168 s->last_ch_attr[s->cursor_offset] = -1;
1169 if (cursor_offset < CH_ATTR_SIZE)
1170 s->last_ch_attr[cursor_offset] = -1;
1171 s->cursor_offset = cursor_offset;
1172 s->cursor_start = s->cr[0xa];
1173 s->cursor_end = s->cr[0xb];
1175 cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
1177 depth_index = get_depth_index(s->ds);
1178 if (cw == 16)
1179 vga_draw_glyph8 = vga_draw_glyph16_table[depth_index];
1180 else
1181 vga_draw_glyph8 = vga_draw_glyph8_table[depth_index];
1182 vga_draw_glyph9 = vga_draw_glyph9_table[depth_index];
1184 dest = s->ds->data;
1185 linesize = s->ds->linesize;
1186 ch_attr_ptr = s->last_ch_attr;
1187 for(cy = 0; cy < height; cy++) {
1188 d1 = dest;
1189 src = s1;
1190 cx_min = width;
1191 cx_max = -1;
1192 for(cx = 0; cx < width; cx++) {
1193 ch_attr = *(uint16_t *)src;
1194 if (full_update || ch_attr != *ch_attr_ptr) {
1195 if (cx < cx_min)
1196 cx_min = cx;
1197 if (cx > cx_max)
1198 cx_max = cx;
1199 *ch_attr_ptr = ch_attr;
1200 #ifdef WORDS_BIGENDIAN
1201 ch = ch_attr >> 8;
1202 cattr = ch_attr & 0xff;
1203 #else
1204 ch = ch_attr & 0xff;
1205 cattr = ch_attr >> 8;
1206 #endif
1207 font_ptr = font_base[(cattr >> 3) & 1];
1208 font_ptr += 32 * 4 * ch;
1209 bgcol = palette[cattr >> 4];
1210 fgcol = palette[cattr & 0x0f];
1211 if (cw != 9) {
1212 vga_draw_glyph8(d1, linesize,
1213 font_ptr, cheight, fgcol, bgcol);
1214 } else {
1215 dup9 = 0;
1216 if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))
1217 dup9 = 1;
1218 vga_draw_glyph9(d1, linesize,
1219 font_ptr, cheight, fgcol, bgcol, dup9);
1221 if (src == cursor_ptr &&
1222 !(s->cr[0x0a] & 0x20)) {
1223 int line_start, line_last, h;
1224 /* draw the cursor */
1225 line_start = s->cr[0x0a] & 0x1f;
1226 line_last = s->cr[0x0b] & 0x1f;
1227 /* XXX: check that */
1228 if (line_last > cheight - 1)
1229 line_last = cheight - 1;
1230 if (line_last >= line_start && line_start < cheight) {
1231 h = line_last - line_start + 1;
1232 d = d1 + linesize * line_start;
1233 if (cw != 9) {
1234 vga_draw_glyph8(d, linesize,
1235 cursor_glyph, h, fgcol, bgcol);
1236 } else {
1237 vga_draw_glyph9(d, linesize,
1238 cursor_glyph, h, fgcol, bgcol, 1);
1243 d1 += x_incr;
1244 src += 4;
1245 ch_attr_ptr++;
1247 if (cx_max != -1) {
1248 dpy_update(s->ds, cx_min * cw, cy * cheight,
1249 (cx_max - cx_min + 1) * cw, cheight);
1251 dest += linesize * cheight;
1252 s1 += line_offset;
1256 enum {
1257 VGA_DRAW_LINE2,
1258 VGA_DRAW_LINE2D2,
1259 VGA_DRAW_LINE4,
1260 VGA_DRAW_LINE4D2,
1261 VGA_DRAW_LINE8D2,
1262 VGA_DRAW_LINE8,
1263 VGA_DRAW_LINE15,
1264 VGA_DRAW_LINE16,
1265 VGA_DRAW_LINE24,
1266 VGA_DRAW_LINE32,
1267 VGA_DRAW_LINE_NB,
1268 };
1270 static vga_draw_line_func *vga_draw_line_table[NB_DEPTHS * VGA_DRAW_LINE_NB] = {
1271 vga_draw_line2_8,
1272 vga_draw_line2_16,
1273 vga_draw_line2_16,
1274 vga_draw_line2_32,
1275 vga_draw_line2_32,
1277 vga_draw_line2d2_8,
1278 vga_draw_line2d2_16,
1279 vga_draw_line2d2_16,
1280 vga_draw_line2d2_32,
1281 vga_draw_line2d2_32,
1283 vga_draw_line4_8,
1284 vga_draw_line4_16,
1285 vga_draw_line4_16,
1286 vga_draw_line4_32,
1287 vga_draw_line4_32,
1289 vga_draw_line4d2_8,
1290 vga_draw_line4d2_16,
1291 vga_draw_line4d2_16,
1292 vga_draw_line4d2_32,
1293 vga_draw_line4d2_32,
1295 vga_draw_line8d2_8,
1296 vga_draw_line8d2_16,
1297 vga_draw_line8d2_16,
1298 vga_draw_line8d2_32,
1299 vga_draw_line8d2_32,
1301 vga_draw_line8_8,
1302 vga_draw_line8_16,
1303 vga_draw_line8_16,
1304 vga_draw_line8_32,
1305 vga_draw_line8_32,
1307 vga_draw_line15_8,
1308 vga_draw_line15_15,
1309 vga_draw_line15_16,
1310 vga_draw_line15_32,
1311 vga_draw_line15_32bgr,
1313 vga_draw_line16_8,
1314 vga_draw_line16_15,
1315 vga_draw_line16_16,
1316 vga_draw_line16_32,
1317 vga_draw_line16_32bgr,
1319 vga_draw_line24_8,
1320 vga_draw_line24_15,
1321 vga_draw_line24_16,
1322 vga_draw_line24_32,
1323 vga_draw_line24_32bgr,
1325 vga_draw_line32_8,
1326 vga_draw_line32_15,
1327 vga_draw_line32_16,
1328 vga_draw_line32_32,
1329 vga_draw_line32_32bgr,
1330 };
1332 static rgb_to_pixel_dup_func *rgb_to_pixel_dup_table[NB_DEPTHS] = {
1333 rgb_to_pixel8_dup,
1334 rgb_to_pixel15_dup,
1335 rgb_to_pixel16_dup,
1336 rgb_to_pixel32_dup,
1337 rgb_to_pixel32bgr_dup,
1338 };
1340 static int vga_get_bpp(VGAState *s)
1342 int ret;
1343 #ifdef CONFIG_BOCHS_VBE
1344 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1345 ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
1346 } else
1347 #endif
1349 ret = 0;
1351 return ret;
1354 static void vga_get_resolution(VGAState *s, int *pwidth, int *pheight)
1356 int width, height;
1358 #ifdef CONFIG_BOCHS_VBE
1359 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1360 width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
1361 height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
1362 } else
1363 #endif
1365 width = (s->cr[0x01] + 1) * 8;
1366 height = s->cr[0x12] |
1367 ((s->cr[0x07] & 0x02) << 7) |
1368 ((s->cr[0x07] & 0x40) << 3);
1369 height = (height + 1);
1371 *pwidth = width;
1372 *pheight = height;
1375 void vga_invalidate_scanlines(VGAState *s, int y1, int y2)
1377 int y;
1378 if (y1 >= VGA_MAX_HEIGHT)
1379 return;
1380 if (y2 >= VGA_MAX_HEIGHT)
1381 y2 = VGA_MAX_HEIGHT;
1382 for(y = y1; y < y2; y++) {
1383 s->invalidated_y_table[y >> 5] |= 1 << (y & 0x1f);
1387 /*
1388 * graphic modes
1389 */
1390 static void vga_draw_graphic(VGAState *s, int full_update)
1392 int y1, y, update, linesize, y_start, double_scan, mask, depth;
1393 int width, height, shift_control, line_offset, bwidth, ds_depth, bits;
1394 ram_addr_t page0, page1;
1395 int disp_width, multi_scan, multi_run;
1396 uint8_t *d;
1397 uint32_t v, addr1, addr;
1398 vga_draw_line_func *vga_draw_line;
1399 ram_addr_t page_min, page_max;
1400 unsigned long start, end;
1402 full_update |= update_basic_params(s);
1404 s->get_resolution(s, &width, &height);
1405 disp_width = width;
1407 shift_control = (s->gr[0x05] >> 5) & 3;
1408 double_scan = (s->cr[0x09] >> 7);
1409 if (shift_control != 1) {
1410 multi_scan = (((s->cr[0x09] & 0x1f) + 1) << double_scan) - 1;
1411 } else {
1412 /* in CGA modes, multi_scan is ignored */
1413 /* XXX: is it correct ? */
1414 multi_scan = double_scan;
1416 multi_run = multi_scan;
1417 if (shift_control != s->shift_control ||
1418 double_scan != s->double_scan) {
1419 full_update = 1;
1420 s->shift_control = shift_control;
1421 s->double_scan = double_scan;
1423 if (shift_control == 1 && (s->sr[0x01] & 8)) {
1424 disp_width <<= 1;
1427 ds_depth = s->ds->depth;
1428 depth = s->get_bpp(s);
1429 if (s->ds->dpy_resize_shared) {
1430 if (s->line_offset != s->last_line_offset ||
1431 disp_width != s->last_width ||
1432 height != s->last_height ||
1433 s->last_depth != depth) {
1434 dpy_resize_shared(s->ds, disp_width, height, depth, s->line_offset, s->vram_ptr + (s->start_addr * 4));
1435 s->last_scr_width = disp_width;
1436 s->last_scr_height = height;
1437 s->last_width = disp_width;
1438 s->last_height = height;
1439 s->last_line_offset = s->line_offset;
1440 s->last_depth = depth;
1441 full_update = 1;
1442 } else if (s->ds->shared_buf && (full_update || s->ds->data != s->vram_ptr + (s->start_addr * 4)))
1443 s->ds->dpy_setdata(s->ds, s->vram_ptr + (s->start_addr * 4));
1444 } else if (disp_width != s->last_width ||
1445 height != s->last_height) {
1446 dpy_resize(s->ds, disp_width, height);
1447 s->last_scr_width = disp_width;
1448 s->last_scr_height = height;
1449 s->last_width = disp_width;
1450 s->last_height = height;
1451 full_update = 1;
1454 s->rgb_to_pixel =
1455 rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1457 if (shift_control == 0) {
1458 full_update |= update_palette16(s);
1459 if (s->sr[0x01] & 8) {
1460 v = VGA_DRAW_LINE4D2;
1461 } else {
1462 v = VGA_DRAW_LINE4;
1464 bits = 4;
1465 } else if (shift_control == 1) {
1466 full_update |= update_palette16(s);
1467 if (s->sr[0x01] & 8) {
1468 v = VGA_DRAW_LINE2D2;
1469 } else {
1470 v = VGA_DRAW_LINE2;
1472 bits = 4;
1473 } else {
1474 switch(s->get_bpp(s)) {
1475 default:
1476 case 0:
1477 full_update |= update_palette256(s);
1478 v = VGA_DRAW_LINE8D2;
1479 bits = 4;
1480 break;
1481 case 8:
1482 full_update |= update_palette256(s);
1483 v = VGA_DRAW_LINE8;
1484 bits = 8;
1485 break;
1486 case 15:
1487 v = VGA_DRAW_LINE15;
1488 bits = 16;
1489 break;
1490 case 16:
1491 v = VGA_DRAW_LINE16;
1492 bits = 16;
1493 break;
1494 case 24:
1495 v = VGA_DRAW_LINE24;
1496 bits = 24;
1497 break;
1498 case 32:
1499 v = VGA_DRAW_LINE32;
1500 bits = 32;
1501 break;
1505 vga_draw_line = vga_draw_line_table[v * NB_DEPTHS + get_depth_index(s->ds)];
1506 if (!s->ds->shared_buf && s->cursor_invalidate)
1507 s->cursor_invalidate(s);
1509 line_offset = s->line_offset;
1510 #if 0
1511 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",
1512 width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]);
1513 #endif
1515 if (s->lfb_addr) {
1516 if (height - 1 > s->line_compare || multi_run || (s->cr[0x17] & 3) != 3) {
1517 /* Tricky things happen, just track all video memory */
1518 start = 0;
1519 end = s->vram_size;
1520 } else {
1521 /* Tricky things won't have any effect, i.e. we are in the very simple
1522 * (and very usual) case of a linear buffer. */
1523 /* use page table dirty bit tracking for the LFB plus border */
1524 start = (s->start_addr * 4) & TARGET_PAGE_MASK;
1525 end = ((s->start_addr * 4 + height * line_offset) + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
1528 for (y = 0 ; y < start; y += TARGET_PAGE_SIZE)
1529 /* We will not read that anyway. */
1530 cpu_physical_memory_set_dirty(s->vram_offset + y);
1533 unsigned long npages = (end - y) / TARGET_PAGE_SIZE;
1534 const int width = sizeof(unsigned long) * 8;
1535 unsigned long bitmap[(npages + width - 1) / width];
1536 int err;
1538 if (!(err = xc_hvm_track_dirty_vram(xc_handle, domid,
1539 (s->lfb_addr + y) / TARGET_PAGE_SIZE, npages, bitmap))) {
1540 int i, j;
1541 for (i = 0; i < sizeof(bitmap) / sizeof(*bitmap); i++) {
1542 unsigned long map = bitmap[i];
1543 for (j = i * width; map && j < npages; map >>= 1, j++)
1544 if (map & 1)
1545 cpu_physical_memory_set_dirty(s->vram_offset + y
1546 + j * TARGET_PAGE_SIZE);
1548 y += npages * TARGET_PAGE_SIZE;
1549 } else {
1550 /* ENODATA just means we have changed mode and will succeed
1551 * next time */
1552 if (errno != ENODATA)
1553 fprintf(stderr, "track_dirty_vram(%lx, %lx) failed (%d, %d)\n", s->lfb_addr + y, npages, err, errno);
1557 for ( ; y < s->vram_size; y += TARGET_PAGE_SIZE)
1558 /* We will not read that anyway. */
1559 cpu_physical_memory_set_dirty(s->vram_offset + y);
1562 addr1 = (s->start_addr * 4);
1563 bwidth = (width * bits + 7) / 8;
1564 y_start = -1;
1565 page_min = 0;
1566 page_max = 0;
1567 d = s->ds->data;
1568 linesize = s->ds->linesize;
1569 y1 = 0;
1570 for(y = 0; y < height; y++) {
1571 addr = addr1;
1572 if (!(s->cr[0x17] & 1)) {
1573 int shift;
1574 /* CGA compatibility handling */
1575 shift = 14 + ((s->cr[0x17] >> 6) & 1);
1576 addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
1578 if (!(s->cr[0x17] & 2)) {
1579 addr = (addr & ~0x8000) | ((y1 & 2) << 14);
1581 page0 = s->vram_offset + (addr & TARGET_PAGE_MASK);
1582 page1 = s->vram_offset + ((addr + bwidth - 1) & TARGET_PAGE_MASK);
1583 update = full_update |
1584 cpu_physical_memory_get_dirty(page0, VGA_DIRTY_FLAG) |
1585 cpu_physical_memory_get_dirty(page1, VGA_DIRTY_FLAG);
1586 if ((page1 - page0) > TARGET_PAGE_SIZE) {
1587 /* if wide line, can use another page */
1588 update |= cpu_physical_memory_get_dirty(page0 + TARGET_PAGE_SIZE,
1589 VGA_DIRTY_FLAG);
1591 /* explicit invalidation for the hardware cursor */
1592 update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
1593 if (update) {
1594 if (y_start < 0)
1595 y_start = y;
1596 if (page_min == 0 || page0 < page_min)
1597 page_min = page0;
1598 if (page_max == 0 || page1 > page_max)
1599 page_max = page1;
1600 if (!s->ds->shared_buf) {
1601 vga_draw_line(s, d, s->vram_ptr + addr, width);
1602 if (s->cursor_draw_line)
1603 s->cursor_draw_line(s, d, y);
1605 } else {
1606 if (y_start >= 0) {
1607 /* flush to display */
1608 dpy_update(s->ds, 0, y_start,
1609 disp_width, y - y_start);
1610 y_start = -1;
1613 if (!multi_run) {
1614 mask = (s->cr[0x17] & 3) ^ 3;
1615 if ((y1 & mask) == mask)
1616 addr1 += line_offset;
1617 y1++;
1618 multi_run = multi_scan;
1619 } else {
1620 multi_run--;
1622 /* line compare acts on the displayed lines */
1623 if (y == s->line_compare)
1624 addr1 = 0;
1625 d += linesize;
1627 if (y_start >= 0) {
1628 /* flush to display */
1629 dpy_update(s->ds, 0, y_start,
1630 disp_width, y - y_start);
1632 /* reset modified pages */
1633 if (page_max != -1) {
1634 cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
1635 VGA_DIRTY_FLAG);
1637 memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
1640 static void vga_draw_blank(VGAState *s, int full_update)
1642 int i, w, val;
1643 uint8_t *d;
1645 if (!full_update)
1646 return;
1647 if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
1648 return;
1650 /* Disable dirty bit tracking */
1651 xc_hvm_track_dirty_vram(xc_handle, domid, 0, 0, NULL);
1653 s->rgb_to_pixel =
1654 rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1655 if (s->ds->depth == 8)
1656 val = s->rgb_to_pixel(0, 0, 0);
1657 else
1658 val = 0;
1659 w = s->last_scr_width * ((s->ds->depth + 7) >> 3);
1660 d = s->ds->data;
1661 for(i = 0; i < s->last_scr_height; i++) {
1662 memset(d, val, w);
1663 d += s->ds->linesize;
1665 dpy_update(s->ds, 0, 0,
1666 s->last_scr_width, s->last_scr_height);
1669 #define GMODE_TEXT 0
1670 #define GMODE_GRAPH 1
1671 #define GMODE_BLANK 2
1673 static void vga_update_display(void *opaque)
1675 VGAState *s = (VGAState *)opaque;
1676 int full_update, graphic_mode;
1678 if (s->ds->depth == 0) {
1679 /* nothing to do */
1680 } else {
1681 full_update = 0;
1682 if (!(s->ar_index & 0x20)) {
1683 graphic_mode = GMODE_BLANK;
1684 } else {
1685 graphic_mode = s->gr[6] & 1;
1687 if (graphic_mode != s->graphic_mode) {
1688 s->graphic_mode = graphic_mode;
1689 full_update = 1;
1691 switch(graphic_mode) {
1692 case GMODE_TEXT:
1693 vga_draw_text(s, full_update);
1694 break;
1695 case GMODE_GRAPH:
1696 vga_draw_graphic(s, full_update);
1697 break;
1698 case GMODE_BLANK:
1699 default:
1700 vga_draw_blank(s, full_update);
1701 break;
1706 /* force a full display refresh */
1707 static void vga_invalidate_display(void *opaque)
1709 VGAState *s = (VGAState *)opaque;
1711 s->last_width = -1;
1712 s->last_height = -1;
1715 static void vga_reset(VGAState *s)
1717 memset(s, 0, sizeof(VGAState));
1718 s->graphic_mode = -1; /* force full update */
1721 static CPUReadMemoryFunc *vga_mem_read[3] = {
1722 vga_mem_readb,
1723 vga_mem_readw,
1724 vga_mem_readl,
1725 };
1727 static CPUWriteMemoryFunc *vga_mem_write[3] = {
1728 vga_mem_writeb,
1729 vga_mem_writew,
1730 vga_mem_writel,
1731 };
1733 static void vga_save(QEMUFile *f, void *opaque)
1735 VGAState *s = opaque;
1736 uint32_t vram_size;
1737 #ifdef CONFIG_BOCHS_VBE
1738 int i;
1739 #endif
1741 if (s->pci_dev)
1742 pci_device_save(s->pci_dev, f);
1744 qemu_put_be32s(f, &s->latch);
1745 qemu_put_8s(f, &s->sr_index);
1746 qemu_put_buffer(f, s->sr, 8);
1747 qemu_put_8s(f, &s->gr_index);
1748 qemu_put_buffer(f, s->gr, 16);
1749 qemu_put_8s(f, &s->ar_index);
1750 qemu_put_buffer(f, s->ar, 21);
1751 qemu_put_be32s(f, &s->ar_flip_flop);
1752 qemu_put_8s(f, &s->cr_index);
1753 qemu_put_buffer(f, s->cr, 256);
1754 qemu_put_8s(f, &s->msr);
1755 qemu_put_8s(f, &s->fcr);
1756 qemu_put_8s(f, &s->st00);
1757 qemu_put_8s(f, &s->st01);
1759 qemu_put_8s(f, &s->dac_state);
1760 qemu_put_8s(f, &s->dac_sub_index);
1761 qemu_put_8s(f, &s->dac_read_index);
1762 qemu_put_8s(f, &s->dac_write_index);
1763 qemu_put_buffer(f, s->dac_cache, 3);
1764 qemu_put_buffer(f, s->palette, 768);
1766 qemu_put_be32s(f, &s->bank_offset);
1767 #ifdef CONFIG_BOCHS_VBE
1768 qemu_put_byte(f, 1);
1769 qemu_put_be16s(f, &s->vbe_index);
1770 for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
1771 qemu_put_be16s(f, &s->vbe_regs[i]);
1772 qemu_put_be32s(f, &s->vbe_start_addr);
1773 qemu_put_be32s(f, &s->vbe_line_offset);
1774 qemu_put_be32s(f, &s->vbe_bank_mask);
1775 #else
1776 qemu_put_byte(f, 0);
1777 #endif
1778 vram_size = s->vram_size;
1779 qemu_put_be32s(f, &vram_size);
1780 qemu_put_be64s(f, &s->stolen_vram_addr);
1781 if (!s->stolen_vram_addr)
1782 /* Old guest: VRAM is not mapped, we have to save it ourselves */
1783 qemu_put_buffer(f, s->vram_ptr, VGA_RAM_SIZE);
1786 static int vga_load(QEMUFile *f, void *opaque, int version_id)
1788 VGAState *s = opaque;
1789 int is_vbe, ret;
1790 uint32_t vram_size;
1791 #ifdef CONFIG_BOCHS_VBE
1792 int i;
1793 #endif
1795 if (version_id > 4)
1796 return -EINVAL;
1798 if (s->pci_dev && version_id >= 2) {
1799 ret = pci_device_load(s->pci_dev, f);
1800 if (ret < 0)
1801 return ret;
1804 qemu_get_be32s(f, &s->latch);
1805 qemu_get_8s(f, &s->sr_index);
1806 qemu_get_buffer(f, s->sr, 8);
1807 qemu_get_8s(f, &s->gr_index);
1808 qemu_get_buffer(f, s->gr, 16);
1809 qemu_get_8s(f, &s->ar_index);
1810 qemu_get_buffer(f, s->ar, 21);
1811 qemu_get_be32s(f, &s->ar_flip_flop);
1812 qemu_get_8s(f, &s->cr_index);
1813 qemu_get_buffer(f, s->cr, 256);
1814 qemu_get_8s(f, &s->msr);
1815 qemu_get_8s(f, &s->fcr);
1816 qemu_get_8s(f, &s->st00);
1817 qemu_get_8s(f, &s->st01);
1819 qemu_get_8s(f, &s->dac_state);
1820 qemu_get_8s(f, &s->dac_sub_index);
1821 qemu_get_8s(f, &s->dac_read_index);
1822 qemu_get_8s(f, &s->dac_write_index);
1823 qemu_get_buffer(f, s->dac_cache, 3);
1824 qemu_get_buffer(f, s->palette, 768);
1826 qemu_get_be32s(f, &s->bank_offset);
1827 is_vbe = qemu_get_byte(f);
1828 #ifdef CONFIG_BOCHS_VBE
1829 if (!is_vbe)
1830 return -EINVAL;
1831 qemu_get_be16s(f, &s->vbe_index);
1832 for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
1833 qemu_get_be16s(f, &s->vbe_regs[i]);
1834 qemu_get_be32s(f, &s->vbe_start_addr);
1835 qemu_get_be32s(f, &s->vbe_line_offset);
1836 qemu_get_be32s(f, &s->vbe_bank_mask);
1837 #else
1838 if (is_vbe)
1839 return -EINVAL;
1840 #endif
1841 if (version_id >= 3) {
1842 /* people who restore old images may be lucky ... */
1843 qemu_get_be32s(f, &vram_size);
1844 if (vram_size != s->vram_size)
1845 return -EINVAL;
1846 if (version_id >= 4) {
1847 qemu_get_be64s(f, &s->stolen_vram_addr);
1848 if (s->stolen_vram_addr)
1849 xen_vga_vram_map(s->stolen_vram_addr, 0);
1851 /* Old guest, VRAM is not mapped, we have to restore it ourselves */
1852 if (!s->stolen_vram_addr)
1853 qemu_get_buffer(f, s->vram_ptr, s->vram_size);
1856 /* force refresh */
1857 s->graphic_mode = -1;
1858 return 0;
1861 typedef struct PCIVGAState {
1862 PCIDevice dev;
1863 VGAState vga_state;
1864 } PCIVGAState;
1866 static void vga_map(PCIDevice *pci_dev, int region_num,
1867 uint32_t addr, uint32_t size, int type)
1869 PCIVGAState *d = (PCIVGAState *)pci_dev;
1870 VGAState *s = &d->vga_state;
1871 if (region_num == PCI_ROM_SLOT) {
1872 cpu_register_physical_memory(addr, s->bios_size, s->bios_offset);
1873 } else {
1874 cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
1878 /* do the same job as vgabios before vgabios get ready - yeah */
1879 void vga_bios_init(VGAState *s)
1881 uint8_t palette_model[192] = {
1882 0, 0, 0, 0, 0, 170, 0, 170,
1883 0, 0, 170, 170, 170, 0, 0, 170,
1884 0, 170, 170, 85, 0, 170, 170, 170,
1885 85, 85, 85, 85, 85, 255, 85, 255,
1886 85, 85, 255, 255, 255, 85, 85, 255,
1887 85, 255, 255, 255, 85, 255, 255, 255,
1888 0, 21, 0, 0, 21, 42, 0, 63,
1889 0, 0, 63, 42, 42, 21, 0, 42,
1890 21, 42, 42, 63, 0, 42, 63, 42,
1891 0, 21, 21, 0, 21, 63, 0, 63,
1892 21, 0, 63, 63, 42, 21, 21, 42,
1893 21, 63, 42, 63, 21, 42, 63, 63,
1894 21, 0, 0, 21, 0, 42, 21, 42,
1895 0, 21, 42, 42, 63, 0, 0, 63,
1896 0, 42, 63, 42, 0, 63, 42, 42,
1897 21, 0, 21, 21, 0, 63, 21, 42,
1898 21, 21, 42, 63, 63, 0, 21, 63,
1899 0, 63, 63, 42, 21, 63, 42, 63,
1900 21, 21, 0, 21, 21, 42, 21, 63,
1901 0, 21, 63, 42, 63, 21, 0, 63,
1902 21, 42, 63, 63, 0, 63, 63, 42,
1903 21, 21, 21, 21, 21, 63, 21, 63,
1904 21, 21, 63, 63, 63, 21, 21, 63,
1905 21, 63, 63, 63, 21, 63, 63, 63
1906 };
1908 s->latch = 0;
1910 s->sr_index = 3;
1911 s->sr[0] = 3;
1912 s->sr[1] = 0;
1913 s->sr[2] = 3;
1914 s->sr[3] = 0;
1915 s->sr[4] = 2;
1916 s->sr[5] = 0;
1917 s->sr[6] = 0;
1918 s->sr[7] = 0;
1920 s->gr_index = 5;
1921 s->gr[0] = 0;
1922 s->gr[1] = 0;
1923 s->gr[2] = 0;
1924 s->gr[3] = 0;
1925 s->gr[4] = 0;
1926 s->gr[5] = 16;
1927 s->gr[6] = 14;
1928 s->gr[7] = 15;
1929 s->gr[8] = 255;
1931 /* changed by out 0x03c0 */
1932 s->ar_index = 32;
1933 s->ar[0] = 0;
1934 s->ar[1] = 1;
1935 s->ar[2] = 2;
1936 s->ar[3] = 3;
1937 s->ar[4] = 4;
1938 s->ar[5] = 5;
1939 s->ar[6] = 6;
1940 s->ar[7] = 7;
1941 s->ar[8] = 8;
1942 s->ar[9] = 9;
1943 s->ar[10] = 10;
1944 s->ar[11] = 11;
1945 s->ar[12] = 12;
1946 s->ar[13] = 13;
1947 s->ar[14] = 14;
1948 s->ar[15] = 15;
1949 s->ar[16] = 12;
1950 s->ar[17] = 0;
1951 s->ar[18] = 15;
1952 s->ar[19] = 8;
1953 s->ar[20] = 0;
1955 s->ar_flip_flop = 1;
1957 s->cr_index = 15;
1958 s->cr[0] = 95;
1959 s->cr[1] = 79;
1960 s->cr[2] = 80;
1961 s->cr[3] = 130;
1962 s->cr[4] = 85;
1963 s->cr[5] = 129;
1964 s->cr[6] = 191;
1965 s->cr[7] = 31;
1966 s->cr[8] = 0;
1967 s->cr[9] = 79;
1968 s->cr[10] = 14;
1969 s->cr[11] = 15;
1970 s->cr[12] = 0;
1971 s->cr[13] = 0;
1972 s->cr[14] = 5;
1973 s->cr[15] = 160;
1974 s->cr[16] = 156;
1975 s->cr[17] = 142;
1976 s->cr[18] = 143;
1977 s->cr[19] = 40;
1978 s->cr[20] = 31;
1979 s->cr[21] = 150;
1980 s->cr[22] = 185;
1981 s->cr[23] = 163;
1982 s->cr[24] = 255;
1984 s->msr = 103;
1985 s->fcr = 0;
1986 s->st00 = 0;
1987 s->st01 = 0;
1989 /* dac_* & palette will be initialized by os through out 0x03c8 &
1990 * out 0c03c9(1:3) */
1991 s->dac_state = 0;
1992 s->dac_sub_index = 0;
1993 s->dac_read_index = 0;
1994 s->dac_write_index = 16;
1995 s->dac_cache[0] = 255;
1996 s->dac_cache[1] = 255;
1997 s->dac_cache[2] = 255;
1999 /* palette */
2000 memcpy(s->palette, palette_model, 192);
2002 s->bank_offset = 0;
2003 s->graphic_mode = -1;
2005 /* TODO: add vbe support if enabled */
2009 static VGAState *xen_vga_state;
2011 /* When loading old images we have to populate the video ram ourselves */
2012 void xen_vga_populate_vram(uint64_t vram_addr)
2014 unsigned long nr_pfn;
2015 struct xen_remove_from_physmap xrfp;
2016 xen_pfn_t *pfn_list;
2017 int i;
2018 int rc;
2020 fprintf(logfile, "populating video RAM at %lx\n", vram_addr);
2022 nr_pfn = VGA_RAM_SIZE >> TARGET_PAGE_BITS;
2024 pfn_list = malloc(sizeof(*pfn_list) * nr_pfn);
2026 for (i = 0; i < nr_pfn; i++)
2027 pfn_list[i] = (vram_addr >> TARGET_PAGE_BITS) + i;
2029 if (xc_domain_memory_populate_physmap(xc_handle, domid, nr_pfn, 0, 0, pfn_list)) {
2030 fprintf(stderr, "Failed to populate video ram\n");
2031 exit(1);
2033 free(pfn_list);
2035 xen_vga_vram_map(vram_addr, 0);
2037 /* Unmap them from the guest for now. */
2038 xrfp.domid = domid;
2039 for (i = 0; i < nr_pfn; i++) {
2040 xrfp.gpfn = (vram_addr >> TARGET_PAGE_BITS) + i;
2041 rc = xc_memory_op(xc_handle, XENMEM_remove_from_physmap, &xrfp);
2042 if (rc) {
2043 fprintf(stderr, "remove_from_physmap PFN %"PRI_xen_pfn" failed: %d\n", xrfp.gpfn, rc);
2044 break;
2049 /* Called once video memory has been allocated in the GPFN space */
2050 void xen_vga_vram_map(uint64_t vram_addr, int copy)
2052 unsigned long nr_pfn;
2053 xen_pfn_t *pfn_list;
2054 int i;
2055 void *vram;
2057 fprintf(logfile, "mapping video RAM from %lx\n", vram_addr);
2059 nr_pfn = VGA_RAM_SIZE >> TARGET_PAGE_BITS;
2061 pfn_list = malloc(sizeof(*pfn_list) * nr_pfn);
2063 for (i = 0; i < nr_pfn; i++)
2064 pfn_list[i] = (vram_addr >> TARGET_PAGE_BITS) + i;
2066 vram = xc_map_foreign_pages(xc_handle, domid,
2067 PROT_READ|PROT_WRITE,
2068 pfn_list, nr_pfn);
2070 if (!vram) {
2071 fprintf(stderr, "Failed to map vram\n");
2072 exit(1);
2075 if (xc_domain_memory_translate_gpfn_list(xc_handle, domid, nr_pfn,
2076 pfn_list, pfn_list)) {
2077 fprintf(stderr, "Failed translation in xen_vga_vram_addr\n");
2078 exit(1);
2081 if (copy)
2082 memcpy(vram, xen_vga_state->vram_ptr, VGA_RAM_SIZE);
2083 qemu_free(xen_vga_state->vram_ptr);
2084 xen_vga_state->vram_ptr = vram;
2085 xen_vga_state->vram_mfns = pfn_list;
2086 #ifdef CONFIG_STUBDOM
2087 xenfb_pv_display_start(vram);
2088 #endif
2091 /* Called at boot time when the BIOS has allocated video RAM */
2092 void xen_vga_stolen_vram_addr(uint64_t stolen_vram_addr)
2094 fprintf(logfile, "stolen video RAM at %lx\n", stolen_vram_addr);
2096 xen_vga_state->stolen_vram_addr = stolen_vram_addr;
2098 /* And copy from the initialization value */
2099 xen_vga_vram_map(stolen_vram_addr, 1);
2102 /* when used on xen environment, the vga_ram_base is not used */
2103 void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base,
2104 unsigned long vga_ram_offset, int vga_ram_size)
2106 int i, j, v, b;
2108 for(i = 0;i < 256; i++) {
2109 v = 0;
2110 for(j = 0; j < 8; j++) {
2111 v |= ((i >> j) & 1) << (j * 4);
2113 expand4[i] = v;
2115 v = 0;
2116 for(j = 0; j < 4; j++) {
2117 v |= ((i >> (2 * j)) & 3) << (j * 4);
2119 expand2[i] = v;
2121 for(i = 0; i < 16; i++) {
2122 v = 0;
2123 for(j = 0; j < 4; j++) {
2124 b = ((i >> j) & 1);
2125 v |= b << (2 * j);
2126 v |= b << (2 * j + 1);
2128 expand4to8[i] = v;
2131 vga_reset(s);
2133 s->vram_ptr = qemu_malloc(vga_ram_size);
2134 s->vram_mfns = NULL;
2135 xen_vga_state = s;
2137 s->vram_offset = vga_ram_offset;
2138 s->vram_size = vga_ram_size;
2139 s->ds = ds;
2140 ds->palette = s->last_palette;
2141 s->get_bpp = vga_get_bpp;
2142 s->get_offsets = vga_get_offsets;
2143 s->get_resolution = vga_get_resolution;
2144 graphic_console_init(s->ds, vga_update_display, vga_invalidate_display,
2145 vga_screen_dump, s);
2147 vga_bios_init(s);
2150 /* used by both ISA and PCI */
2151 static void vga_init(VGAState *s)
2153 int vga_io_memory;
2155 register_savevm("vga", 0, 4, vga_save, vga_load, s);
2157 register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
2159 register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
2160 register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);
2161 register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);
2162 register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);
2164 register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
2166 register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);
2167 register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);
2168 register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
2169 register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
2170 s->bank_offset = 0;
2172 #ifdef CONFIG_BOCHS_VBE
2173 s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0;
2174 s->vbe_bank_mask = ((s->vram_size >> 16) - 1);
2175 #if defined (TARGET_I386)
2176 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
2177 register_ioport_read(0x1cf, 1, 2, vbe_ioport_read_data, s);
2179 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
2180 register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data, s);
2182 /* old Bochs IO ports */
2183 register_ioport_read(0xff80, 1, 2, vbe_ioport_read_index, s);
2184 register_ioport_read(0xff81, 1, 2, vbe_ioport_read_data, s);
2186 register_ioport_write(0xff80, 1, 2, vbe_ioport_write_index, s);
2187 register_ioport_write(0xff81, 1, 2, vbe_ioport_write_data, s);
2188 #else
2189 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
2190 register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data, s);
2192 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
2193 register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data, s);
2194 #endif
2195 #endif /* CONFIG_BOCHS_VBE */
2197 vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s);
2198 cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
2199 vga_io_memory);
2202 int isa_vga_init(DisplayState *ds, uint8_t *vga_ram_base,
2203 unsigned long vga_ram_offset, int vga_ram_size)
2205 VGAState *s;
2207 s = qemu_mallocz(sizeof(VGAState));
2208 if (!s)
2209 return -1;
2211 vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size);
2212 vga_init(s);
2214 #ifdef CONFIG_BOCHS_VBE
2215 /* XXX: use optimized standard vga accesses */
2216 cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
2217 vga_ram_size, vga_ram_offset);
2218 #endif
2219 return 0;
2222 int pci_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base,
2223 unsigned long vga_ram_offset, int vga_ram_size,
2224 unsigned long vga_bios_offset, int vga_bios_size)
2226 PCIVGAState *d;
2227 VGAState *s;
2228 uint8_t *pci_conf;
2230 d = (PCIVGAState *)pci_register_device(bus, "VGA",
2231 sizeof(PCIVGAState),
2232 -1, NULL, NULL);
2233 if (!d)
2234 return -1;
2235 s = &d->vga_state;
2237 vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size);
2238 vga_init(s);
2239 s->pci_dev = &d->dev;
2241 pci_conf = d->dev.config;
2242 pci_conf[0x00] = 0x34; // dummy VGA (same as Bochs ID)
2243 pci_conf[0x01] = 0x12;
2244 pci_conf[0x02] = 0x11;
2245 pci_conf[0x03] = 0x11;
2246 pci_conf[0x0a] = 0x00; // VGA controller
2247 pci_conf[0x0b] = 0x03;
2248 pci_conf[0x0e] = 0x00; // header_type
2250 /* XXX: vga_ram_size must be a power of two */
2251 pci_register_io_region(&d->dev, 0, vga_ram_size,
2252 PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
2253 if (vga_bios_size != 0) {
2254 unsigned int bios_total_size;
2255 s->bios_offset = vga_bios_offset;
2256 s->bios_size = vga_bios_size;
2257 /* must be a power of two */
2258 bios_total_size = 1;
2259 while (bios_total_size < vga_bios_size)
2260 bios_total_size <<= 1;
2261 pci_register_io_region(&d->dev, PCI_ROM_SLOT, bios_total_size,
2262 PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
2264 return 0;
2267 /********************************************************/
2268 /* vga screen dump */
2270 static int vga_save_w, vga_save_h;
2272 static void vga_save_dpy_update(DisplayState *s,
2273 int x, int y, int w, int h)
2277 static void vga_save_dpy_resize(DisplayState *s, int w, int h)
2279 s->linesize = w * 4;
2280 s->data = qemu_malloc(h * s->linesize);
2281 vga_save_w = w;
2282 vga_save_h = h;
2285 static void vga_save_dpy_refresh(DisplayState *s)
2289 static int ppm_save(const char *filename, uint8_t *data,
2290 int w, int h, int linesize)
2292 FILE *f;
2293 uint8_t *d, *d1;
2294 unsigned int v;
2295 int y, x;
2297 f = fopen(filename, "wb");
2298 if (!f)
2299 return -1;
2300 fprintf(f, "P6\n%d %d\n%d\n",
2301 w, h, 255);
2302 d1 = data;
2303 for(y = 0; y < h; y++) {
2304 d = d1;
2305 for(x = 0; x < w; x++) {
2306 v = *(uint32_t *)d;
2307 fputc((v >> 16) & 0xff, f);
2308 fputc((v >> 8) & 0xff, f);
2309 fputc((v) & 0xff, f);
2310 d += 4;
2312 d1 += linesize;
2314 fclose(f);
2315 return 0;
2318 /* save the vga display in a PPM image even if no display is
2319 available */
2320 static void vga_screen_dump(void *opaque, const char *filename)
2322 VGAState *s = (VGAState *)opaque;
2323 DisplayState *saved_ds, ds1, *ds = &ds1;
2325 /* XXX: this is a little hackish */
2326 vga_invalidate_display(s);
2327 saved_ds = s->ds;
2329 memset(ds, 0, sizeof(DisplayState));
2330 ds->dpy_update = vga_save_dpy_update;
2331 ds->dpy_resize = vga_save_dpy_resize;
2332 ds->dpy_refresh = vga_save_dpy_refresh;
2333 ds->depth = 32;
2335 s->ds = ds;
2336 s->graphic_mode = -1;
2337 vga_update_display(s);
2339 if (ds->data) {
2340 ppm_save(filename, ds->data, vga_save_w, vga_save_h,
2341 s->ds->linesize);
2342 qemu_free(ds->data);
2344 s->ds = saved_ds;