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