]> git.proxmox.com Git - mirror_qemu.git/blame - hw/vga.c
vhost: convert to MemoryListener API
[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
e9a07334
JK
1841 qemu_flush_coalesced_mmio_buffer();
1842
0e1f5a0c 1843 if (ds_get_bits_per_pixel(s->ds) == 0) {
0f35920c 1844 /* nothing to do */
59a983b9 1845 } else {
3098b9fd 1846 full_update = 0;
799e709b
AL
1847 if (!(s->ar_index & 0x20)) {
1848 graphic_mode = GMODE_BLANK;
1849 } else {
1850 graphic_mode = s->gr[6] & 1;
1851 }
1852 if (graphic_mode != s->graphic_mode) {
1853 s->graphic_mode = graphic_mode;
1854 full_update = 1;
1855 }
1856 switch(graphic_mode) {
2aebb3eb 1857 case GMODE_TEXT:
e89f66ec 1858 vga_draw_text(s, full_update);
2aebb3eb
FB
1859 break;
1860 case GMODE_GRAPH:
1861 vga_draw_graphic(s, full_update);
1862 break;
1863 case GMODE_BLANK:
1864 default:
1865 vga_draw_blank(s, full_update);
1866 break;
1867 }
e89f66ec
FB
1868 }
1869}
1870
a130a41e 1871/* force a full display refresh */
95219897 1872static void vga_invalidate_display(void *opaque)
a130a41e 1873{
cedd91d2 1874 VGACommonState *s = opaque;
3b46e624 1875
3098b9fd
AJ
1876 s->last_width = -1;
1877 s->last_height = -1;
a130a41e
FB
1878}
1879
03a3e7ba 1880void vga_common_reset(VGACommonState *s)
e89f66ec 1881{
6e6b7363
BS
1882 s->sr_index = 0;
1883 memset(s->sr, '\0', sizeof(s->sr));
1884 s->gr_index = 0;
1885 memset(s->gr, '\0', sizeof(s->gr));
1886 s->ar_index = 0;
1887 memset(s->ar, '\0', sizeof(s->ar));
1888 s->ar_flip_flop = 0;
1889 s->cr_index = 0;
1890 memset(s->cr, '\0', sizeof(s->cr));
1891 s->msr = 0;
1892 s->fcr = 0;
1893 s->st00 = 0;
1894 s->st01 = 0;
1895 s->dac_state = 0;
1896 s->dac_sub_index = 0;
1897 s->dac_read_index = 0;
1898 s->dac_write_index = 0;
1899 memset(s->dac_cache, '\0', sizeof(s->dac_cache));
1900 s->dac_8bit = 0;
1901 memset(s->palette, '\0', sizeof(s->palette));
1902 s->bank_offset = 0;
1903#ifdef CONFIG_BOCHS_VBE
1904 s->vbe_index = 0;
1905 memset(s->vbe_regs, '\0', sizeof(s->vbe_regs));
af92284b 1906 s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID5;
6e6b7363
BS
1907 s->vbe_start_addr = 0;
1908 s->vbe_line_offset = 0;
1909 s->vbe_bank_mask = (s->vram_size >> 16) - 1;
1910#endif
1911 memset(s->font_offsets, '\0', sizeof(s->font_offsets));
799e709b 1912 s->graphic_mode = -1; /* force full update */
6e6b7363
BS
1913 s->shift_control = 0;
1914 s->double_scan = 0;
1915 s->line_offset = 0;
1916 s->line_compare = 0;
1917 s->start_addr = 0;
1918 s->plane_updated = 0;
1919 s->last_cw = 0;
1920 s->last_ch = 0;
1921 s->last_width = 0;
1922 s->last_height = 0;
1923 s->last_scr_width = 0;
1924 s->last_scr_height = 0;
1925 s->cursor_start = 0;
1926 s->cursor_end = 0;
1927 s->cursor_offset = 0;
1928 memset(s->invalidated_y_table, '\0', sizeof(s->invalidated_y_table));
1929 memset(s->last_palette, '\0', sizeof(s->last_palette));
1930 memset(s->last_ch_attr, '\0', sizeof(s->last_ch_attr));
1931 switch (vga_retrace_method) {
1932 case VGA_RETRACE_DUMB:
1933 break;
1934 case VGA_RETRACE_PRECISE:
1935 memset(&s->retrace_info, 0, sizeof (s->retrace_info));
1936 break;
1937 }
80763888 1938 vga_update_memory_access(s);
e89f66ec
FB
1939}
1940
03a3e7ba
JQ
1941static void vga_reset(void *opaque)
1942{
cedd91d2 1943 VGACommonState *s = opaque;
03a3e7ba
JQ
1944 vga_common_reset(s);
1945}
1946
4d3b6f6e
AZ
1947#define TEXTMODE_X(x) ((x) % width)
1948#define TEXTMODE_Y(x) ((x) / width)
1949#define VMEM2CHTYPE(v) ((v & 0xff0007ff) | \
1950 ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1))
1951/* relay text rendering to the display driver
1952 * instead of doing a full vga_update_display() */
c227f099 1953static void vga_update_text(void *opaque, console_ch_t *chardata)
4d3b6f6e 1954{
cedd91d2 1955 VGACommonState *s = opaque;
799e709b 1956 int graphic_mode, i, cursor_offset, cursor_visible;
4d3b6f6e
AZ
1957 int cw, cheight, width, height, size, c_min, c_max;
1958 uint32_t *src;
c227f099 1959 console_ch_t *dst, val;
4d3b6f6e 1960 char msg_buffer[80];
799e709b
AL
1961 int full_update = 0;
1962
e9a07334
JK
1963 qemu_flush_coalesced_mmio_buffer();
1964
799e709b
AL
1965 if (!(s->ar_index & 0x20)) {
1966 graphic_mode = GMODE_BLANK;
1967 } else {
1968 graphic_mode = s->gr[6] & 1;
1969 }
1970 if (graphic_mode != s->graphic_mode) {
1971 s->graphic_mode = graphic_mode;
1972 full_update = 1;
1973 }
1974 if (s->last_width == -1) {
1975 s->last_width = 0;
1976 full_update = 1;
1977 }
4d3b6f6e 1978
799e709b 1979 switch (graphic_mode) {
4d3b6f6e
AZ
1980 case GMODE_TEXT:
1981 /* TODO: update palette */
799e709b 1982 full_update |= update_basic_params(s);
4d3b6f6e 1983
799e709b
AL
1984 /* total width & height */
1985 cheight = (s->cr[9] & 0x1f) + 1;
1986 cw = 8;
1987 if (!(s->sr[1] & 0x01))
1988 cw = 9;
1989 if (s->sr[1] & 0x08)
1990 cw = 16; /* NOTE: no 18 pixel wide */
1991 width = (s->cr[0x01] + 1);
1992 if (s->cr[0x06] == 100) {
1993 /* ugly hack for CGA 160x100x16 - explain me the logic */
1994 height = 100;
1995 } else {
1996 height = s->cr[0x12] |
1997 ((s->cr[0x07] & 0x02) << 7) |
1998 ((s->cr[0x07] & 0x40) << 3);
1999 height = (height + 1) / cheight;
4d3b6f6e
AZ
2000 }
2001
2002 size = (height * width);
2003 if (size > CH_ATTR_SIZE) {
2004 if (!full_update)
2005 return;
2006
363a37d5
BS
2007 snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Text mode",
2008 width, height);
4d3b6f6e
AZ
2009 break;
2010 }
2011
799e709b
AL
2012 if (width != s->last_width || height != s->last_height ||
2013 cw != s->last_cw || cheight != s->last_ch) {
2014 s->last_scr_width = width * cw;
2015 s->last_scr_height = height * cheight;
2016 s->ds->surface->width = width;
2017 s->ds->surface->height = height;
2018 dpy_resize(s->ds);
2019 s->last_width = width;
2020 s->last_height = height;
2021 s->last_ch = cheight;
2022 s->last_cw = cw;
2023 full_update = 1;
2024 }
2025
4d3b6f6e
AZ
2026 /* Update "hardware" cursor */
2027 cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
2028 if (cursor_offset != s->cursor_offset ||
2029 s->cr[0xa] != s->cursor_start ||
2030 s->cr[0xb] != s->cursor_end || full_update) {
2031 cursor_visible = !(s->cr[0xa] & 0x20);
2032 if (cursor_visible && cursor_offset < size && cursor_offset >= 0)
2033 dpy_cursor(s->ds,
2034 TEXTMODE_X(cursor_offset),
2035 TEXTMODE_Y(cursor_offset));
2036 else
2037 dpy_cursor(s->ds, -1, -1);
2038 s->cursor_offset = cursor_offset;
2039 s->cursor_start = s->cr[0xa];
2040 s->cursor_end = s->cr[0xb];
2041 }
2042
2043 src = (uint32_t *) s->vram_ptr + s->start_addr;
2044 dst = chardata;
2045
2046 if (full_update) {
2047 for (i = 0; i < size; src ++, dst ++, i ++)
9ae19b65 2048 console_write_ch(dst, VMEM2CHTYPE(le32_to_cpu(*src)));
4d3b6f6e
AZ
2049
2050 dpy_update(s->ds, 0, 0, width, height);
2051 } else {
2052 c_max = 0;
2053
2054 for (i = 0; i < size; src ++, dst ++, i ++) {
9ae19b65 2055 console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
4d3b6f6e
AZ
2056 if (*dst != val) {
2057 *dst = val;
2058 c_max = i;
2059 break;
2060 }
2061 }
2062 c_min = i;
2063 for (; i < size; src ++, dst ++, i ++) {
9ae19b65 2064 console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
4d3b6f6e
AZ
2065 if (*dst != val) {
2066 *dst = val;
2067 c_max = i;
2068 }
2069 }
2070
2071 if (c_min <= c_max) {
2072 i = TEXTMODE_Y(c_min);
2073 dpy_update(s->ds, 0, i, width, TEXTMODE_Y(c_max) - i + 1);
2074 }
2075 }
2076
2077 return;
2078 case GMODE_GRAPH:
2079 if (!full_update)
2080 return;
2081
2082 s->get_resolution(s, &width, &height);
363a37d5
BS
2083 snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Graphic mode",
2084 width, height);
4d3b6f6e
AZ
2085 break;
2086 case GMODE_BLANK:
2087 default:
2088 if (!full_update)
2089 return;
2090
363a37d5 2091 snprintf(msg_buffer, sizeof(msg_buffer), "VGA Blank mode");
4d3b6f6e
AZ
2092 break;
2093 }
2094
2095 /* Display a message */
5228c2d3
AZ
2096 s->last_width = 60;
2097 s->last_height = height = 3;
4d3b6f6e 2098 dpy_cursor(s->ds, -1, -1);
7d957bd8
AL
2099 s->ds->surface->width = s->last_width;
2100 s->ds->surface->height = height;
2101 dpy_resize(s->ds);
4d3b6f6e 2102
5228c2d3 2103 for (dst = chardata, i = 0; i < s->last_width * height; i ++)
4d3b6f6e
AZ
2104 console_write_ch(dst ++, ' ');
2105
2106 size = strlen(msg_buffer);
5228c2d3
AZ
2107 width = (s->last_width - size) / 2;
2108 dst = chardata + s->last_width + width;
4d3b6f6e
AZ
2109 for (i = 0; i < size; i ++)
2110 console_write_ch(dst ++, 0x00200100 | msg_buffer[i]);
2111
5228c2d3 2112 dpy_update(s->ds, 0, 0, s->last_width, height);
4d3b6f6e
AZ
2113}
2114
b1950430
AK
2115static uint64_t vga_mem_read(void *opaque, target_phys_addr_t addr,
2116 unsigned size)
2117{
2118 VGACommonState *s = opaque;
2119
b2a5e761 2120 return vga_mem_readb(s, addr);
b1950430 2121}
e89f66ec 2122
b1950430
AK
2123static void vga_mem_write(void *opaque, target_phys_addr_t addr,
2124 uint64_t data, unsigned size)
2125{
2126 VGACommonState *s = opaque;
2127
b2a5e761 2128 return vga_mem_writeb(s, addr, data);
b1950430
AK
2129}
2130
2131const MemoryRegionOps vga_mem_ops = {
2132 .read = vga_mem_read,
2133 .write = vga_mem_write,
2134 .endianness = DEVICE_LITTLE_ENDIAN,
b2a5e761
AK
2135 .impl = {
2136 .min_access_size = 1,
2137 .max_access_size = 1,
2138 },
e89f66ec
FB
2139};
2140
11b6b345 2141static int vga_common_post_load(void *opaque, int version_id)
b0a21b53 2142{
0d65ddc3 2143 VGACommonState *s = opaque;
11b6b345
JQ
2144
2145 /* force refresh */
2146 s->graphic_mode = -1;
2147 return 0;
2148}
2149
2150const VMStateDescription vmstate_vga_common = {
2151 .name = "vga",
2152 .version_id = 2,
2153 .minimum_version_id = 2,
2154 .minimum_version_id_old = 2,
2155 .post_load = vga_common_post_load,
2156 .fields = (VMStateField []) {
2157 VMSTATE_UINT32(latch, VGACommonState),
2158 VMSTATE_UINT8(sr_index, VGACommonState),
2159 VMSTATE_PARTIAL_BUFFER(sr, VGACommonState, 8),
2160 VMSTATE_UINT8(gr_index, VGACommonState),
2161 VMSTATE_PARTIAL_BUFFER(gr, VGACommonState, 16),
2162 VMSTATE_UINT8(ar_index, VGACommonState),
2163 VMSTATE_BUFFER(ar, VGACommonState),
2164 VMSTATE_INT32(ar_flip_flop, VGACommonState),
2165 VMSTATE_UINT8(cr_index, VGACommonState),
2166 VMSTATE_BUFFER(cr, VGACommonState),
2167 VMSTATE_UINT8(msr, VGACommonState),
2168 VMSTATE_UINT8(fcr, VGACommonState),
2169 VMSTATE_UINT8(st00, VGACommonState),
2170 VMSTATE_UINT8(st01, VGACommonState),
2171
2172 VMSTATE_UINT8(dac_state, VGACommonState),
2173 VMSTATE_UINT8(dac_sub_index, VGACommonState),
2174 VMSTATE_UINT8(dac_read_index, VGACommonState),
2175 VMSTATE_UINT8(dac_write_index, VGACommonState),
2176 VMSTATE_BUFFER(dac_cache, VGACommonState),
2177 VMSTATE_BUFFER(palette, VGACommonState),
2178
2179 VMSTATE_INT32(bank_offset, VGACommonState),
2180 VMSTATE_UINT8_EQUAL(is_vbe_vmstate, VGACommonState),
b0a21b53 2181#ifdef CONFIG_BOCHS_VBE
11b6b345
JQ
2182 VMSTATE_UINT16(vbe_index, VGACommonState),
2183 VMSTATE_UINT16_ARRAY(vbe_regs, VGACommonState, VBE_DISPI_INDEX_NB),
2184 VMSTATE_UINT32(vbe_start_addr, VGACommonState),
2185 VMSTATE_UINT32(vbe_line_offset, VGACommonState),
2186 VMSTATE_UINT32(vbe_bank_mask, VGACommonState),
b0a21b53 2187#endif
11b6b345
JQ
2188 VMSTATE_END_OF_LIST()
2189 }
2190};
2191
a4a2f59c 2192void vga_common_init(VGACommonState *s, int vga_ram_size)
e89f66ec 2193{
17b0018b 2194 int i, j, v, b;
e89f66ec
FB
2195
2196 for(i = 0;i < 256; i++) {
2197 v = 0;
2198 for(j = 0; j < 8; j++) {
2199 v |= ((i >> j) & 1) << (j * 4);
2200 }
2201 expand4[i] = v;
2202
2203 v = 0;
2204 for(j = 0; j < 4; j++) {
2205 v |= ((i >> (2 * j)) & 3) << (j * 4);
2206 }
2207 expand2[i] = v;
2208 }
17b0018b
FB
2209 for(i = 0; i < 16; i++) {
2210 v = 0;
2211 for(j = 0; j < 4; j++) {
2212 b = ((i >> j) & 1);
2213 v |= b << (2 * j);
2214 v |= b << (2 * j + 1);
2215 }
2216 expand4to8[i] = v;
2217 }
e89f66ec 2218
2a3138ab
JQ
2219#ifdef CONFIG_BOCHS_VBE
2220 s->is_vbe_vmstate = 1;
2221#else
2222 s->is_vbe_vmstate = 0;
2223#endif
b1950430
AK
2224 memory_region_init_ram(&s->vram, NULL, "vga.vram", vga_ram_size);
2225 s->vram_ptr = memory_region_get_ram_ptr(&s->vram);
e89f66ec 2226 s->vram_size = vga_ram_size;
798b0c25
FB
2227 s->get_bpp = vga_get_bpp;
2228 s->get_offsets = vga_get_offsets;
a130a41e 2229 s->get_resolution = vga_get_resolution;
d34cab9f
TS
2230 s->update = vga_update_display;
2231 s->invalidate = vga_invalidate_display;
2232 s->screen_dump = vga_screen_dump;
4d3b6f6e 2233 s->text_update = vga_update_text;
cb5a7aa8 2234 switch (vga_retrace_method) {
2235 case VGA_RETRACE_DUMB:
2236 s->retrace = vga_dumb_retrace;
2237 s->update_retrace_info = vga_dumb_update_retrace_info;
2238 break;
2239
2240 case VGA_RETRACE_PRECISE:
2241 s->retrace = vga_precise_retrace;
2242 s->update_retrace_info = vga_precise_update_retrace_info;
cb5a7aa8 2243 break;
2244 }
b1950430 2245 vga_dirty_log_start(s);
798b0c25
FB
2246}
2247
0a039dc7
RH
2248static const MemoryRegionPortio vga_portio_list[] = {
2249 { 0x04, 2, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3b4 */
2250 { 0x0a, 1, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3ba */
2251 { 0x10, 16, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3c0 */
2252 { 0x24, 2, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3d4 */
2253 { 0x2a, 1, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3da */
2254 PORTIO_END_OF_LIST(),
2255};
e89f66ec 2256
4fa0f5d2 2257#ifdef CONFIG_BOCHS_VBE
0a039dc7
RH
2258static const MemoryRegionPortio vbe_portio_list[] = {
2259 { 0, 1, 2, .read = vbe_ioport_read_index, .write = vbe_ioport_write_index },
2260# ifdef TARGET_I386
2261 { 1, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data },
2262# else
2263 { 2, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data },
2264# endif
2265 PORTIO_END_OF_LIST(),
2266};
2267#endif /* CONFIG_BOCHS_VBE */
4fa0f5d2 2268
0a039dc7
RH
2269/* Used by both ISA and PCI */
2270MemoryRegion *vga_init_io(VGACommonState *s,
2271 const MemoryRegionPortio **vga_ports,
2272 const MemoryRegionPortio **vbe_ports)
2273{
2274 MemoryRegion *vga_mem;
09a79b49 2275
0a039dc7
RH
2276 *vga_ports = vga_portio_list;
2277 *vbe_ports = NULL;
2278#ifdef CONFIG_BOCHS_VBE
2279 *vbe_ports = vbe_portio_list;
4fa0f5d2
FB
2280#endif
2281
7267c094 2282 vga_mem = g_malloc(sizeof(*vga_mem));
b1950430
AK
2283 memory_region_init_io(vga_mem, &vga_mem_ops, s,
2284 "vga-lowmem", 0x20000);
2285
2286 return vga_mem;
7435b791
BS
2287}
2288
0a039dc7
RH
2289void vga_init(VGACommonState *s, MemoryRegion *address_space,
2290 MemoryRegion *address_space_io, bool init_vga_ports)
7435b791 2291{
b1950430 2292 MemoryRegion *vga_io_memory;
0a039dc7
RH
2293 const MemoryRegionPortio *vga_ports, *vbe_ports;
2294 PortioList *vga_port_list = g_new(PortioList, 1);
2295 PortioList *vbe_port_list = g_new(PortioList, 1);
7435b791
BS
2296
2297 qemu_register_reset(vga_reset, s);
2298
2299 s->bank_offset = 0;
2300
80763888
JK
2301 s->legacy_address_space = address_space;
2302
0a039dc7 2303 vga_io_memory = vga_init_io(s, &vga_ports, &vbe_ports);
be20f9e9 2304 memory_region_add_subregion_overlap(address_space,
b1950430
AK
2305 isa_mem_base + 0x000a0000,
2306 vga_io_memory,
2307 1);
2308 memory_region_set_coalescing(vga_io_memory);
0a039dc7
RH
2309 if (init_vga_ports) {
2310 portio_list_init(vga_port_list, vga_ports, s, "vga");
2311 portio_list_add(vga_port_list, address_space_io, 0x3b0);
2312 }
2313 if (vbe_ports) {
2314 portio_list_init(vbe_port_list, vbe_ports, s, "vbe");
2315 portio_list_add(vbe_port_list, address_space_io, 0x1ce);
2316 }
d2269f6f
FB
2317}
2318
be20f9e9 2319void vga_init_vbe(VGACommonState *s, MemoryRegion *system_memory)
f0138a63
AL
2320{
2321#ifdef CONFIG_BOCHS_VBE
2322 /* XXX: use optimized standard vga accesses */
be20f9e9 2323 memory_region_add_subregion(system_memory,
b1950430
AK
2324 VBE_DISPI_LFB_PHYSICAL_ADDRESS,
2325 &s->vram);
f0138a63
AL
2326 s->vbe_mapped = 1;
2327#endif
2328}
59a983b9
FB
2329/********************************************************/
2330/* vga screen dump */
2331
04a52b41 2332static void vga_save_dpy_update(DisplayState *ds,
59a983b9
FB
2333 int x, int y, int w, int h)
2334{
04a52b41
SS
2335 if (screen_dump_filename) {
2336 ppm_save(screen_dump_filename, ds->surface);
04a52b41 2337 }
59a983b9
FB
2338}
2339
7d957bd8 2340static void vga_save_dpy_resize(DisplayState *s)
59a983b9 2341{
59a983b9
FB
2342}
2343
2344static void vga_save_dpy_refresh(DisplayState *s)
2345{
2346}
2347
e07d630a 2348int ppm_save(const char *filename, struct DisplaySurface *ds)
59a983b9
FB
2349{
2350 FILE *f;
2351 uint8_t *d, *d1;
e07d630a 2352 uint32_t v;
59a983b9 2353 int y, x;
e07d630a 2354 uint8_t r, g, b;
f8e378f2
AK
2355 int ret;
2356 char *linebuf, *pbuf;
59a983b9
FB
2357
2358 f = fopen(filename, "wb");
2359 if (!f)
2360 return -1;
2361 fprintf(f, "P6\n%d %d\n%d\n",
e07d630a 2362 ds->width, ds->height, 255);
7267c094 2363 linebuf = g_malloc(ds->width * 3);
e07d630a
AL
2364 d1 = ds->data;
2365 for(y = 0; y < ds->height; y++) {
59a983b9 2366 d = d1;
f8e378f2 2367 pbuf = linebuf;
e07d630a
AL
2368 for(x = 0; x < ds->width; x++) {
2369 if (ds->pf.bits_per_pixel == 32)
2370 v = *(uint32_t *)d;
2371 else
2372 v = (uint32_t) (*(uint16_t *)d);
2373 r = ((v >> ds->pf.rshift) & ds->pf.rmax) * 256 /
2374 (ds->pf.rmax + 1);
2375 g = ((v >> ds->pf.gshift) & ds->pf.gmax) * 256 /
2376 (ds->pf.gmax + 1);
2377 b = ((v >> ds->pf.bshift) & ds->pf.bmax) * 256 /
2378 (ds->pf.bmax + 1);
f8e378f2
AK
2379 *pbuf++ = r;
2380 *pbuf++ = g;
2381 *pbuf++ = b;
e07d630a 2382 d += ds->pf.bytes_per_pixel;
59a983b9 2383 }
e07d630a 2384 d1 += ds->linesize;
f8e378f2
AK
2385 ret = fwrite(linebuf, 1, pbuf - linebuf, f);
2386 (void)ret;
59a983b9 2387 }
7267c094 2388 g_free(linebuf);
59a983b9
FB
2389 fclose(f);
2390 return 0;
2391}
2392
04a52b41 2393static DisplayChangeListener* vga_screen_dump_init(DisplayState *ds)
4c5e8c5c 2394{
04a52b41 2395 DisplayChangeListener *dcl;
4c5e8c5c 2396
7267c094 2397 dcl = g_malloc0(sizeof(DisplayChangeListener));
04a52b41
SS
2398 dcl->dpy_update = vga_save_dpy_update;
2399 dcl->dpy_resize = vga_save_dpy_resize;
2400 dcl->dpy_refresh = vga_save_dpy_refresh;
2401 register_displaychangelistener(ds, dcl);
2402 return dcl;
4c5e8c5c
BS
2403}
2404
2405/* save the vga display in a PPM image even if no display is
2406 available */
2407static void vga_screen_dump(void *opaque, const char *filename)
2408{
cedd91d2 2409 VGACommonState *s = opaque;
4c5e8c5c 2410
04a52b41
SS
2411 if (!screen_dump_dcl)
2412 screen_dump_dcl = vga_screen_dump_init(s->ds);
2413
2313e998 2414 screen_dump_filename = filename;
9d1b494a 2415 vga_invalidate_display(s);
04a52b41 2416 vga_hw_update();
2313e998 2417 screen_dump_filename = NULL;
4c5e8c5c 2418}