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