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