]> git.proxmox.com Git - mirror_qemu.git/blame - hw/vga.c
Merge remote-tracking branch 'kwolf/for-anthony' into staging
[mirror_qemu.git] / hw / vga.c
CommitLineData
e89f66ec 1/*
4fa0f5d2 2 * QEMU VGA Emulator.
5fafdf24 3 *
e89f66ec 4 * Copyright (c) 2003 Fabrice Bellard
5fafdf24 5 *
e89f66ec
FB
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 */
87ecb68b
PB
24#include "hw.h"
25#include "console.h"
26#include "pc.h"
27#include "pci.h"
798b0c25 28#include "vga_int.h"
94470844 29#include "pixel_ops.h"
cb5a7aa8 30#include "qemu-timer.h"
e89f66ec 31
e89f66ec 32//#define DEBUG_VGA
17b0018b 33//#define DEBUG_VGA_MEM
a41bc9af
FB
34//#define DEBUG_VGA_REG
35
4fa0f5d2
FB
36//#define DEBUG_BOCHS_VBE
37
e89f66ec 38/* force some bits to zero */
798b0c25 39const uint8_t sr_mask[8] = {
9e622b15
BS
40 0x03,
41 0x3d,
42 0x0f,
43 0x3f,
44 0x0e,
45 0x00,
46 0x00,
47 0xff,
e89f66ec
FB
48};
49
798b0c25 50const uint8_t gr_mask[16] = {
9e622b15
BS
51 0x0f, /* 0x00 */
52 0x0f, /* 0x01 */
53 0x0f, /* 0x02 */
54 0x1f, /* 0x03 */
55 0x03, /* 0x04 */
56 0x7b, /* 0x05 */
57 0x0f, /* 0x06 */
58 0x0f, /* 0x07 */
59 0xff, /* 0x08 */
60 0x00, /* 0x09 */
61 0x00, /* 0x0a */
62 0x00, /* 0x0b */
63 0x00, /* 0x0c */
64 0x00, /* 0x0d */
65 0x00, /* 0x0e */
66 0x00, /* 0x0f */
e89f66ec
FB
67};
68
69#define cbswap_32(__x) \
70((uint32_t)( \
71 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
72 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
73 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
74 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
75
e2542fe2 76#ifdef HOST_WORDS_BIGENDIAN
e89f66ec
FB
77#define PAT(x) cbswap_32(x)
78#else
79#define PAT(x) (x)
80#endif
81
e2542fe2 82#ifdef HOST_WORDS_BIGENDIAN
b8ed223b
FB
83#define BIG 1
84#else
85#define BIG 0
86#endif
87
e2542fe2 88#ifdef HOST_WORDS_BIGENDIAN
b8ed223b
FB
89#define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
90#else
91#define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
92#endif
93
e89f66ec
FB
94static const uint32_t mask16[16] = {
95 PAT(0x00000000),
96 PAT(0x000000ff),
97 PAT(0x0000ff00),
98 PAT(0x0000ffff),
99 PAT(0x00ff0000),
100 PAT(0x00ff00ff),
101 PAT(0x00ffff00),
102 PAT(0x00ffffff),
103 PAT(0xff000000),
104 PAT(0xff0000ff),
105 PAT(0xff00ff00),
106 PAT(0xff00ffff),
107 PAT(0xffff0000),
108 PAT(0xffff00ff),
109 PAT(0xffffff00),
110 PAT(0xffffffff),
111};
112
113#undef PAT
114
e2542fe2 115#ifdef HOST_WORDS_BIGENDIAN
e89f66ec
FB
116#define PAT(x) (x)
117#else
118#define PAT(x) cbswap_32(x)
119#endif
120
121static const uint32_t dmask16[16] = {
122 PAT(0x00000000),
123 PAT(0x000000ff),
124 PAT(0x0000ff00),
125 PAT(0x0000ffff),
126 PAT(0x00ff0000),
127 PAT(0x00ff00ff),
128 PAT(0x00ffff00),
129 PAT(0x00ffffff),
130 PAT(0xff000000),
131 PAT(0xff0000ff),
132 PAT(0xff00ff00),
133 PAT(0xff00ffff),
134 PAT(0xffff0000),
135 PAT(0xffff00ff),
136 PAT(0xffffff00),
137 PAT(0xffffffff),
138};
139
140static const uint32_t dmask4[4] = {
141 PAT(0x00000000),
142 PAT(0x0000ffff),
143 PAT(0xffff0000),
144 PAT(0xffffffff),
145};
146
147static uint32_t expand4[256];
148static uint16_t expand2[256];
17b0018b 149static uint8_t expand4to8[16];
e89f66ec 150
95219897 151static void vga_screen_dump(void *opaque, const char *filename);
2313e998 152static const char *screen_dump_filename;
04a52b41 153static DisplayChangeListener *screen_dump_dcl;
95219897 154
80763888
JK
155static void vga_update_memory_access(VGACommonState *s)
156{
157 MemoryRegion *region, *old_region = s->chain4_alias;
158 target_phys_addr_t base, offset, size;
159
160 s->chain4_alias = NULL;
161
162 if ((s->sr[0x02] & 0xf) == 0xf && s->sr[0x04] & 0x08) {
163 offset = 0;
164 switch ((s->gr[6] >> 2) & 3) {
165 case 0:
166 base = 0xa0000;
167 size = 0x20000;
168 break;
169 case 1:
170 base = 0xa0000;
171 size = 0x10000;
172 offset = s->bank_offset;
173 break;
174 case 2:
175 base = 0xb0000;
176 size = 0x8000;
177 break;
178 case 3:
f065aa0a 179 default:
80763888
JK
180 base = 0xb8000;
181 size = 0x8000;
182 break;
183 }
71579cae 184 base += isa_mem_base;
80763888
JK
185 region = g_malloc(sizeof(*region));
186 memory_region_init_alias(region, "vga.chain4", &s->vram, offset, size);
187 memory_region_add_subregion_overlap(s->legacy_address_space, base,
188 region, 2);
189 s->chain4_alias = region;
190 }
191 if (old_region) {
192 memory_region_del_subregion(s->legacy_address_space, old_region);
193 memory_region_destroy(old_region);
194 g_free(old_region);
195 s->plane_updated = 0xf;
196 }
197}
198
cedd91d2 199static void vga_dumb_update_retrace_info(VGACommonState *s)
cb5a7aa8 200{
201 (void) s;
202}
203
cedd91d2 204static void vga_precise_update_retrace_info(VGACommonState *s)
cb5a7aa8 205{
206 int htotal_chars;
207 int hretr_start_char;
208 int hretr_skew_chars;
209 int hretr_end_char;
210
211 int vtotal_lines;
212 int vretr_start_line;
213 int vretr_end_line;
214
7f5b7d3e
BS
215 int dots;
216#if 0
217 int div2, sldiv2;
218#endif
cb5a7aa8 219 int clocking_mode;
220 int clock_sel;
b0f74c87 221 const int clk_hz[] = {25175000, 28322000, 25175000, 25175000};
cb5a7aa8 222 int64_t chars_per_sec;
223 struct vga_precise_retrace *r = &s->retrace_info.precise;
224
225 htotal_chars = s->cr[0x00] + 5;
226 hretr_start_char = s->cr[0x04];
227 hretr_skew_chars = (s->cr[0x05] >> 5) & 3;
228 hretr_end_char = s->cr[0x05] & 0x1f;
229
230 vtotal_lines = (s->cr[0x06]
231 | (((s->cr[0x07] & 1) | ((s->cr[0x07] >> 4) & 2)) << 8)) + 2
232 ;
233 vretr_start_line = s->cr[0x10]
234 | ((((s->cr[0x07] >> 2) & 1) | ((s->cr[0x07] >> 6) & 2)) << 8)
235 ;
236 vretr_end_line = s->cr[0x11] & 0xf;
237
238
cb5a7aa8 239
240 clocking_mode = (s->sr[0x01] >> 3) & 1;
241 clock_sel = (s->msr >> 2) & 3;
f87fc09b 242 dots = (s->msr & 1) ? 8 : 9;
cb5a7aa8 243
b0f74c87 244 chars_per_sec = clk_hz[clock_sel] / dots;
cb5a7aa8 245
246 htotal_chars <<= clocking_mode;
247
248 r->total_chars = vtotal_lines * htotal_chars;
cb5a7aa8 249 if (r->freq) {
6ee093c9 250 r->ticks_per_char = get_ticks_per_sec() / (r->total_chars * r->freq);
cb5a7aa8 251 } else {
6ee093c9 252 r->ticks_per_char = get_ticks_per_sec() / chars_per_sec;
cb5a7aa8 253 }
254
255 r->vstart = vretr_start_line;
256 r->vend = r->vstart + vretr_end_line + 1;
257
258 r->hstart = hretr_start_char + hretr_skew_chars;
259 r->hend = r->hstart + hretr_end_char + 1;
260 r->htotal = htotal_chars;
261
f87fc09b 262#if 0
7f5b7d3e
BS
263 div2 = (s->cr[0x17] >> 2) & 1;
264 sldiv2 = (s->cr[0x17] >> 3) & 1;
cb5a7aa8 265 printf (
f87fc09b 266 "hz=%f\n"
cb5a7aa8 267 "htotal = %d\n"
268 "hretr_start = %d\n"
269 "hretr_skew = %d\n"
270 "hretr_end = %d\n"
271 "vtotal = %d\n"
272 "vretr_start = %d\n"
273 "vretr_end = %d\n"
274 "div2 = %d sldiv2 = %d\n"
275 "clocking_mode = %d\n"
276 "clock_sel = %d %d\n"
277 "dots = %d\n"
0bfcd599 278 "ticks/char = %" PRId64 "\n"
cb5a7aa8 279 "\n",
6ee093c9 280 (double) get_ticks_per_sec() / (r->ticks_per_char * r->total_chars),
cb5a7aa8 281 htotal_chars,
282 hretr_start_char,
283 hretr_skew_chars,
284 hretr_end_char,
285 vtotal_lines,
286 vretr_start_line,
287 vretr_end_line,
288 div2, sldiv2,
289 clocking_mode,
290 clock_sel,
b0f74c87 291 clk_hz[clock_sel],
cb5a7aa8 292 dots,
293 r->ticks_per_char
294 );
295#endif
296}
297
cedd91d2 298static uint8_t vga_precise_retrace(VGACommonState *s)
cb5a7aa8 299{
300 struct vga_precise_retrace *r = &s->retrace_info.precise;
301 uint8_t val = s->st01 & ~(ST01_V_RETRACE | ST01_DISP_ENABLE);
302
303 if (r->total_chars) {
304 int cur_line, cur_line_char, cur_char;
305 int64_t cur_tick;
306
74475455 307 cur_tick = qemu_get_clock_ns(vm_clock);
cb5a7aa8 308
309 cur_char = (cur_tick / r->ticks_per_char) % r->total_chars;
310 cur_line = cur_char / r->htotal;
311
312 if (cur_line >= r->vstart && cur_line <= r->vend) {
313 val |= ST01_V_RETRACE | ST01_DISP_ENABLE;
f87fc09b 314 } else {
315 cur_line_char = cur_char % r->htotal;
316 if (cur_line_char >= r->hstart && cur_line_char <= r->hend) {
317 val |= ST01_DISP_ENABLE;
318 }
cb5a7aa8 319 }
320
321 return val;
322 } else {
323 return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
324 }
325}
326
cedd91d2 327static uint8_t vga_dumb_retrace(VGACommonState *s)
cb5a7aa8 328{
329 return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
330}
331
25a18cbd
JQ
332int vga_ioport_invalid(VGACommonState *s, uint32_t addr)
333{
334 if (s->msr & MSR_COLOR_EMULATION) {
335 /* Color */
336 return (addr >= 0x3b0 && addr <= 0x3bf);
337 } else {
338 /* Monochrome */
339 return (addr >= 0x3d0 && addr <= 0x3df);
340 }
341}
342
43bf782b 343uint32_t vga_ioport_read(void *opaque, uint32_t addr)
e89f66ec 344{
43bf782b 345 VGACommonState *s = opaque;
e89f66ec
FB
346 int val, index;
347
25a18cbd 348 if (vga_ioport_invalid(s, addr)) {
e89f66ec
FB
349 val = 0xff;
350 } else {
351 switch(addr) {
352 case 0x3c0:
353 if (s->ar_flip_flop == 0) {
354 val = s->ar_index;
355 } else {
356 val = 0;
357 }
358 break;
359 case 0x3c1:
360 index = s->ar_index & 0x1f;
5fafdf24 361 if (index < 21)
e89f66ec
FB
362 val = s->ar[index];
363 else
364 val = 0;
365 break;
366 case 0x3c2:
367 val = s->st00;
368 break;
369 case 0x3c4:
370 val = s->sr_index;
371 break;
372 case 0x3c5:
373 val = s->sr[s->sr_index];
a41bc9af
FB
374#ifdef DEBUG_VGA_REG
375 printf("vga: read SR%x = 0x%02x\n", s->sr_index, val);
376#endif
e89f66ec
FB
377 break;
378 case 0x3c7:
379 val = s->dac_state;
380 break;
e9b43ea3
JQ
381 case 0x3c8:
382 val = s->dac_write_index;
383 break;
e89f66ec
FB
384 case 0x3c9:
385 val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
386 if (++s->dac_sub_index == 3) {
387 s->dac_sub_index = 0;
388 s->dac_read_index++;
389 }
390 break;
391 case 0x3ca:
392 val = s->fcr;
393 break;
394 case 0x3cc:
395 val = s->msr;
396 break;
397 case 0x3ce:
398 val = s->gr_index;
399 break;
400 case 0x3cf:
401 val = s->gr[s->gr_index];
a41bc9af
FB
402#ifdef DEBUG_VGA_REG
403 printf("vga: read GR%x = 0x%02x\n", s->gr_index, val);
404#endif
e89f66ec
FB
405 break;
406 case 0x3b4:
407 case 0x3d4:
408 val = s->cr_index;
409 break;
410 case 0x3b5:
411 case 0x3d5:
412 val = s->cr[s->cr_index];
a41bc9af
FB
413#ifdef DEBUG_VGA_REG
414 printf("vga: read CR%x = 0x%02x\n", s->cr_index, val);
a41bc9af 415#endif
e89f66ec
FB
416 break;
417 case 0x3ba:
418 case 0x3da:
419 /* just toggle to fool polling */
cb5a7aa8 420 val = s->st01 = s->retrace(s);
e89f66ec
FB
421 s->ar_flip_flop = 0;
422 break;
423 default:
424 val = 0x00;
425 break;
426 }
427 }
4fa0f5d2 428#if defined(DEBUG_VGA)
e89f66ec
FB
429 printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
430#endif
431 return val;
432}
433
43bf782b 434void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
e89f66ec 435{
43bf782b 436 VGACommonState *s = opaque;
5467a722 437 int index;
e89f66ec
FB
438
439 /* check port range access depending on color/monochrome mode */
25a18cbd 440 if (vga_ioport_invalid(s, addr)) {
e89f66ec 441 return;
25a18cbd 442 }
e89f66ec
FB
443#ifdef DEBUG_VGA
444 printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
445#endif
446
447 switch(addr) {
448 case 0x3c0:
449 if (s->ar_flip_flop == 0) {
450 val &= 0x3f;
451 s->ar_index = val;
452 } else {
453 index = s->ar_index & 0x1f;
454 switch(index) {
455 case 0x00 ... 0x0f:
456 s->ar[index] = val & 0x3f;
457 break;
458 case 0x10:
459 s->ar[index] = val & ~0x10;
460 break;
461 case 0x11:
462 s->ar[index] = val;
463 break;
464 case 0x12:
465 s->ar[index] = val & ~0xc0;
466 break;
467 case 0x13:
468 s->ar[index] = val & ~0xf0;
469 break;
470 case 0x14:
471 s->ar[index] = val & ~0xf0;
472 break;
473 default:
474 break;
475 }
476 }
477 s->ar_flip_flop ^= 1;
478 break;
479 case 0x3c2:
480 s->msr = val & ~0x10;
cb5a7aa8 481 s->update_retrace_info(s);
e89f66ec
FB
482 break;
483 case 0x3c4:
484 s->sr_index = val & 7;
485 break;
486 case 0x3c5:
a41bc9af
FB
487#ifdef DEBUG_VGA_REG
488 printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
489#endif
e89f66ec 490 s->sr[s->sr_index] = val & sr_mask[s->sr_index];
cb5a7aa8 491 if (s->sr_index == 1) s->update_retrace_info(s);
80763888 492 vga_update_memory_access(s);
e89f66ec
FB
493 break;
494 case 0x3c7:
495 s->dac_read_index = val;
496 s->dac_sub_index = 0;
497 s->dac_state = 3;
498 break;
499 case 0x3c8:
500 s->dac_write_index = val;
501 s->dac_sub_index = 0;
502 s->dac_state = 0;
503 break;
504 case 0x3c9:
505 s->dac_cache[s->dac_sub_index] = val;
506 if (++s->dac_sub_index == 3) {
507 memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
508 s->dac_sub_index = 0;
509 s->dac_write_index++;
510 }
511 break;
512 case 0x3ce:
513 s->gr_index = val & 0x0f;
514 break;
515 case 0x3cf:
a41bc9af
FB
516#ifdef DEBUG_VGA_REG
517 printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
518#endif
e89f66ec 519 s->gr[s->gr_index] = val & gr_mask[s->gr_index];
80763888 520 vga_update_memory_access(s);
e89f66ec
FB
521 break;
522 case 0x3b4:
523 case 0x3d4:
524 s->cr_index = val;
525 break;
526 case 0x3b5:
527 case 0x3d5:
a41bc9af
FB
528#ifdef DEBUG_VGA_REG
529 printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
530#endif
e89f66ec 531 /* handle CR0-7 protection */
f6c958c8 532 if ((s->cr[0x11] & 0x80) && s->cr_index <= 7) {
e89f66ec
FB
533 /* can always write bit 4 of CR7 */
534 if (s->cr_index == 7)
535 s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
536 return;
537 }
a46007a0 538 s->cr[s->cr_index] = val;
cb5a7aa8 539
540 switch(s->cr_index) {
541 case 0x00:
542 case 0x04:
543 case 0x05:
544 case 0x06:
545 case 0x07:
546 case 0x11:
547 case 0x17:
548 s->update_retrace_info(s);
549 break;
550 }
e89f66ec
FB
551 break;
552 case 0x3ba:
553 case 0x3da:
554 s->fcr = val & 0x10;
555 break;
556 }
557}
558
4fa0f5d2 559#ifdef CONFIG_BOCHS_VBE
09a79b49 560static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
4fa0f5d2 561{
cedd91d2 562 VGACommonState *s = opaque;
4fa0f5d2 563 uint32_t val;
09a79b49
FB
564 val = s->vbe_index;
565 return val;
566}
4fa0f5d2 567
09a79b49
FB
568static uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr)
569{
cedd91d2 570 VGACommonState *s = opaque;
09a79b49
FB
571 uint32_t val;
572
af92284b 573 if (s->vbe_index < VBE_DISPI_INDEX_NB) {
8454df8b
FB
574 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_GETCAPS) {
575 switch(s->vbe_index) {
576 /* XXX: do not hardcode ? */
577 case VBE_DISPI_INDEX_XRES:
578 val = VBE_DISPI_MAX_XRES;
579 break;
580 case VBE_DISPI_INDEX_YRES:
581 val = VBE_DISPI_MAX_YRES;
582 break;
583 case VBE_DISPI_INDEX_BPP:
584 val = VBE_DISPI_MAX_BPP;
585 break;
586 default:
5fafdf24 587 val = s->vbe_regs[s->vbe_index];
8454df8b
FB
588 break;
589 }
590 } else {
5fafdf24 591 val = s->vbe_regs[s->vbe_index];
8454df8b 592 }
af92284b
GH
593 } else if (s->vbe_index == VBE_DISPI_INDEX_VIDEO_MEMORY_64K) {
594 val = s->vram_size / (64 * 1024);
8454df8b 595 } else {
09a79b49 596 val = 0;
8454df8b 597 }
4fa0f5d2 598#ifdef DEBUG_BOCHS_VBE
09a79b49 599 printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val);
4fa0f5d2 600#endif
4fa0f5d2
FB
601 return val;
602}
603
09a79b49
FB
604static void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val)
605{
cedd91d2 606 VGACommonState *s = opaque;
09a79b49
FB
607 s->vbe_index = val;
608}
609
610static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
4fa0f5d2 611{
cedd91d2 612 VGACommonState *s = opaque;
4fa0f5d2 613
09a79b49 614 if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
4fa0f5d2
FB
615#ifdef DEBUG_BOCHS_VBE
616 printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val);
617#endif
618 switch(s->vbe_index) {
619 case VBE_DISPI_INDEX_ID:
cae61cef
FB
620 if (val == VBE_DISPI_ID0 ||
621 val == VBE_DISPI_ID1 ||
37dd208d
FB
622 val == VBE_DISPI_ID2 ||
623 val == VBE_DISPI_ID3 ||
624 val == VBE_DISPI_ID4) {
cae61cef
FB
625 s->vbe_regs[s->vbe_index] = val;
626 }
4fa0f5d2
FB
627 break;
628 case VBE_DISPI_INDEX_XRES:
cae61cef
FB
629 if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) {
630 s->vbe_regs[s->vbe_index] = val;
631 }
4fa0f5d2
FB
632 break;
633 case VBE_DISPI_INDEX_YRES:
cae61cef
FB
634 if (val <= VBE_DISPI_MAX_YRES) {
635 s->vbe_regs[s->vbe_index] = val;
636 }
4fa0f5d2
FB
637 break;
638 case VBE_DISPI_INDEX_BPP:
639 if (val == 0)
640 val = 8;
5fafdf24 641 if (val == 4 || val == 8 || val == 15 ||
cae61cef
FB
642 val == 16 || val == 24 || val == 32) {
643 s->vbe_regs[s->vbe_index] = val;
644 }
4fa0f5d2
FB
645 break;
646 case VBE_DISPI_INDEX_BANK:
42fc925e
FB
647 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
648 val &= (s->vbe_bank_mask >> 2);
649 } else {
650 val &= s->vbe_bank_mask;
651 }
cae61cef 652 s->vbe_regs[s->vbe_index] = val;
26aa7d72 653 s->bank_offset = (val << 16);
80763888 654 vga_update_memory_access(s);
4fa0f5d2
FB
655 break;
656 case VBE_DISPI_INDEX_ENABLE:
8454df8b
FB
657 if ((val & VBE_DISPI_ENABLED) &&
658 !(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
4fa0f5d2
FB
659 int h, shift_control;
660
5fafdf24 661 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] =
4fa0f5d2 662 s->vbe_regs[VBE_DISPI_INDEX_XRES];
5fafdf24 663 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] =
4fa0f5d2
FB
664 s->vbe_regs[VBE_DISPI_INDEX_YRES];
665 s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
666 s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
3b46e624 667
4fa0f5d2
FB
668 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
669 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1;
670 else
5fafdf24 671 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] *
4fa0f5d2
FB
672 ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
673 s->vbe_start_addr = 0;
8454df8b 674
4fa0f5d2
FB
675 /* clear the screen (should be done in BIOS) */
676 if (!(val & VBE_DISPI_NOCLEARMEM)) {
5fafdf24 677 memset(s->vram_ptr, 0,
4fa0f5d2
FB
678 s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
679 }
3b46e624 680
cae61cef
FB
681 /* we initialize the VGA graphic mode (should be done
682 in BIOS) */
683 s->gr[0x06] = (s->gr[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
4fa0f5d2
FB
684 s->cr[0x17] |= 3; /* no CGA modes */
685 s->cr[0x13] = s->vbe_line_offset >> 3;
686 /* width */
687 s->cr[0x01] = (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
8454df8b 688 /* height (only meaningful if < 1024) */
4fa0f5d2
FB
689 h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
690 s->cr[0x12] = h;
5fafdf24 691 s->cr[0x07] = (s->cr[0x07] & ~0x42) |
4fa0f5d2
FB
692 ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
693 /* line compare to 1023 */
694 s->cr[0x18] = 0xff;
695 s->cr[0x07] |= 0x10;
696 s->cr[0x09] |= 0x40;
3b46e624 697
4fa0f5d2
FB
698 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
699 shift_control = 0;
700 s->sr[0x01] &= ~8; /* no double line */
701 } else {
702 shift_control = 2;
646be93b 703 s->sr[4] |= 0x08; /* set chain 4 mode */
141253b2 704 s->sr[2] |= 0x0f; /* activate all planes */
4fa0f5d2
FB
705 }
706 s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5);
707 s->cr[0x09] &= ~0x9f; /* no double scan */
cae61cef
FB
708 } else {
709 /* XXX: the bios should do that */
26aa7d72 710 s->bank_offset = 0;
cae61cef 711 }
37dd208d 712 s->dac_8bit = (val & VBE_DISPI_8BIT_DAC) > 0;
141253b2 713 s->vbe_regs[s->vbe_index] = val;
80763888 714 vga_update_memory_access(s);
cae61cef
FB
715 break;
716 case VBE_DISPI_INDEX_VIRT_WIDTH:
717 {
718 int w, h, line_offset;
719
720 if (val < s->vbe_regs[VBE_DISPI_INDEX_XRES])
721 return;
722 w = val;
723 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
724 line_offset = w >> 1;
725 else
726 line_offset = w * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
727 h = s->vram_size / line_offset;
728 /* XXX: support weird bochs semantics ? */
729 if (h < s->vbe_regs[VBE_DISPI_INDEX_YRES])
730 return;
731 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = w;
732 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h;
733 s->vbe_line_offset = line_offset;
734 }
735 break;
736 case VBE_DISPI_INDEX_X_OFFSET:
737 case VBE_DISPI_INDEX_Y_OFFSET:
738 {
739 int x;
740 s->vbe_regs[s->vbe_index] = val;
741 s->vbe_start_addr = s->vbe_line_offset * s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET];
742 x = s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET];
743 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
744 s->vbe_start_addr += x >> 1;
745 else
746 s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
747 s->vbe_start_addr >>= 2;
4fa0f5d2
FB
748 }
749 break;
750 default:
751 break;
752 }
4fa0f5d2
FB
753 }
754}
755#endif
756
e89f66ec 757/* called for accesses between 0xa0000 and 0xc0000 */
b2a5e761 758uint32_t vga_mem_readb(VGACommonState *s, target_phys_addr_t addr)
e89f66ec 759{
e89f66ec
FB
760 int memory_map_mode, plane;
761 uint32_t ret;
3b46e624 762
e89f66ec
FB
763 /* convert to VGA memory offset */
764 memory_map_mode = (s->gr[6] >> 2) & 3;
26aa7d72 765 addr &= 0x1ffff;
e89f66ec
FB
766 switch(memory_map_mode) {
767 case 0:
e89f66ec
FB
768 break;
769 case 1:
26aa7d72 770 if (addr >= 0x10000)
e89f66ec 771 return 0xff;
cae61cef 772 addr += s->bank_offset;
e89f66ec
FB
773 break;
774 case 2:
26aa7d72 775 addr -= 0x10000;
e89f66ec
FB
776 if (addr >= 0x8000)
777 return 0xff;
778 break;
779 default:
780 case 3:
26aa7d72 781 addr -= 0x18000;
c92b2e84
FB
782 if (addr >= 0x8000)
783 return 0xff;
e89f66ec
FB
784 break;
785 }
3b46e624 786
e89f66ec
FB
787 if (s->sr[4] & 0x08) {
788 /* chain 4 mode : simplest access */
789 ret = s->vram_ptr[addr];
790 } else if (s->gr[5] & 0x10) {
791 /* odd/even mode (aka text mode mapping) */
792 plane = (s->gr[4] & 2) | (addr & 1);
793 ret = s->vram_ptr[((addr & ~1) << 1) | plane];
794 } else {
795 /* standard VGA latched access */
796 s->latch = ((uint32_t *)s->vram_ptr)[addr];
797
798 if (!(s->gr[5] & 0x08)) {
799 /* read mode 0 */
800 plane = s->gr[4];
b8ed223b 801 ret = GET_PLANE(s->latch, plane);
e89f66ec
FB
802 } else {
803 /* read mode 1 */
804 ret = (s->latch ^ mask16[s->gr[2]]) & mask16[s->gr[7]];
805 ret |= ret >> 16;
806 ret |= ret >> 8;
807 ret = (~ret) & 0xff;
808 }
809 }
810 return ret;
811}
812
e89f66ec 813/* called for accesses between 0xa0000 and 0xc0000 */
b2a5e761 814void vga_mem_writeb(VGACommonState *s, target_phys_addr_t addr, uint32_t val)
e89f66ec 815{
546fa6ab 816 int memory_map_mode, plane, write_mode, b, func_select, mask;
e89f66ec
FB
817 uint32_t write_mask, bit_mask, set_mask;
818
17b0018b 819#ifdef DEBUG_VGA_MEM
0bf9e31a 820 printf("vga: [0x" TARGET_FMT_plx "] = 0x%02x\n", addr, val);
e89f66ec
FB
821#endif
822 /* convert to VGA memory offset */
823 memory_map_mode = (s->gr[6] >> 2) & 3;
26aa7d72 824 addr &= 0x1ffff;
e89f66ec
FB
825 switch(memory_map_mode) {
826 case 0:
e89f66ec
FB
827 break;
828 case 1:
26aa7d72 829 if (addr >= 0x10000)
e89f66ec 830 return;
cae61cef 831 addr += s->bank_offset;
e89f66ec
FB
832 break;
833 case 2:
26aa7d72 834 addr -= 0x10000;
e89f66ec
FB
835 if (addr >= 0x8000)
836 return;
837 break;
838 default:
839 case 3:
26aa7d72 840 addr -= 0x18000;
c92b2e84
FB
841 if (addr >= 0x8000)
842 return;
e89f66ec
FB
843 break;
844 }
3b46e624 845
e89f66ec
FB
846 if (s->sr[4] & 0x08) {
847 /* chain 4 mode : simplest access */
848 plane = addr & 3;
546fa6ab
FB
849 mask = (1 << plane);
850 if (s->sr[2] & mask) {
e89f66ec 851 s->vram_ptr[addr] = val;
17b0018b 852#ifdef DEBUG_VGA_MEM
0bf9e31a 853 printf("vga: chain4: [0x" TARGET_FMT_plx "]\n", addr);
e89f66ec 854#endif
546fa6ab 855 s->plane_updated |= mask; /* only used to detect font change */
b1950430 856 memory_region_set_dirty(&s->vram, addr);
e89f66ec
FB
857 }
858 } else if (s->gr[5] & 0x10) {
859 /* odd/even mode (aka text mode mapping) */
860 plane = (s->gr[4] & 2) | (addr & 1);
546fa6ab
FB
861 mask = (1 << plane);
862 if (s->sr[2] & mask) {
e89f66ec
FB
863 addr = ((addr & ~1) << 1) | plane;
864 s->vram_ptr[addr] = val;
17b0018b 865#ifdef DEBUG_VGA_MEM
0bf9e31a 866 printf("vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr);
e89f66ec 867#endif
546fa6ab 868 s->plane_updated |= mask; /* only used to detect font change */
b1950430 869 memory_region_set_dirty(&s->vram, addr);
e89f66ec
FB
870 }
871 } else {
872 /* standard VGA latched access */
873 write_mode = s->gr[5] & 3;
874 switch(write_mode) {
875 default:
876 case 0:
877 /* rotate */
878 b = s->gr[3] & 7;
879 val = ((val >> b) | (val << (8 - b))) & 0xff;
880 val |= val << 8;
881 val |= val << 16;
882
883 /* apply set/reset mask */
884 set_mask = mask16[s->gr[1]];
885 val = (val & ~set_mask) | (mask16[s->gr[0]] & set_mask);
886 bit_mask = s->gr[8];
887 break;
888 case 1:
889 val = s->latch;
890 goto do_write;
891 case 2:
892 val = mask16[val & 0x0f];
893 bit_mask = s->gr[8];
894 break;
895 case 3:
896 /* rotate */
897 b = s->gr[3] & 7;
a41bc9af 898 val = (val >> b) | (val << (8 - b));
e89f66ec
FB
899
900 bit_mask = s->gr[8] & val;
901 val = mask16[s->gr[0]];
902 break;
903 }
904
905 /* apply logical operation */
906 func_select = s->gr[3] >> 3;
907 switch(func_select) {
908 case 0:
909 default:
910 /* nothing to do */
911 break;
912 case 1:
913 /* and */
914 val &= s->latch;
915 break;
916 case 2:
917 /* or */
918 val |= s->latch;
919 break;
920 case 3:
921 /* xor */
922 val ^= s->latch;
923 break;
924 }
925
926 /* apply bit mask */
927 bit_mask |= bit_mask << 8;
928 bit_mask |= bit_mask << 16;
929 val = (val & bit_mask) | (s->latch & ~bit_mask);
930
931 do_write:
932 /* mask data according to sr[2] */
546fa6ab
FB
933 mask = s->sr[2];
934 s->plane_updated |= mask; /* only used to detect font change */
935 write_mask = mask16[mask];
5fafdf24
TS
936 ((uint32_t *)s->vram_ptr)[addr] =
937 (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
e89f66ec 938 (val & write_mask);
17b0018b 939#ifdef DEBUG_VGA_MEM
0bf9e31a
BS
940 printf("vga: latch: [0x" TARGET_FMT_plx "] mask=0x%08x val=0x%08x\n",
941 addr * 4, write_mask, val);
e89f66ec 942#endif
b1950430 943 memory_region_set_dirty(&s->vram, addr << 2);
e89f66ec
FB
944 }
945}
946
e89f66ec
FB
947typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
948 const uint8_t *font_ptr, int h,
949 uint32_t fgcol, uint32_t bgcol);
950typedef void vga_draw_glyph9_func(uint8_t *d, int linesize,
5fafdf24 951 const uint8_t *font_ptr, int h,
e89f66ec 952 uint32_t fgcol, uint32_t bgcol, int dup9);
cedd91d2 953typedef void vga_draw_line_func(VGACommonState *s1, uint8_t *d,
e89f66ec
FB
954 const uint8_t *s, int width);
955
e89f66ec
FB
956#define DEPTH 8
957#include "vga_template.h"
958
959#define DEPTH 15
960#include "vga_template.h"
961
a2502b58
BS
962#define BGR_FORMAT
963#define DEPTH 15
964#include "vga_template.h"
965
966#define DEPTH 16
967#include "vga_template.h"
968
969#define BGR_FORMAT
e89f66ec
FB
970#define DEPTH 16
971#include "vga_template.h"
972
973#define DEPTH 32
974#include "vga_template.h"
975
d3079cd2
FB
976#define BGR_FORMAT
977#define DEPTH 32
978#include "vga_template.h"
979
17b0018b
FB
980static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
981{
982 unsigned int col;
983 col = rgb_to_pixel8(r, g, b);
984 col |= col << 8;
985 col |= col << 16;
986 return col;
987}
988
989static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b)
990{
991 unsigned int col;
992 col = rgb_to_pixel15(r, g, b);
993 col |= col << 16;
994 return col;
995}
996
b29169d2
BS
997static unsigned int rgb_to_pixel15bgr_dup(unsigned int r, unsigned int g,
998 unsigned int b)
999{
1000 unsigned int col;
1001 col = rgb_to_pixel15bgr(r, g, b);
1002 col |= col << 16;
1003 return col;
1004}
1005
17b0018b
FB
1006static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
1007{
1008 unsigned int col;
1009 col = rgb_to_pixel16(r, g, b);
1010 col |= col << 16;
1011 return col;
1012}
1013
b29169d2
BS
1014static unsigned int rgb_to_pixel16bgr_dup(unsigned int r, unsigned int g,
1015 unsigned int b)
1016{
1017 unsigned int col;
1018 col = rgb_to_pixel16bgr(r, g, b);
1019 col |= col << 16;
1020 return col;
1021}
1022
17b0018b
FB
1023static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
1024{
1025 unsigned int col;
1026 col = rgb_to_pixel32(r, g, b);
1027 return col;
1028}
1029
d3079cd2
FB
1030static unsigned int rgb_to_pixel32bgr_dup(unsigned int r, unsigned int g, unsigned b)
1031{
1032 unsigned int col;
1033 col = rgb_to_pixel32bgr(r, g, b);
1034 return col;
1035}
1036
e89f66ec 1037/* return true if the palette was modified */
cedd91d2 1038static int update_palette16(VGACommonState *s)
e89f66ec 1039{
17b0018b 1040 int full_update, i;
e89f66ec 1041 uint32_t v, col, *palette;
e89f66ec
FB
1042
1043 full_update = 0;
1044 palette = s->last_palette;
1045 for(i = 0; i < 16; i++) {
1046 v = s->ar[i];
1047 if (s->ar[0x10] & 0x80)
1048 v = ((s->ar[0x14] & 0xf) << 4) | (v & 0xf);
1049 else
1050 v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f);
1051 v = v * 3;
5fafdf24
TS
1052 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
1053 c6_to_8(s->palette[v + 1]),
17b0018b
FB
1054 c6_to_8(s->palette[v + 2]));
1055 if (col != palette[i]) {
1056 full_update = 1;
1057 palette[i] = col;
e89f66ec 1058 }
17b0018b
FB
1059 }
1060 return full_update;
1061}
1062
1063/* return true if the palette was modified */
cedd91d2 1064static int update_palette256(VGACommonState *s)
17b0018b
FB
1065{
1066 int full_update, i;
1067 uint32_t v, col, *palette;
1068
1069 full_update = 0;
1070 palette = s->last_palette;
1071 v = 0;
1072 for(i = 0; i < 256; i++) {
37dd208d 1073 if (s->dac_8bit) {
5fafdf24
TS
1074 col = s->rgb_to_pixel(s->palette[v],
1075 s->palette[v + 1],
37dd208d
FB
1076 s->palette[v + 2]);
1077 } else {
5fafdf24
TS
1078 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
1079 c6_to_8(s->palette[v + 1]),
37dd208d
FB
1080 c6_to_8(s->palette[v + 2]));
1081 }
e89f66ec
FB
1082 if (col != palette[i]) {
1083 full_update = 1;
1084 palette[i] = col;
1085 }
17b0018b 1086 v += 3;
e89f66ec
FB
1087 }
1088 return full_update;
1089}
1090
cedd91d2 1091static void vga_get_offsets(VGACommonState *s,
5fafdf24 1092 uint32_t *pline_offset,
83acc96b
FB
1093 uint32_t *pstart_addr,
1094 uint32_t *pline_compare)
e89f66ec 1095{
83acc96b 1096 uint32_t start_addr, line_offset, line_compare;
4fa0f5d2
FB
1097#ifdef CONFIG_BOCHS_VBE
1098 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1099 line_offset = s->vbe_line_offset;
1100 start_addr = s->vbe_start_addr;
83acc96b 1101 line_compare = 65535;
4fa0f5d2
FB
1102 } else
1103#endif
3b46e624 1104 {
4fa0f5d2
FB
1105 /* compute line_offset in bytes */
1106 line_offset = s->cr[0x13];
4fa0f5d2 1107 line_offset <<= 3;
08e48902 1108
4fa0f5d2
FB
1109 /* starting address */
1110 start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8);
83acc96b
FB
1111
1112 /* line compare */
5fafdf24 1113 line_compare = s->cr[0x18] |
83acc96b
FB
1114 ((s->cr[0x07] & 0x10) << 4) |
1115 ((s->cr[0x09] & 0x40) << 3);
4fa0f5d2 1116 }
798b0c25
FB
1117 *pline_offset = line_offset;
1118 *pstart_addr = start_addr;
83acc96b 1119 *pline_compare = line_compare;
798b0c25
FB
1120}
1121
1122/* update start_addr and line_offset. Return TRUE if modified */
cedd91d2 1123static int update_basic_params(VGACommonState *s)
798b0c25
FB
1124{
1125 int full_update;
1126 uint32_t start_addr, line_offset, line_compare;
3b46e624 1127
798b0c25
FB
1128 full_update = 0;
1129
83acc96b 1130 s->get_offsets(s, &line_offset, &start_addr, &line_compare);
e89f66ec
FB
1131
1132 if (line_offset != s->line_offset ||
1133 start_addr != s->start_addr ||
1134 line_compare != s->line_compare) {
1135 s->line_offset = line_offset;
1136 s->start_addr = start_addr;
1137 s->line_compare = line_compare;
1138 full_update = 1;
1139 }
1140 return full_update;
1141}
1142
b29169d2 1143#define NB_DEPTHS 7
d3079cd2
FB
1144
1145static inline int get_depth_index(DisplayState *s)
e89f66ec 1146{
0e1f5a0c 1147 switch(ds_get_bits_per_pixel(s)) {
e89f66ec
FB
1148 default:
1149 case 8:
1150 return 0;
1151 case 15:
8927bcfd 1152 return 1;
e89f66ec 1153 case 16:
8927bcfd 1154 return 2;
e89f66ec 1155 case 32:
7b5d76da
AL
1156 if (is_surface_bgr(s->surface))
1157 return 4;
1158 else
1159 return 3;
e89f66ec
FB
1160 }
1161}
1162
68f04a3c 1163static vga_draw_glyph8_func * const vga_draw_glyph8_table[NB_DEPTHS] = {
e89f66ec
FB
1164 vga_draw_glyph8_8,
1165 vga_draw_glyph8_16,
1166 vga_draw_glyph8_16,
1167 vga_draw_glyph8_32,
d3079cd2 1168 vga_draw_glyph8_32,
b29169d2
BS
1169 vga_draw_glyph8_16,
1170 vga_draw_glyph8_16,
e89f66ec
FB
1171};
1172
68f04a3c 1173static vga_draw_glyph8_func * const vga_draw_glyph16_table[NB_DEPTHS] = {
17b0018b
FB
1174 vga_draw_glyph16_8,
1175 vga_draw_glyph16_16,
1176 vga_draw_glyph16_16,
1177 vga_draw_glyph16_32,
d3079cd2 1178 vga_draw_glyph16_32,
b29169d2
BS
1179 vga_draw_glyph16_16,
1180 vga_draw_glyph16_16,
17b0018b
FB
1181};
1182
68f04a3c 1183static vga_draw_glyph9_func * const vga_draw_glyph9_table[NB_DEPTHS] = {
e89f66ec
FB
1184 vga_draw_glyph9_8,
1185 vga_draw_glyph9_16,
1186 vga_draw_glyph9_16,
1187 vga_draw_glyph9_32,
d3079cd2 1188 vga_draw_glyph9_32,
b29169d2
BS
1189 vga_draw_glyph9_16,
1190 vga_draw_glyph9_16,
e89f66ec 1191};
3b46e624 1192
e89f66ec
FB
1193static const uint8_t cursor_glyph[32 * 4] = {
1194 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1195 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1196 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1197 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1198 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1199 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1200 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1201 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1202 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1203 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1204 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1205 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1206 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1207 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1208 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1209 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
3b46e624 1210};
e89f66ec 1211
cedd91d2 1212static void vga_get_text_resolution(VGACommonState *s, int *pwidth, int *pheight,
4c5e8c5c
BS
1213 int *pcwidth, int *pcheight)
1214{
1215 int width, cwidth, height, cheight;
1216
1217 /* total width & height */
1218 cheight = (s->cr[9] & 0x1f) + 1;
1219 cwidth = 8;
1220 if (!(s->sr[1] & 0x01))
1221 cwidth = 9;
1222 if (s->sr[1] & 0x08)
1223 cwidth = 16; /* NOTE: no 18 pixel wide */
1224 width = (s->cr[0x01] + 1);
1225 if (s->cr[0x06] == 100) {
1226 /* ugly hack for CGA 160x100x16 - explain me the logic */
1227 height = 100;
1228 } else {
1229 height = s->cr[0x12] |
1230 ((s->cr[0x07] & 0x02) << 7) |
1231 ((s->cr[0x07] & 0x40) << 3);
1232 height = (height + 1) / cheight;
1233 }
1234
1235 *pwidth = width;
1236 *pheight = height;
1237 *pcwidth = cwidth;
1238 *pcheight = cheight;
1239}
1240
7d957bd8
AL
1241typedef unsigned int rgb_to_pixel_dup_func(unsigned int r, unsigned int g, unsigned b);
1242
68f04a3c 1243static rgb_to_pixel_dup_func * const rgb_to_pixel_dup_table[NB_DEPTHS] = {
bdb19571
AL
1244 rgb_to_pixel8_dup,
1245 rgb_to_pixel15_dup,
1246 rgb_to_pixel16_dup,
1247 rgb_to_pixel32_dup,
1248 rgb_to_pixel32bgr_dup,
1249 rgb_to_pixel15bgr_dup,
1250 rgb_to_pixel16bgr_dup,
1251};
7d957bd8 1252
5fafdf24
TS
1253/*
1254 * Text mode update
e89f66ec
FB
1255 * Missing:
1256 * - double scan
5fafdf24 1257 * - double width
e89f66ec
FB
1258 * - underline
1259 * - flashing
1260 */
cedd91d2 1261static void vga_draw_text(VGACommonState *s, int full_update)
e89f66ec
FB
1262{
1263 int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
cae334cd 1264 int cx_min, cx_max, linesize, x_incr, line, line1;
e89f66ec 1265 uint32_t offset, fgcol, bgcol, v, cursor_offset;
d1984194 1266 uint8_t *d1, *d, *src, *dest, *cursor_ptr;
e89f66ec
FB
1267 const uint8_t *font_ptr, *font_base[2];
1268 int dup9, line_offset, depth_index;
1269 uint32_t *palette;
1270 uint32_t *ch_attr_ptr;
1271 vga_draw_glyph8_func *vga_draw_glyph8;
1272 vga_draw_glyph9_func *vga_draw_glyph9;
1273
e89f66ec
FB
1274 /* compute font data address (in plane 2) */
1275 v = s->sr[3];
1078f663 1276 offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
e89f66ec
FB
1277 if (offset != s->font_offsets[0]) {
1278 s->font_offsets[0] = offset;
1279 full_update = 1;
1280 }
1281 font_base[0] = s->vram_ptr + offset;
1282
1078f663 1283 offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
e89f66ec
FB
1284 font_base[1] = s->vram_ptr + offset;
1285 if (offset != s->font_offsets[1]) {
1286 s->font_offsets[1] = offset;
1287 full_update = 1;
1288 }
80763888 1289 if (s->plane_updated & (1 << 2) || s->chain4_alias) {
546fa6ab
FB
1290 /* if the plane 2 was modified since the last display, it
1291 indicates the font may have been modified */
1292 s->plane_updated = 0;
1293 full_update = 1;
1294 }
799e709b 1295 full_update |= update_basic_params(s);
e89f66ec
FB
1296
1297 line_offset = s->line_offset;
e89f66ec 1298
4c5e8c5c 1299 vga_get_text_resolution(s, &width, &height, &cw, &cheight);
3294b949
FB
1300 if ((height * width) > CH_ATTR_SIZE) {
1301 /* better than nothing: exit if transient size is too big */
1302 return;
1303 }
1304
799e709b
AL
1305 if (width != s->last_width || height != s->last_height ||
1306 cw != s->last_cw || cheight != s->last_ch || s->last_depth) {
1307 s->last_scr_width = width * cw;
1308 s->last_scr_height = height * cheight;
1309 qemu_console_resize(s->ds, s->last_scr_width, s->last_scr_height);
1310 s->last_depth = 0;
1311 s->last_width = width;
1312 s->last_height = height;
1313 s->last_ch = cheight;
1314 s->last_cw = cw;
1315 full_update = 1;
1316 }
7d957bd8
AL
1317 s->rgb_to_pixel =
1318 rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1319 full_update |= update_palette16(s);
1320 palette = s->last_palette;
1321 x_incr = cw * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
1322
e89f66ec
FB
1323 cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
1324 if (cursor_offset != s->cursor_offset ||
1325 s->cr[0xa] != s->cursor_start ||
1326 s->cr[0xb] != s->cursor_end) {
1327 /* if the cursor position changed, we update the old and new
1328 chars */
1329 if (s->cursor_offset < CH_ATTR_SIZE)
1330 s->last_ch_attr[s->cursor_offset] = -1;
1331 if (cursor_offset < CH_ATTR_SIZE)
1332 s->last_ch_attr[cursor_offset] = -1;
1333 s->cursor_offset = cursor_offset;
1334 s->cursor_start = s->cr[0xa];
1335 s->cursor_end = s->cr[0xb];
1336 }
39cf7803 1337 cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
3b46e624 1338
d3079cd2 1339 depth_index = get_depth_index(s->ds);
17b0018b
FB
1340 if (cw == 16)
1341 vga_draw_glyph8 = vga_draw_glyph16_table[depth_index];
1342 else
1343 vga_draw_glyph8 = vga_draw_glyph8_table[depth_index];
e89f66ec 1344 vga_draw_glyph9 = vga_draw_glyph9_table[depth_index];
3b46e624 1345
0e1f5a0c
AL
1346 dest = ds_get_data(s->ds);
1347 linesize = ds_get_linesize(s->ds);
e89f66ec 1348 ch_attr_ptr = s->last_ch_attr;
d1984194 1349 line = 0;
1350 offset = s->start_addr * 4;
e89f66ec
FB
1351 for(cy = 0; cy < height; cy++) {
1352 d1 = dest;
d1984194 1353 src = s->vram_ptr + offset;
e89f66ec
FB
1354 cx_min = width;
1355 cx_max = -1;
1356 for(cx = 0; cx < width; cx++) {
1357 ch_attr = *(uint16_t *)src;
1358 if (full_update || ch_attr != *ch_attr_ptr) {
1359 if (cx < cx_min)
1360 cx_min = cx;
1361 if (cx > cx_max)
1362 cx_max = cx;
1363 *ch_attr_ptr = ch_attr;
e2542fe2 1364#ifdef HOST_WORDS_BIGENDIAN
e89f66ec
FB
1365 ch = ch_attr >> 8;
1366 cattr = ch_attr & 0xff;
1367#else
1368 ch = ch_attr & 0xff;
1369 cattr = ch_attr >> 8;
1370#endif
1371 font_ptr = font_base[(cattr >> 3) & 1];
1372 font_ptr += 32 * 4 * ch;
1373 bgcol = palette[cattr >> 4];
1374 fgcol = palette[cattr & 0x0f];
17b0018b 1375 if (cw != 9) {
5fafdf24 1376 vga_draw_glyph8(d1, linesize,
e89f66ec
FB
1377 font_ptr, cheight, fgcol, bgcol);
1378 } else {
1379 dup9 = 0;
1380 if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))
1381 dup9 = 1;
5fafdf24 1382 vga_draw_glyph9(d1, linesize,
e89f66ec
FB
1383 font_ptr, cheight, fgcol, bgcol, dup9);
1384 }
1385 if (src == cursor_ptr &&
1386 !(s->cr[0x0a] & 0x20)) {
1387 int line_start, line_last, h;
1388 /* draw the cursor */
1389 line_start = s->cr[0x0a] & 0x1f;
1390 line_last = s->cr[0x0b] & 0x1f;
1391 /* XXX: check that */
1392 if (line_last > cheight - 1)
1393 line_last = cheight - 1;
1394 if (line_last >= line_start && line_start < cheight) {
1395 h = line_last - line_start + 1;
1396 d = d1 + linesize * line_start;
17b0018b 1397 if (cw != 9) {
5fafdf24 1398 vga_draw_glyph8(d, linesize,
e89f66ec
FB
1399 cursor_glyph, h, fgcol, bgcol);
1400 } else {
5fafdf24 1401 vga_draw_glyph9(d, linesize,
e89f66ec
FB
1402 cursor_glyph, h, fgcol, bgcol, 1);
1403 }
1404 }
1405 }
1406 }
1407 d1 += x_incr;
1408 src += 4;
1409 ch_attr_ptr++;
1410 }
1411 if (cx_max != -1) {
5fafdf24 1412 dpy_update(s->ds, cx_min * cw, cy * cheight,
e89f66ec
FB
1413 (cx_max - cx_min + 1) * cw, cheight);
1414 }
1415 dest += linesize * cheight;
cae334cd 1416 line1 = line + cheight;
1417 offset += line_offset;
1418 if (line < s->line_compare && line1 >= s->line_compare) {
d1984194 1419 offset = 0;
1420 }
cae334cd 1421 line = line1;
e89f66ec
FB
1422 }
1423}
1424
17b0018b
FB
1425enum {
1426 VGA_DRAW_LINE2,
1427 VGA_DRAW_LINE2D2,
1428 VGA_DRAW_LINE4,
1429 VGA_DRAW_LINE4D2,
1430 VGA_DRAW_LINE8D2,
1431 VGA_DRAW_LINE8,
1432 VGA_DRAW_LINE15,
1433 VGA_DRAW_LINE16,
4fa0f5d2 1434 VGA_DRAW_LINE24,
17b0018b
FB
1435 VGA_DRAW_LINE32,
1436 VGA_DRAW_LINE_NB,
1437};
1438
68f04a3c 1439static vga_draw_line_func * const vga_draw_line_table[NB_DEPTHS * VGA_DRAW_LINE_NB] = {
e89f66ec
FB
1440 vga_draw_line2_8,
1441 vga_draw_line2_16,
1442 vga_draw_line2_16,
1443 vga_draw_line2_32,
d3079cd2 1444 vga_draw_line2_32,
b29169d2
BS
1445 vga_draw_line2_16,
1446 vga_draw_line2_16,
e89f66ec 1447
17b0018b
FB
1448 vga_draw_line2d2_8,
1449 vga_draw_line2d2_16,
1450 vga_draw_line2d2_16,
1451 vga_draw_line2d2_32,
d3079cd2 1452 vga_draw_line2d2_32,
b29169d2
BS
1453 vga_draw_line2d2_16,
1454 vga_draw_line2d2_16,
17b0018b 1455
e89f66ec
FB
1456 vga_draw_line4_8,
1457 vga_draw_line4_16,
1458 vga_draw_line4_16,
1459 vga_draw_line4_32,
d3079cd2 1460 vga_draw_line4_32,
b29169d2
BS
1461 vga_draw_line4_16,
1462 vga_draw_line4_16,
e89f66ec 1463
17b0018b
FB
1464 vga_draw_line4d2_8,
1465 vga_draw_line4d2_16,
1466 vga_draw_line4d2_16,
1467 vga_draw_line4d2_32,
d3079cd2 1468 vga_draw_line4d2_32,
b29169d2
BS
1469 vga_draw_line4d2_16,
1470 vga_draw_line4d2_16,
17b0018b
FB
1471
1472 vga_draw_line8d2_8,
1473 vga_draw_line8d2_16,
1474 vga_draw_line8d2_16,
1475 vga_draw_line8d2_32,
d3079cd2 1476 vga_draw_line8d2_32,
b29169d2
BS
1477 vga_draw_line8d2_16,
1478 vga_draw_line8d2_16,
17b0018b 1479
e89f66ec
FB
1480 vga_draw_line8_8,
1481 vga_draw_line8_16,
1482 vga_draw_line8_16,
1483 vga_draw_line8_32,
d3079cd2 1484 vga_draw_line8_32,
b29169d2
BS
1485 vga_draw_line8_16,
1486 vga_draw_line8_16,
e89f66ec
FB
1487
1488 vga_draw_line15_8,
1489 vga_draw_line15_15,
1490 vga_draw_line15_16,
1491 vga_draw_line15_32,
d3079cd2 1492 vga_draw_line15_32bgr,
b29169d2
BS
1493 vga_draw_line15_15bgr,
1494 vga_draw_line15_16bgr,
e89f66ec
FB
1495
1496 vga_draw_line16_8,
1497 vga_draw_line16_15,
1498 vga_draw_line16_16,
1499 vga_draw_line16_32,
d3079cd2 1500 vga_draw_line16_32bgr,
b29169d2
BS
1501 vga_draw_line16_15bgr,
1502 vga_draw_line16_16bgr,
e89f66ec 1503
4fa0f5d2
FB
1504 vga_draw_line24_8,
1505 vga_draw_line24_15,
1506 vga_draw_line24_16,
1507 vga_draw_line24_32,
d3079cd2 1508 vga_draw_line24_32bgr,
b29169d2
BS
1509 vga_draw_line24_15bgr,
1510 vga_draw_line24_16bgr,
4fa0f5d2 1511
e89f66ec
FB
1512 vga_draw_line32_8,
1513 vga_draw_line32_15,
1514 vga_draw_line32_16,
1515 vga_draw_line32_32,
d3079cd2 1516 vga_draw_line32_32bgr,
b29169d2
BS
1517 vga_draw_line32_15bgr,
1518 vga_draw_line32_16bgr,
d3079cd2
FB
1519};
1520
cedd91d2 1521static int vga_get_bpp(VGACommonState *s)
798b0c25
FB
1522{
1523 int ret;
1524#ifdef CONFIG_BOCHS_VBE
1525 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1526 ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
5fafdf24 1527 } else
798b0c25
FB
1528#endif
1529 {
1530 ret = 0;
1531 }
1532 return ret;
1533}
1534
cedd91d2 1535static void vga_get_resolution(VGACommonState *s, int *pwidth, int *pheight)
a130a41e
FB
1536{
1537 int width, height;
3b46e624 1538
8454df8b
FB
1539#ifdef CONFIG_BOCHS_VBE
1540 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1541 width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
1542 height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
5fafdf24 1543 } else
8454df8b
FB
1544#endif
1545 {
1546 width = (s->cr[0x01] + 1) * 8;
5fafdf24
TS
1547 height = s->cr[0x12] |
1548 ((s->cr[0x07] & 0x02) << 7) |
8454df8b
FB
1549 ((s->cr[0x07] & 0x40) << 3);
1550 height = (height + 1);
1551 }
a130a41e
FB
1552 *pwidth = width;
1553 *pheight = height;
1554}
1555
cedd91d2 1556void vga_invalidate_scanlines(VGACommonState *s, int y1, int y2)
a8aa669b
FB
1557{
1558 int y;
1559 if (y1 >= VGA_MAX_HEIGHT)
1560 return;
1561 if (y2 >= VGA_MAX_HEIGHT)
1562 y2 = VGA_MAX_HEIGHT;
1563 for(y = y1; y < y2; y++) {
1564 s->invalidated_y_table[y >> 5] |= 1 << (y & 0x1f);
1565 }
1566}
1567
cedd91d2 1568static void vga_sync_dirty_bitmap(VGACommonState *s)
2bec46dc 1569{
b1950430 1570 memory_region_sync_dirty_bitmap(&s->vram);
2bec46dc
AL
1571}
1572
50af3246
JQ
1573void vga_dirty_log_start(VGACommonState *s)
1574{
b1950430 1575 memory_region_set_log(&s->vram, true, DIRTY_MEMORY_VGA);
b5cc6e32
AL
1576}
1577
1578void vga_dirty_log_stop(VGACommonState *s)
1579{
b1950430 1580 memory_region_set_log(&s->vram, false, DIRTY_MEMORY_VGA);
b5cc6e32
AL
1581}
1582
799e709b
AL
1583/*
1584 * graphic modes
1585 */
cedd91d2 1586static void vga_draw_graphic(VGACommonState *s, int full_update)
e89f66ec 1587{
12c7e75a
AK
1588 int y1, y, update, linesize, y_start, double_scan, mask, depth;
1589 int width, height, shift_control, line_offset, bwidth, bits;
c227f099 1590 ram_addr_t page0, page1, page_min, page_max;
a07cf92a 1591 int disp_width, multi_scan, multi_run;
799e709b
AL
1592 uint8_t *d;
1593 uint32_t v, addr1, addr;
1594 vga_draw_line_func *vga_draw_line;
1595
1596 full_update |= update_basic_params(s);
1597
1598 if (!full_update)
1599 vga_sync_dirty_bitmap(s);
2bec46dc 1600
a130a41e 1601 s->get_resolution(s, &width, &height);
17b0018b 1602 disp_width = width;
09a79b49 1603
e89f66ec 1604 shift_control = (s->gr[0x05] >> 5) & 3;
f6c958c8 1605 double_scan = (s->cr[0x09] >> 7);
799e709b
AL
1606 if (shift_control != 1) {
1607 multi_scan = (((s->cr[0x09] & 0x1f) + 1) << double_scan) - 1;
1608 } else {
1609 /* in CGA modes, multi_scan is ignored */
1610 /* XXX: is it correct ? */
1611 multi_scan = double_scan;
1612 }
1613 multi_run = multi_scan;
17b0018b
FB
1614 if (shift_control != s->shift_control ||
1615 double_scan != s->double_scan) {
799e709b 1616 full_update = 1;
e89f66ec 1617 s->shift_control = shift_control;
17b0018b 1618 s->double_scan = double_scan;
e89f66ec 1619 }
3b46e624 1620
aba35a6c 1621 if (shift_control == 0) {
1622 if (s->sr[0x01] & 8) {
1623 disp_width <<= 1;
1624 }
1625 } else if (shift_control == 1) {
1626 if (s->sr[0x01] & 8) {
1627 disp_width <<= 1;
1628 }
1629 }
1630
799e709b 1631 depth = s->get_bpp(s);
e3697092
AJ
1632 if (s->line_offset != s->last_line_offset ||
1633 disp_width != s->last_width ||
1634 height != s->last_height ||
799e709b 1635 s->last_depth != depth) {
e2542fe2 1636#if defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
e3697092 1637 if (depth == 16 || depth == 32) {
0da2ea1b 1638#else
1639 if (depth == 32) {
1640#endif
b8c18e4c
AL
1641 qemu_free_displaysurface(s->ds);
1642 s->ds->surface = qemu_create_displaysurface_from(disp_width, height, depth,
1643 s->line_offset,
1644 s->vram_ptr + (s->start_addr * 4));
e2542fe2 1645#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
b8c18e4c 1646 s->ds->surface->pf = qemu_different_endianness_pixelformat(depth);
0da2ea1b 1647#endif
b8c18e4c 1648 dpy_resize(s->ds);
e3697092
AJ
1649 } else {
1650 qemu_console_resize(s->ds, disp_width, height);
1651 }
1652 s->last_scr_width = disp_width;
1653 s->last_scr_height = height;
1654 s->last_width = disp_width;
1655 s->last_height = height;
1656 s->last_line_offset = s->line_offset;
1657 s->last_depth = depth;
799e709b
AL
1658 full_update = 1;
1659 } else if (is_buffer_shared(s->ds->surface) &&
e3697092
AJ
1660 (full_update || s->ds->surface->data != s->vram_ptr + (s->start_addr * 4))) {
1661 s->ds->surface->data = s->vram_ptr + (s->start_addr * 4);
1662 dpy_setdata(s->ds);
1663 }
1664
1665 s->rgb_to_pixel =
1666 rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1667
799e709b 1668 if (shift_control == 0) {
17b0018b
FB
1669 full_update |= update_palette16(s);
1670 if (s->sr[0x01] & 8) {
1671 v = VGA_DRAW_LINE4D2;
17b0018b
FB
1672 } else {
1673 v = VGA_DRAW_LINE4;
1674 }
15342721 1675 bits = 4;
799e709b 1676 } else if (shift_control == 1) {
17b0018b
FB
1677 full_update |= update_palette16(s);
1678 if (s->sr[0x01] & 8) {
1679 v = VGA_DRAW_LINE2D2;
17b0018b
FB
1680 } else {
1681 v = VGA_DRAW_LINE2;
1682 }
15342721 1683 bits = 4;
17b0018b 1684 } else {
798b0c25
FB
1685 switch(s->get_bpp(s)) {
1686 default:
1687 case 0:
4fa0f5d2
FB
1688 full_update |= update_palette256(s);
1689 v = VGA_DRAW_LINE8D2;
15342721 1690 bits = 4;
798b0c25
FB
1691 break;
1692 case 8:
1693 full_update |= update_palette256(s);
1694 v = VGA_DRAW_LINE8;
15342721 1695 bits = 8;
798b0c25
FB
1696 break;
1697 case 15:
1698 v = VGA_DRAW_LINE15;
15342721 1699 bits = 16;
798b0c25
FB
1700 break;
1701 case 16:
1702 v = VGA_DRAW_LINE16;
15342721 1703 bits = 16;
798b0c25
FB
1704 break;
1705 case 24:
1706 v = VGA_DRAW_LINE24;
15342721 1707 bits = 24;
798b0c25
FB
1708 break;
1709 case 32:
1710 v = VGA_DRAW_LINE32;
15342721 1711 bits = 32;
798b0c25 1712 break;
4fa0f5d2 1713 }
17b0018b 1714 }
d3079cd2 1715 vga_draw_line = vga_draw_line_table[v * NB_DEPTHS + get_depth_index(s->ds)];
17b0018b 1716
7d957bd8 1717 if (!is_buffer_shared(s->ds->surface) && s->cursor_invalidate)
a8aa669b 1718 s->cursor_invalidate(s);
3b46e624 1719
e89f66ec 1720 line_offset = s->line_offset;
17b0018b 1721#if 0
f6c958c8 1722 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",
17b0018b
FB
1723 width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]);
1724#endif
e89f66ec 1725 addr1 = (s->start_addr * 4);
15342721 1726 bwidth = (width * bits + 7) / 8;
39cf7803 1727 y_start = -1;
12c7e75a
AK
1728 page_min = -1;
1729 page_max = 0;
0e1f5a0c
AL
1730 d = ds_get_data(s->ds);
1731 linesize = ds_get_linesize(s->ds);
17b0018b 1732 y1 = 0;
e89f66ec
FB
1733 for(y = 0; y < height; y++) {
1734 addr = addr1;
39cf7803 1735 if (!(s->cr[0x17] & 1)) {
17b0018b 1736 int shift;
e89f66ec 1737 /* CGA compatibility handling */
17b0018b
FB
1738 shift = 14 + ((s->cr[0x17] >> 6) & 1);
1739 addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
e89f66ec 1740 }
39cf7803 1741 if (!(s->cr[0x17] & 2)) {
17b0018b 1742 addr = (addr & ~0x8000) | ((y1 & 2) << 14);
e89f66ec 1743 }
b1950430
AK
1744 page0 = addr & TARGET_PAGE_MASK;
1745 page1 = (addr + bwidth - 1) & TARGET_PAGE_MASK;
5fafdf24 1746 update = full_update |
b1950430
AK
1747 memory_region_get_dirty(&s->vram, page0, DIRTY_MEMORY_VGA) |
1748 memory_region_get_dirty(&s->vram, page1, DIRTY_MEMORY_VGA);
4fa0f5d2 1749 if ((page1 - page0) > TARGET_PAGE_SIZE) {
39cf7803 1750 /* if wide line, can use another page */
b1950430
AK
1751 update |= memory_region_get_dirty(&s->vram,
1752 page0 + TARGET_PAGE_SIZE,
1753 DIRTY_MEMORY_VGA);
39cf7803 1754 }
a8aa669b
FB
1755 /* explicit invalidation for the hardware cursor */
1756 update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
e89f66ec 1757 if (update) {
39cf7803
FB
1758 if (y_start < 0)
1759 y_start = y;
e89f66ec
FB
1760 if (page0 < page_min)
1761 page_min = page0;
1762 if (page1 > page_max)
1763 page_max = page1;
7d957bd8
AL
1764 if (!(is_buffer_shared(s->ds->surface))) {
1765 vga_draw_line(s, d, s->vram_ptr + addr, width);
1766 if (s->cursor_draw_line)
1767 s->cursor_draw_line(s, d, y);
1768 }
39cf7803
FB
1769 } else {
1770 if (y_start >= 0) {
1771 /* flush to display */
5fafdf24 1772 dpy_update(s->ds, 0, y_start,
799e709b 1773 disp_width, y - y_start);
39cf7803
FB
1774 y_start = -1;
1775 }
e89f66ec 1776 }
a07cf92a 1777 if (!multi_run) {
f6c958c8
FB
1778 mask = (s->cr[0x17] & 3) ^ 3;
1779 if ((y1 & mask) == mask)
1780 addr1 += line_offset;
1781 y1++;
799e709b 1782 multi_run = multi_scan;
a07cf92a
FB
1783 } else {
1784 multi_run--;
e89f66ec 1785 }
f6c958c8
FB
1786 /* line compare acts on the displayed lines */
1787 if (y == s->line_compare)
1788 addr1 = 0;
e89f66ec
FB
1789 d += linesize;
1790 }
39cf7803
FB
1791 if (y_start >= 0) {
1792 /* flush to display */
5fafdf24 1793 dpy_update(s->ds, 0, y_start,
799e709b 1794 disp_width, y - y_start);
39cf7803 1795 }
e89f66ec 1796 /* reset modified pages */
12c7e75a 1797 if (page_max >= page_min) {
b1950430
AK
1798 memory_region_reset_dirty(&s->vram,
1799 page_min,
1800 page_max + TARGET_PAGE_SIZE - page_min,
1801 DIRTY_MEMORY_VGA);
e89f66ec 1802 }
a8aa669b 1803 memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
e89f66ec
FB
1804}
1805
cedd91d2 1806static void vga_draw_blank(VGACommonState *s, int full_update)
2aebb3eb
FB
1807{
1808 int i, w, val;
1809 uint8_t *d;
1810
1811 if (!full_update)
1812 return;
1813 if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
1814 return;
2bec46dc 1815
7d957bd8
AL
1816 s->rgb_to_pixel =
1817 rgb_to_pixel_dup_table[get_depth_index(s->ds)];
0e1f5a0c 1818 if (ds_get_bits_per_pixel(s->ds) == 8)
2aebb3eb
FB
1819 val = s->rgb_to_pixel(0, 0, 0);
1820 else
1821 val = 0;
0e1f5a0c
AL
1822 w = s->last_scr_width * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
1823 d = ds_get_data(s->ds);
2aebb3eb
FB
1824 for(i = 0; i < s->last_scr_height; i++) {
1825 memset(d, val, w);
0e1f5a0c 1826 d += ds_get_linesize(s->ds);
2aebb3eb 1827 }
5fafdf24 1828 dpy_update(s->ds, 0, 0,
2aebb3eb
FB
1829 s->last_scr_width, s->last_scr_height);
1830}
1831
799e709b
AL
1832#define GMODE_TEXT 0
1833#define GMODE_GRAPH 1
1834#define GMODE_BLANK 2
1835
95219897 1836static void vga_update_display(void *opaque)
e89f66ec 1837{
cedd91d2 1838 VGACommonState *s = opaque;
799e709b 1839 int full_update, graphic_mode;
e89f66ec 1840
0e1f5a0c 1841 if (ds_get_bits_per_pixel(s->ds) == 0) {
0f35920c 1842 /* nothing to do */
59a983b9 1843 } else {
3098b9fd 1844 full_update = 0;
799e709b
AL
1845 if (!(s->ar_index & 0x20)) {
1846 graphic_mode = GMODE_BLANK;
1847 } else {
1848 graphic_mode = s->gr[6] & 1;
1849 }
1850 if (graphic_mode != s->graphic_mode) {
1851 s->graphic_mode = graphic_mode;
1852 full_update = 1;
1853 }
1854 switch(graphic_mode) {
2aebb3eb 1855 case GMODE_TEXT:
e89f66ec 1856 vga_draw_text(s, full_update);
2aebb3eb
FB
1857 break;
1858 case GMODE_GRAPH:
1859 vga_draw_graphic(s, full_update);
1860 break;
1861 case GMODE_BLANK:
1862 default:
1863 vga_draw_blank(s, full_update);
1864 break;
1865 }
e89f66ec
FB
1866 }
1867}
1868
a130a41e 1869/* force a full display refresh */
95219897 1870static void vga_invalidate_display(void *opaque)
a130a41e 1871{
cedd91d2 1872 VGACommonState *s = opaque;
3b46e624 1873
3098b9fd
AJ
1874 s->last_width = -1;
1875 s->last_height = -1;
a130a41e
FB
1876}
1877
03a3e7ba 1878void vga_common_reset(VGACommonState *s)
e89f66ec 1879{
6e6b7363
BS
1880 s->sr_index = 0;
1881 memset(s->sr, '\0', sizeof(s->sr));
1882 s->gr_index = 0;
1883 memset(s->gr, '\0', sizeof(s->gr));
1884 s->ar_index = 0;
1885 memset(s->ar, '\0', sizeof(s->ar));
1886 s->ar_flip_flop = 0;
1887 s->cr_index = 0;
1888 memset(s->cr, '\0', sizeof(s->cr));
1889 s->msr = 0;
1890 s->fcr = 0;
1891 s->st00 = 0;
1892 s->st01 = 0;
1893 s->dac_state = 0;
1894 s->dac_sub_index = 0;
1895 s->dac_read_index = 0;
1896 s->dac_write_index = 0;
1897 memset(s->dac_cache, '\0', sizeof(s->dac_cache));
1898 s->dac_8bit = 0;
1899 memset(s->palette, '\0', sizeof(s->palette));
1900 s->bank_offset = 0;
1901#ifdef CONFIG_BOCHS_VBE
1902 s->vbe_index = 0;
1903 memset(s->vbe_regs, '\0', sizeof(s->vbe_regs));
af92284b 1904 s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID5;
6e6b7363
BS
1905 s->vbe_start_addr = 0;
1906 s->vbe_line_offset = 0;
1907 s->vbe_bank_mask = (s->vram_size >> 16) - 1;
1908#endif
1909 memset(s->font_offsets, '\0', sizeof(s->font_offsets));
799e709b 1910 s->graphic_mode = -1; /* force full update */
6e6b7363
BS
1911 s->shift_control = 0;
1912 s->double_scan = 0;
1913 s->line_offset = 0;
1914 s->line_compare = 0;
1915 s->start_addr = 0;
1916 s->plane_updated = 0;
1917 s->last_cw = 0;
1918 s->last_ch = 0;
1919 s->last_width = 0;
1920 s->last_height = 0;
1921 s->last_scr_width = 0;
1922 s->last_scr_height = 0;
1923 s->cursor_start = 0;
1924 s->cursor_end = 0;
1925 s->cursor_offset = 0;
1926 memset(s->invalidated_y_table, '\0', sizeof(s->invalidated_y_table));
1927 memset(s->last_palette, '\0', sizeof(s->last_palette));
1928 memset(s->last_ch_attr, '\0', sizeof(s->last_ch_attr));
1929 switch (vga_retrace_method) {
1930 case VGA_RETRACE_DUMB:
1931 break;
1932 case VGA_RETRACE_PRECISE:
1933 memset(&s->retrace_info, 0, sizeof (s->retrace_info));
1934 break;
1935 }
80763888 1936 vga_update_memory_access(s);
e89f66ec
FB
1937}
1938
03a3e7ba
JQ
1939static void vga_reset(void *opaque)
1940{
cedd91d2 1941 VGACommonState *s = opaque;
03a3e7ba
JQ
1942 vga_common_reset(s);
1943}
1944
4d3b6f6e
AZ
1945#define TEXTMODE_X(x) ((x) % width)
1946#define TEXTMODE_Y(x) ((x) / width)
1947#define VMEM2CHTYPE(v) ((v & 0xff0007ff) | \
1948 ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1))
1949/* relay text rendering to the display driver
1950 * instead of doing a full vga_update_display() */
c227f099 1951static void vga_update_text(void *opaque, console_ch_t *chardata)
4d3b6f6e 1952{
cedd91d2 1953 VGACommonState *s = opaque;
799e709b 1954 int graphic_mode, i, cursor_offset, cursor_visible;
4d3b6f6e
AZ
1955 int cw, cheight, width, height, size, c_min, c_max;
1956 uint32_t *src;
c227f099 1957 console_ch_t *dst, val;
4d3b6f6e 1958 char msg_buffer[80];
799e709b
AL
1959 int full_update = 0;
1960
1961 if (!(s->ar_index & 0x20)) {
1962 graphic_mode = GMODE_BLANK;
1963 } else {
1964 graphic_mode = s->gr[6] & 1;
1965 }
1966 if (graphic_mode != s->graphic_mode) {
1967 s->graphic_mode = graphic_mode;
1968 full_update = 1;
1969 }
1970 if (s->last_width == -1) {
1971 s->last_width = 0;
1972 full_update = 1;
1973 }
4d3b6f6e 1974
799e709b 1975 switch (graphic_mode) {
4d3b6f6e
AZ
1976 case GMODE_TEXT:
1977 /* TODO: update palette */
799e709b 1978 full_update |= update_basic_params(s);
4d3b6f6e 1979
799e709b
AL
1980 /* total width & height */
1981 cheight = (s->cr[9] & 0x1f) + 1;
1982 cw = 8;
1983 if (!(s->sr[1] & 0x01))
1984 cw = 9;
1985 if (s->sr[1] & 0x08)
1986 cw = 16; /* NOTE: no 18 pixel wide */
1987 width = (s->cr[0x01] + 1);
1988 if (s->cr[0x06] == 100) {
1989 /* ugly hack for CGA 160x100x16 - explain me the logic */
1990 height = 100;
1991 } else {
1992 height = s->cr[0x12] |
1993 ((s->cr[0x07] & 0x02) << 7) |
1994 ((s->cr[0x07] & 0x40) << 3);
1995 height = (height + 1) / cheight;
4d3b6f6e
AZ
1996 }
1997
1998 size = (height * width);
1999 if (size > CH_ATTR_SIZE) {
2000 if (!full_update)
2001 return;
2002
363a37d5
BS
2003 snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Text mode",
2004 width, height);
4d3b6f6e
AZ
2005 break;
2006 }
2007
799e709b
AL
2008 if (width != s->last_width || height != s->last_height ||
2009 cw != s->last_cw || cheight != s->last_ch) {
2010 s->last_scr_width = width * cw;
2011 s->last_scr_height = height * cheight;
2012 s->ds->surface->width = width;
2013 s->ds->surface->height = height;
2014 dpy_resize(s->ds);
2015 s->last_width = width;
2016 s->last_height = height;
2017 s->last_ch = cheight;
2018 s->last_cw = cw;
2019 full_update = 1;
2020 }
2021
4d3b6f6e
AZ
2022 /* Update "hardware" cursor */
2023 cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
2024 if (cursor_offset != s->cursor_offset ||
2025 s->cr[0xa] != s->cursor_start ||
2026 s->cr[0xb] != s->cursor_end || full_update) {
2027 cursor_visible = !(s->cr[0xa] & 0x20);
2028 if (cursor_visible && cursor_offset < size && cursor_offset >= 0)
2029 dpy_cursor(s->ds,
2030 TEXTMODE_X(cursor_offset),
2031 TEXTMODE_Y(cursor_offset));
2032 else
2033 dpy_cursor(s->ds, -1, -1);
2034 s->cursor_offset = cursor_offset;
2035 s->cursor_start = s->cr[0xa];
2036 s->cursor_end = s->cr[0xb];
2037 }
2038
2039 src = (uint32_t *) s->vram_ptr + s->start_addr;
2040 dst = chardata;
2041
2042 if (full_update) {
2043 for (i = 0; i < size; src ++, dst ++, i ++)
9ae19b65 2044 console_write_ch(dst, VMEM2CHTYPE(le32_to_cpu(*src)));
4d3b6f6e
AZ
2045
2046 dpy_update(s->ds, 0, 0, width, height);
2047 } else {
2048 c_max = 0;
2049
2050 for (i = 0; i < size; src ++, dst ++, i ++) {
9ae19b65 2051 console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
4d3b6f6e
AZ
2052 if (*dst != val) {
2053 *dst = val;
2054 c_max = i;
2055 break;
2056 }
2057 }
2058 c_min = i;
2059 for (; i < size; src ++, dst ++, i ++) {
9ae19b65 2060 console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
4d3b6f6e
AZ
2061 if (*dst != val) {
2062 *dst = val;
2063 c_max = i;
2064 }
2065 }
2066
2067 if (c_min <= c_max) {
2068 i = TEXTMODE_Y(c_min);
2069 dpy_update(s->ds, 0, i, width, TEXTMODE_Y(c_max) - i + 1);
2070 }
2071 }
2072
2073 return;
2074 case GMODE_GRAPH:
2075 if (!full_update)
2076 return;
2077
2078 s->get_resolution(s, &width, &height);
363a37d5
BS
2079 snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Graphic mode",
2080 width, height);
4d3b6f6e
AZ
2081 break;
2082 case GMODE_BLANK:
2083 default:
2084 if (!full_update)
2085 return;
2086
363a37d5 2087 snprintf(msg_buffer, sizeof(msg_buffer), "VGA Blank mode");
4d3b6f6e
AZ
2088 break;
2089 }
2090
2091 /* Display a message */
5228c2d3
AZ
2092 s->last_width = 60;
2093 s->last_height = height = 3;
4d3b6f6e 2094 dpy_cursor(s->ds, -1, -1);
7d957bd8
AL
2095 s->ds->surface->width = s->last_width;
2096 s->ds->surface->height = height;
2097 dpy_resize(s->ds);
4d3b6f6e 2098
5228c2d3 2099 for (dst = chardata, i = 0; i < s->last_width * height; i ++)
4d3b6f6e
AZ
2100 console_write_ch(dst ++, ' ');
2101
2102 size = strlen(msg_buffer);
5228c2d3
AZ
2103 width = (s->last_width - size) / 2;
2104 dst = chardata + s->last_width + width;
4d3b6f6e
AZ
2105 for (i = 0; i < size; i ++)
2106 console_write_ch(dst ++, 0x00200100 | msg_buffer[i]);
2107
5228c2d3 2108 dpy_update(s->ds, 0, 0, s->last_width, height);
4d3b6f6e
AZ
2109}
2110
b1950430
AK
2111static uint64_t vga_mem_read(void *opaque, target_phys_addr_t addr,
2112 unsigned size)
2113{
2114 VGACommonState *s = opaque;
2115
b2a5e761 2116 return vga_mem_readb(s, addr);
b1950430 2117}
e89f66ec 2118
b1950430
AK
2119static void vga_mem_write(void *opaque, target_phys_addr_t addr,
2120 uint64_t data, unsigned size)
2121{
2122 VGACommonState *s = opaque;
2123
b2a5e761 2124 return vga_mem_writeb(s, addr, data);
b1950430
AK
2125}
2126
2127const MemoryRegionOps vga_mem_ops = {
2128 .read = vga_mem_read,
2129 .write = vga_mem_write,
2130 .endianness = DEVICE_LITTLE_ENDIAN,
b2a5e761
AK
2131 .impl = {
2132 .min_access_size = 1,
2133 .max_access_size = 1,
2134 },
e89f66ec
FB
2135};
2136
11b6b345 2137static int vga_common_post_load(void *opaque, int version_id)
b0a21b53 2138{
0d65ddc3 2139 VGACommonState *s = opaque;
11b6b345
JQ
2140
2141 /* force refresh */
2142 s->graphic_mode = -1;
2143 return 0;
2144}
2145
2146const VMStateDescription vmstate_vga_common = {
2147 .name = "vga",
2148 .version_id = 2,
2149 .minimum_version_id = 2,
2150 .minimum_version_id_old = 2,
2151 .post_load = vga_common_post_load,
2152 .fields = (VMStateField []) {
2153 VMSTATE_UINT32(latch, VGACommonState),
2154 VMSTATE_UINT8(sr_index, VGACommonState),
2155 VMSTATE_PARTIAL_BUFFER(sr, VGACommonState, 8),
2156 VMSTATE_UINT8(gr_index, VGACommonState),
2157 VMSTATE_PARTIAL_BUFFER(gr, VGACommonState, 16),
2158 VMSTATE_UINT8(ar_index, VGACommonState),
2159 VMSTATE_BUFFER(ar, VGACommonState),
2160 VMSTATE_INT32(ar_flip_flop, VGACommonState),
2161 VMSTATE_UINT8(cr_index, VGACommonState),
2162 VMSTATE_BUFFER(cr, VGACommonState),
2163 VMSTATE_UINT8(msr, VGACommonState),
2164 VMSTATE_UINT8(fcr, VGACommonState),
2165 VMSTATE_UINT8(st00, VGACommonState),
2166 VMSTATE_UINT8(st01, VGACommonState),
2167
2168 VMSTATE_UINT8(dac_state, VGACommonState),
2169 VMSTATE_UINT8(dac_sub_index, VGACommonState),
2170 VMSTATE_UINT8(dac_read_index, VGACommonState),
2171 VMSTATE_UINT8(dac_write_index, VGACommonState),
2172 VMSTATE_BUFFER(dac_cache, VGACommonState),
2173 VMSTATE_BUFFER(palette, VGACommonState),
2174
2175 VMSTATE_INT32(bank_offset, VGACommonState),
2176 VMSTATE_UINT8_EQUAL(is_vbe_vmstate, VGACommonState),
b0a21b53 2177#ifdef CONFIG_BOCHS_VBE
11b6b345
JQ
2178 VMSTATE_UINT16(vbe_index, VGACommonState),
2179 VMSTATE_UINT16_ARRAY(vbe_regs, VGACommonState, VBE_DISPI_INDEX_NB),
2180 VMSTATE_UINT32(vbe_start_addr, VGACommonState),
2181 VMSTATE_UINT32(vbe_line_offset, VGACommonState),
2182 VMSTATE_UINT32(vbe_bank_mask, VGACommonState),
b0a21b53 2183#endif
11b6b345
JQ
2184 VMSTATE_END_OF_LIST()
2185 }
2186};
2187
a4a2f59c 2188void vga_common_init(VGACommonState *s, int vga_ram_size)
e89f66ec 2189{
17b0018b 2190 int i, j, v, b;
e89f66ec
FB
2191
2192 for(i = 0;i < 256; i++) {
2193 v = 0;
2194 for(j = 0; j < 8; j++) {
2195 v |= ((i >> j) & 1) << (j * 4);
2196 }
2197 expand4[i] = v;
2198
2199 v = 0;
2200 for(j = 0; j < 4; j++) {
2201 v |= ((i >> (2 * j)) & 3) << (j * 4);
2202 }
2203 expand2[i] = v;
2204 }
17b0018b
FB
2205 for(i = 0; i < 16; i++) {
2206 v = 0;
2207 for(j = 0; j < 4; j++) {
2208 b = ((i >> j) & 1);
2209 v |= b << (2 * j);
2210 v |= b << (2 * j + 1);
2211 }
2212 expand4to8[i] = v;
2213 }
e89f66ec 2214
2a3138ab
JQ
2215#ifdef CONFIG_BOCHS_VBE
2216 s->is_vbe_vmstate = 1;
2217#else
2218 s->is_vbe_vmstate = 0;
2219#endif
b1950430
AK
2220 memory_region_init_ram(&s->vram, NULL, "vga.vram", vga_ram_size);
2221 s->vram_ptr = memory_region_get_ram_ptr(&s->vram);
e89f66ec 2222 s->vram_size = vga_ram_size;
798b0c25
FB
2223 s->get_bpp = vga_get_bpp;
2224 s->get_offsets = vga_get_offsets;
a130a41e 2225 s->get_resolution = vga_get_resolution;
d34cab9f
TS
2226 s->update = vga_update_display;
2227 s->invalidate = vga_invalidate_display;
2228 s->screen_dump = vga_screen_dump;
4d3b6f6e 2229 s->text_update = vga_update_text;
cb5a7aa8 2230 switch (vga_retrace_method) {
2231 case VGA_RETRACE_DUMB:
2232 s->retrace = vga_dumb_retrace;
2233 s->update_retrace_info = vga_dumb_update_retrace_info;
2234 break;
2235
2236 case VGA_RETRACE_PRECISE:
2237 s->retrace = vga_precise_retrace;
2238 s->update_retrace_info = vga_precise_update_retrace_info;
cb5a7aa8 2239 break;
2240 }
b1950430 2241 vga_dirty_log_start(s);
798b0c25
FB
2242}
2243
0a039dc7
RH
2244static const MemoryRegionPortio vga_portio_list[] = {
2245 { 0x04, 2, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3b4 */
2246 { 0x0a, 1, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3ba */
2247 { 0x10, 16, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3c0 */
2248 { 0x24, 2, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3d4 */
2249 { 0x2a, 1, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3da */
2250 PORTIO_END_OF_LIST(),
2251};
e89f66ec 2252
4fa0f5d2 2253#ifdef CONFIG_BOCHS_VBE
0a039dc7
RH
2254static const MemoryRegionPortio vbe_portio_list[] = {
2255 { 0, 1, 2, .read = vbe_ioport_read_index, .write = vbe_ioport_write_index },
2256# ifdef TARGET_I386
2257 { 1, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data },
2258# else
2259 { 2, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data },
2260# endif
2261 PORTIO_END_OF_LIST(),
2262};
2263#endif /* CONFIG_BOCHS_VBE */
4fa0f5d2 2264
0a039dc7
RH
2265/* Used by both ISA and PCI */
2266MemoryRegion *vga_init_io(VGACommonState *s,
2267 const MemoryRegionPortio **vga_ports,
2268 const MemoryRegionPortio **vbe_ports)
2269{
2270 MemoryRegion *vga_mem;
09a79b49 2271
0a039dc7
RH
2272 *vga_ports = vga_portio_list;
2273 *vbe_ports = NULL;
2274#ifdef CONFIG_BOCHS_VBE
2275 *vbe_ports = vbe_portio_list;
4fa0f5d2
FB
2276#endif
2277
7267c094 2278 vga_mem = g_malloc(sizeof(*vga_mem));
b1950430
AK
2279 memory_region_init_io(vga_mem, &vga_mem_ops, s,
2280 "vga-lowmem", 0x20000);
2281
2282 return vga_mem;
7435b791
BS
2283}
2284
0a039dc7
RH
2285void vga_init(VGACommonState *s, MemoryRegion *address_space,
2286 MemoryRegion *address_space_io, bool init_vga_ports)
7435b791 2287{
b1950430 2288 MemoryRegion *vga_io_memory;
0a039dc7
RH
2289 const MemoryRegionPortio *vga_ports, *vbe_ports;
2290 PortioList *vga_port_list = g_new(PortioList, 1);
2291 PortioList *vbe_port_list = g_new(PortioList, 1);
7435b791
BS
2292
2293 qemu_register_reset(vga_reset, s);
2294
2295 s->bank_offset = 0;
2296
80763888
JK
2297 s->legacy_address_space = address_space;
2298
0a039dc7 2299 vga_io_memory = vga_init_io(s, &vga_ports, &vbe_ports);
be20f9e9 2300 memory_region_add_subregion_overlap(address_space,
b1950430
AK
2301 isa_mem_base + 0x000a0000,
2302 vga_io_memory,
2303 1);
2304 memory_region_set_coalescing(vga_io_memory);
0a039dc7
RH
2305 if (init_vga_ports) {
2306 portio_list_init(vga_port_list, vga_ports, s, "vga");
2307 portio_list_add(vga_port_list, address_space_io, 0x3b0);
2308 }
2309 if (vbe_ports) {
2310 portio_list_init(vbe_port_list, vbe_ports, s, "vbe");
2311 portio_list_add(vbe_port_list, address_space_io, 0x1ce);
2312 }
d2269f6f
FB
2313}
2314
be20f9e9 2315void vga_init_vbe(VGACommonState *s, MemoryRegion *system_memory)
f0138a63
AL
2316{
2317#ifdef CONFIG_BOCHS_VBE
2318 /* XXX: use optimized standard vga accesses */
be20f9e9 2319 memory_region_add_subregion(system_memory,
b1950430
AK
2320 VBE_DISPI_LFB_PHYSICAL_ADDRESS,
2321 &s->vram);
f0138a63
AL
2322 s->vbe_mapped = 1;
2323#endif
2324}
59a983b9
FB
2325/********************************************************/
2326/* vga screen dump */
2327
04a52b41 2328static void vga_save_dpy_update(DisplayState *ds,
59a983b9
FB
2329 int x, int y, int w, int h)
2330{
04a52b41
SS
2331 if (screen_dump_filename) {
2332 ppm_save(screen_dump_filename, ds->surface);
04a52b41 2333 }
59a983b9
FB
2334}
2335
7d957bd8 2336static void vga_save_dpy_resize(DisplayState *s)
59a983b9 2337{
59a983b9
FB
2338}
2339
2340static void vga_save_dpy_refresh(DisplayState *s)
2341{
2342}
2343
e07d630a 2344int ppm_save(const char *filename, struct DisplaySurface *ds)
59a983b9
FB
2345{
2346 FILE *f;
2347 uint8_t *d, *d1;
e07d630a 2348 uint32_t v;
59a983b9 2349 int y, x;
e07d630a 2350 uint8_t r, g, b;
f8e378f2
AK
2351 int ret;
2352 char *linebuf, *pbuf;
59a983b9
FB
2353
2354 f = fopen(filename, "wb");
2355 if (!f)
2356 return -1;
2357 fprintf(f, "P6\n%d %d\n%d\n",
e07d630a 2358 ds->width, ds->height, 255);
7267c094 2359 linebuf = g_malloc(ds->width * 3);
e07d630a
AL
2360 d1 = ds->data;
2361 for(y = 0; y < ds->height; y++) {
59a983b9 2362 d = d1;
f8e378f2 2363 pbuf = linebuf;
e07d630a
AL
2364 for(x = 0; x < ds->width; x++) {
2365 if (ds->pf.bits_per_pixel == 32)
2366 v = *(uint32_t *)d;
2367 else
2368 v = (uint32_t) (*(uint16_t *)d);
2369 r = ((v >> ds->pf.rshift) & ds->pf.rmax) * 256 /
2370 (ds->pf.rmax + 1);
2371 g = ((v >> ds->pf.gshift) & ds->pf.gmax) * 256 /
2372 (ds->pf.gmax + 1);
2373 b = ((v >> ds->pf.bshift) & ds->pf.bmax) * 256 /
2374 (ds->pf.bmax + 1);
f8e378f2
AK
2375 *pbuf++ = r;
2376 *pbuf++ = g;
2377 *pbuf++ = b;
e07d630a 2378 d += ds->pf.bytes_per_pixel;
59a983b9 2379 }
e07d630a 2380 d1 += ds->linesize;
f8e378f2
AK
2381 ret = fwrite(linebuf, 1, pbuf - linebuf, f);
2382 (void)ret;
59a983b9 2383 }
7267c094 2384 g_free(linebuf);
59a983b9
FB
2385 fclose(f);
2386 return 0;
2387}
2388
04a52b41 2389static DisplayChangeListener* vga_screen_dump_init(DisplayState *ds)
4c5e8c5c 2390{
04a52b41 2391 DisplayChangeListener *dcl;
4c5e8c5c 2392
7267c094 2393 dcl = g_malloc0(sizeof(DisplayChangeListener));
04a52b41
SS
2394 dcl->dpy_update = vga_save_dpy_update;
2395 dcl->dpy_resize = vga_save_dpy_resize;
2396 dcl->dpy_refresh = vga_save_dpy_refresh;
2397 register_displaychangelistener(ds, dcl);
2398 return dcl;
4c5e8c5c
BS
2399}
2400
2401/* save the vga display in a PPM image even if no display is
2402 available */
2403static void vga_screen_dump(void *opaque, const char *filename)
2404{
cedd91d2 2405 VGACommonState *s = opaque;
4c5e8c5c 2406
04a52b41
SS
2407 if (!screen_dump_dcl)
2408 screen_dump_dcl = vga_screen_dump_init(s->ds);
2409
2313e998 2410 screen_dump_filename = filename;
9d1b494a 2411 vga_invalidate_display(s);
04a52b41 2412 vga_hw_update();
2313e998 2413 screen_dump_filename = NULL;
4c5e8c5c 2414}