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