]> git.proxmox.com Git - mirror_qemu.git/blame - hw/display/vga.c
Merge remote-tracking branch 'remotes/ehabkost/tags/x86-next-pull-request' into staging
[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
145e543e 1012#include "vga-access.h"
e657d8ef 1013#include "vga-helpers.h"
e89f66ec 1014
e89f66ec 1015/* return true if the palette was modified */
cedd91d2 1016static int update_palette16(VGACommonState *s)
e89f66ec 1017{
17b0018b 1018 int full_update, i;
e89f66ec 1019 uint32_t v, col, *palette;
e89f66ec
FB
1020
1021 full_update = 0;
1022 palette = s->last_palette;
1023 for(i = 0; i < 16; i++) {
1024 v = s->ar[i];
5e55efc9
BS
1025 if (s->ar[VGA_ATC_MODE] & 0x80) {
1026 v = ((s->ar[VGA_ATC_COLOR_PAGE] & 0xf) << 4) | (v & 0xf);
1027 } else {
1028 v = ((s->ar[VGA_ATC_COLOR_PAGE] & 0xc) << 4) | (v & 0x3f);
1029 }
e89f66ec 1030 v = v * 3;
d3c2343a
BH
1031 col = rgb_to_pixel32(c6_to_8(s->palette[v]),
1032 c6_to_8(s->palette[v + 1]),
1033 c6_to_8(s->palette[v + 2]));
17b0018b
FB
1034 if (col != palette[i]) {
1035 full_update = 1;
1036 palette[i] = col;
e89f66ec 1037 }
17b0018b
FB
1038 }
1039 return full_update;
1040}
1041
1042/* return true if the palette was modified */
cedd91d2 1043static int update_palette256(VGACommonState *s)
17b0018b
FB
1044{
1045 int full_update, i;
1046 uint32_t v, col, *palette;
1047
1048 full_update = 0;
1049 palette = s->last_palette;
1050 v = 0;
1051 for(i = 0; i < 256; i++) {
37dd208d 1052 if (s->dac_8bit) {
d3c2343a
BH
1053 col = rgb_to_pixel32(s->palette[v],
1054 s->palette[v + 1],
1055 s->palette[v + 2]);
37dd208d 1056 } else {
d3c2343a
BH
1057 col = rgb_to_pixel32(c6_to_8(s->palette[v]),
1058 c6_to_8(s->palette[v + 1]),
1059 c6_to_8(s->palette[v + 2]));
37dd208d 1060 }
e89f66ec
FB
1061 if (col != palette[i]) {
1062 full_update = 1;
1063 palette[i] = col;
1064 }
17b0018b 1065 v += 3;
e89f66ec
FB
1066 }
1067 return full_update;
1068}
1069
cedd91d2 1070static void vga_get_offsets(VGACommonState *s,
5fafdf24 1071 uint32_t *pline_offset,
83acc96b
FB
1072 uint32_t *pstart_addr,
1073 uint32_t *pline_compare)
e89f66ec 1074{
83acc96b 1075 uint32_t start_addr, line_offset, line_compare;
a96d8bea 1076
bfa0f151 1077 if (vbe_enabled(s)) {
4fa0f5d2
FB
1078 line_offset = s->vbe_line_offset;
1079 start_addr = s->vbe_start_addr;
83acc96b 1080 line_compare = 65535;
a96d8bea 1081 } else {
4fa0f5d2 1082 /* compute line_offset in bytes */
5e55efc9 1083 line_offset = s->cr[VGA_CRTC_OFFSET];
4fa0f5d2 1084 line_offset <<= 3;
08e48902 1085
4fa0f5d2 1086 /* starting address */
5e55efc9
BS
1087 start_addr = s->cr[VGA_CRTC_START_LO] |
1088 (s->cr[VGA_CRTC_START_HI] << 8);
83acc96b
FB
1089
1090 /* line compare */
5e55efc9
BS
1091 line_compare = s->cr[VGA_CRTC_LINE_COMPARE] |
1092 ((s->cr[VGA_CRTC_OVERFLOW] & 0x10) << 4) |
1093 ((s->cr[VGA_CRTC_MAX_SCAN] & 0x40) << 3);
4fa0f5d2 1094 }
798b0c25
FB
1095 *pline_offset = line_offset;
1096 *pstart_addr = start_addr;
83acc96b 1097 *pline_compare = line_compare;
798b0c25
FB
1098}
1099
1100/* update start_addr and line_offset. Return TRUE if modified */
cedd91d2 1101static int update_basic_params(VGACommonState *s)
798b0c25
FB
1102{
1103 int full_update;
1104 uint32_t start_addr, line_offset, line_compare;
3b46e624 1105
798b0c25
FB
1106 full_update = 0;
1107
83acc96b 1108 s->get_offsets(s, &line_offset, &start_addr, &line_compare);
e89f66ec
FB
1109
1110 if (line_offset != s->line_offset ||
1111 start_addr != s->start_addr ||
1112 line_compare != s->line_compare) {
1113 s->line_offset = line_offset;
1114 s->start_addr = start_addr;
1115 s->line_compare = line_compare;
1116 full_update = 1;
1117 }
1118 return full_update;
1119}
1120
3b46e624 1121
e89f66ec
FB
1122static const uint8_t cursor_glyph[32 * 4] = {
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,
1138 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
3b46e624 1139};
e89f66ec 1140
cedd91d2 1141static void vga_get_text_resolution(VGACommonState *s, int *pwidth, int *pheight,
4c5e8c5c
BS
1142 int *pcwidth, int *pcheight)
1143{
1144 int width, cwidth, height, cheight;
1145
1146 /* total width & height */
5e55efc9 1147 cheight = (s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1;
4c5e8c5c 1148 cwidth = 8;
94ef4f33 1149 if (!(sr(s, VGA_SEQ_CLOCK_MODE) & VGA_SR01_CHAR_CLK_8DOTS)) {
4c5e8c5c 1150 cwidth = 9;
5e55efc9 1151 }
94ef4f33 1152 if (sr(s, VGA_SEQ_CLOCK_MODE) & 0x08) {
4c5e8c5c 1153 cwidth = 16; /* NOTE: no 18 pixel wide */
5e55efc9
BS
1154 }
1155 width = (s->cr[VGA_CRTC_H_DISP] + 1);
1156 if (s->cr[VGA_CRTC_V_TOTAL] == 100) {
4c5e8c5c
BS
1157 /* ugly hack for CGA 160x100x16 - explain me the logic */
1158 height = 100;
1159 } else {
5e55efc9
BS
1160 height = s->cr[VGA_CRTC_V_DISP_END] |
1161 ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) |
1162 ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3);
4c5e8c5c
BS
1163 height = (height + 1) / cheight;
1164 }
1165
1166 *pwidth = width;
1167 *pheight = height;
1168 *pcwidth = cwidth;
1169 *pcheight = cheight;
1170}
1171
5fafdf24
TS
1172/*
1173 * Text mode update
e89f66ec
FB
1174 * Missing:
1175 * - double scan
5fafdf24 1176 * - double width
e89f66ec
FB
1177 * - underline
1178 * - flashing
1179 */
cedd91d2 1180static void vga_draw_text(VGACommonState *s, int full_update)
e89f66ec 1181{
c78f7137 1182 DisplaySurface *surface = qemu_console_surface(s->con);
e89f66ec 1183 int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
cae334cd 1184 int cx_min, cx_max, linesize, x_incr, line, line1;
e89f66ec 1185 uint32_t offset, fgcol, bgcol, v, cursor_offset;
d1984194 1186 uint8_t *d1, *d, *src, *dest, *cursor_ptr;
e89f66ec 1187 const uint8_t *font_ptr, *font_base[2];
9e057c0b 1188 int dup9, line_offset;
e89f66ec
FB
1189 uint32_t *palette;
1190 uint32_t *ch_attr_ptr;
bc72ad67 1191 int64_t now = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
e89f66ec 1192
e89f66ec 1193 /* compute font data address (in plane 2) */
94ef4f33 1194 v = sr(s, VGA_SEQ_CHARACTER_MAP);
1078f663 1195 offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
e89f66ec
FB
1196 if (offset != s->font_offsets[0]) {
1197 s->font_offsets[0] = offset;
1198 full_update = 1;
1199 }
1200 font_base[0] = s->vram_ptr + offset;
1201
1078f663 1202 offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
e89f66ec
FB
1203 font_base[1] = s->vram_ptr + offset;
1204 if (offset != s->font_offsets[1]) {
1205 s->font_offsets[1] = offset;
1206 full_update = 1;
1207 }
ad37168c 1208 if (s->plane_updated & (1 << 2) || s->has_chain4_alias) {
546fa6ab
FB
1209 /* if the plane 2 was modified since the last display, it
1210 indicates the font may have been modified */
1211 s->plane_updated = 0;
1212 full_update = 1;
1213 }
799e709b 1214 full_update |= update_basic_params(s);
e89f66ec
FB
1215
1216 line_offset = s->line_offset;
e89f66ec 1217
4c5e8c5c 1218 vga_get_text_resolution(s, &width, &height, &cw, &cheight);
1b296044
SW
1219 if ((height * width) <= 1) {
1220 /* better than nothing: exit if transient size is too small */
1221 return;
1222 }
3294b949
FB
1223 if ((height * width) > CH_ATTR_SIZE) {
1224 /* better than nothing: exit if transient size is too big */
1225 return;
1226 }
1227
799e709b
AL
1228 if (width != s->last_width || height != s->last_height ||
1229 cw != s->last_cw || cheight != s->last_ch || s->last_depth) {
1230 s->last_scr_width = width * cw;
1231 s->last_scr_height = height * cheight;
c78f7137
GH
1232 qemu_console_resize(s->con, s->last_scr_width, s->last_scr_height);
1233 surface = qemu_console_surface(s->con);
1234 dpy_text_resize(s->con, width, height);
799e709b
AL
1235 s->last_depth = 0;
1236 s->last_width = width;
1237 s->last_height = height;
1238 s->last_ch = cheight;
1239 s->last_cw = cw;
1240 full_update = 1;
1241 }
7d957bd8
AL
1242 full_update |= update_palette16(s);
1243 palette = s->last_palette;
c78f7137 1244 x_incr = cw * surface_bytes_per_pixel(surface);
7d957bd8 1245
9678aedd
GH
1246 if (full_update) {
1247 s->full_update_text = 1;
1248 }
1249 if (s->full_update_gfx) {
1250 s->full_update_gfx = 0;
1251 full_update |= 1;
1252 }
1253
5e55efc9
BS
1254 cursor_offset = ((s->cr[VGA_CRTC_CURSOR_HI] << 8) |
1255 s->cr[VGA_CRTC_CURSOR_LO]) - s->start_addr;
e89f66ec 1256 if (cursor_offset != s->cursor_offset ||
5e55efc9
BS
1257 s->cr[VGA_CRTC_CURSOR_START] != s->cursor_start ||
1258 s->cr[VGA_CRTC_CURSOR_END] != s->cursor_end) {
e89f66ec
FB
1259 /* if the cursor position changed, we update the old and new
1260 chars */
1261 if (s->cursor_offset < CH_ATTR_SIZE)
1262 s->last_ch_attr[s->cursor_offset] = -1;
1263 if (cursor_offset < CH_ATTR_SIZE)
1264 s->last_ch_attr[cursor_offset] = -1;
1265 s->cursor_offset = cursor_offset;
5e55efc9
BS
1266 s->cursor_start = s->cr[VGA_CRTC_CURSOR_START];
1267 s->cursor_end = s->cr[VGA_CRTC_CURSOR_END];
e89f66ec 1268 }
39cf7803 1269 cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
9aa0ff0b
JK
1270 if (now >= s->cursor_blink_time) {
1271 s->cursor_blink_time = now + VGA_TEXT_CURSOR_PERIOD_MS / 2;
1272 s->cursor_visible_phase = !s->cursor_visible_phase;
1273 }
3b46e624 1274
c78f7137
GH
1275 dest = surface_data(surface);
1276 linesize = surface_stride(surface);
e89f66ec 1277 ch_attr_ptr = s->last_ch_attr;
d1984194 1278 line = 0;
1279 offset = s->start_addr * 4;
e89f66ec
FB
1280 for(cy = 0; cy < height; cy++) {
1281 d1 = dest;
d1984194 1282 src = s->vram_ptr + offset;
e89f66ec
FB
1283 cx_min = width;
1284 cx_max = -1;
1285 for(cx = 0; cx < width; cx++) {
191f59dc 1286 if (src + sizeof(uint16_t) > s->vram_ptr + s->vram_size) {
1287 break;
1288 }
e89f66ec 1289 ch_attr = *(uint16_t *)src;
9aa0ff0b 1290 if (full_update || ch_attr != *ch_attr_ptr || src == cursor_ptr) {
e89f66ec
FB
1291 if (cx < cx_min)
1292 cx_min = cx;
1293 if (cx > cx_max)
1294 cx_max = cx;
1295 *ch_attr_ptr = ch_attr;
e2542fe2 1296#ifdef HOST_WORDS_BIGENDIAN
e89f66ec
FB
1297 ch = ch_attr >> 8;
1298 cattr = ch_attr & 0xff;
1299#else
1300 ch = ch_attr & 0xff;
1301 cattr = ch_attr >> 8;
1302#endif
1303 font_ptr = font_base[(cattr >> 3) & 1];
1304 font_ptr += 32 * 4 * ch;
1305 bgcol = palette[cattr >> 4];
1306 fgcol = palette[cattr & 0x0f];
9e057c0b 1307 if (cw == 16) {
d2e043a8
BH
1308 vga_draw_glyph16(d1, linesize,
1309 font_ptr, cheight, fgcol, bgcol);
9e057c0b 1310 } else if (cw != 9) {
d2e043a8
BH
1311 vga_draw_glyph8(d1, linesize,
1312 font_ptr, cheight, fgcol, bgcol);
e89f66ec
FB
1313 } else {
1314 dup9 = 0;
5e55efc9
BS
1315 if (ch >= 0xb0 && ch <= 0xdf &&
1316 (s->ar[VGA_ATC_MODE] & 0x04)) {
e89f66ec 1317 dup9 = 1;
5e55efc9 1318 }
d2e043a8
BH
1319 vga_draw_glyph9(d1, linesize,
1320 font_ptr, cheight, fgcol, bgcol, dup9);
e89f66ec
FB
1321 }
1322 if (src == cursor_ptr &&
9aa0ff0b
JK
1323 !(s->cr[VGA_CRTC_CURSOR_START] & 0x20) &&
1324 s->cursor_visible_phase) {
e89f66ec
FB
1325 int line_start, line_last, h;
1326 /* draw the cursor */
5e55efc9
BS
1327 line_start = s->cr[VGA_CRTC_CURSOR_START] & 0x1f;
1328 line_last = s->cr[VGA_CRTC_CURSOR_END] & 0x1f;
e89f66ec
FB
1329 /* XXX: check that */
1330 if (line_last > cheight - 1)
1331 line_last = cheight - 1;
1332 if (line_last >= line_start && line_start < cheight) {
1333 h = line_last - line_start + 1;
1334 d = d1 + linesize * line_start;
9e057c0b 1335 if (cw == 16) {
d2e043a8
BH
1336 vga_draw_glyph16(d, linesize,
1337 cursor_glyph, h, fgcol, bgcol);
9e057c0b 1338 } else if (cw != 9) {
d2e043a8
BH
1339 vga_draw_glyph8(d, linesize,
1340 cursor_glyph, h, fgcol, bgcol);
e89f66ec 1341 } else {
d2e043a8
BH
1342 vga_draw_glyph9(d, linesize,
1343 cursor_glyph, h, fgcol, bgcol, 1);
e89f66ec
FB
1344 }
1345 }
1346 }
1347 }
1348 d1 += x_incr;
1349 src += 4;
1350 ch_attr_ptr++;
1351 }
1352 if (cx_max != -1) {
c78f7137 1353 dpy_gfx_update(s->con, cx_min * cw, cy * cheight,
a93a4a22 1354 (cx_max - cx_min + 1) * cw, cheight);
e89f66ec
FB
1355 }
1356 dest += linesize * cheight;
cae334cd 1357 line1 = line + cheight;
1358 offset += line_offset;
1359 if (line < s->line_compare && line1 >= s->line_compare) {
d1984194 1360 offset = 0;
1361 }
cae334cd 1362 line = line1;
e89f66ec
FB
1363 }
1364}
1365
17b0018b
FB
1366enum {
1367 VGA_DRAW_LINE2,
1368 VGA_DRAW_LINE2D2,
1369 VGA_DRAW_LINE4,
1370 VGA_DRAW_LINE4D2,
1371 VGA_DRAW_LINE8D2,
1372 VGA_DRAW_LINE8,
46c3a8c8
BH
1373 VGA_DRAW_LINE15_LE,
1374 VGA_DRAW_LINE16_LE,
1375 VGA_DRAW_LINE24_LE,
1376 VGA_DRAW_LINE32_LE,
1377 VGA_DRAW_LINE15_BE,
1378 VGA_DRAW_LINE16_BE,
1379 VGA_DRAW_LINE24_BE,
1380 VGA_DRAW_LINE32_BE,
17b0018b
FB
1381 VGA_DRAW_LINE_NB,
1382};
1383
9e057c0b 1384static vga_draw_line_func * const vga_draw_line_table[VGA_DRAW_LINE_NB] = {
d2e043a8
BH
1385 vga_draw_line2,
1386 vga_draw_line2d2,
1387 vga_draw_line4,
1388 vga_draw_line4d2,
1389 vga_draw_line8d2,
1390 vga_draw_line8,
46c3a8c8
BH
1391 vga_draw_line15_le,
1392 vga_draw_line16_le,
1393 vga_draw_line24_le,
1394 vga_draw_line32_le,
1395 vga_draw_line15_be,
1396 vga_draw_line16_be,
1397 vga_draw_line24_be,
1398 vga_draw_line32_be,
d3079cd2
FB
1399};
1400
cedd91d2 1401static int vga_get_bpp(VGACommonState *s)
798b0c25
FB
1402{
1403 int ret;
a96d8bea 1404
bfa0f151 1405 if (vbe_enabled(s)) {
798b0c25 1406 ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
a96d8bea 1407 } else {
798b0c25
FB
1408 ret = 0;
1409 }
1410 return ret;
1411}
1412
cedd91d2 1413static void vga_get_resolution(VGACommonState *s, int *pwidth, int *pheight)
a130a41e
FB
1414{
1415 int width, height;
3b46e624 1416
bfa0f151 1417 if (vbe_enabled(s)) {
8454df8b
FB
1418 width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
1419 height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
a96d8bea 1420 } else {
5e55efc9
BS
1421 width = (s->cr[VGA_CRTC_H_DISP] + 1) * 8;
1422 height = s->cr[VGA_CRTC_V_DISP_END] |
1423 ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) |
1424 ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3);
8454df8b
FB
1425 height = (height + 1);
1426 }
a130a41e
FB
1427 *pwidth = width;
1428 *pheight = height;
1429}
1430
cedd91d2 1431void vga_invalidate_scanlines(VGACommonState *s, int y1, int y2)
a8aa669b
FB
1432{
1433 int y;
1434 if (y1 >= VGA_MAX_HEIGHT)
1435 return;
1436 if (y2 >= VGA_MAX_HEIGHT)
1437 y2 = VGA_MAX_HEIGHT;
1438 for(y = y1; y < y2; y++) {
1439 s->invalidated_y_table[y >> 5] |= 1 << (y & 0x1f);
1440 }
1441}
1442
f3289f6f
GH
1443static bool vga_scanline_invalidated(VGACommonState *s, int y)
1444{
1445 if (y >= VGA_MAX_HEIGHT) {
1446 return false;
1447 }
1448 return s->invalidated_y_table[y >> 5] & (1 << (y & 0x1f));
1449}
1450
50af3246
JQ
1451void vga_dirty_log_start(VGACommonState *s)
1452{
b1950430 1453 memory_region_set_log(&s->vram, true, DIRTY_MEMORY_VGA);
b5cc6e32
AL
1454}
1455
1456void vga_dirty_log_stop(VGACommonState *s)
1457{
b1950430 1458 memory_region_set_log(&s->vram, false, DIRTY_MEMORY_VGA);
b5cc6e32
AL
1459}
1460
799e709b
AL
1461/*
1462 * graphic modes
1463 */
cedd91d2 1464static void vga_draw_graphic(VGACommonState *s, int full_update)
e89f66ec 1465{
c78f7137 1466 DisplaySurface *surface = qemu_console_surface(s->con);
12c7e75a 1467 int y1, y, update, linesize, y_start, double_scan, mask, depth;
362f8117 1468 int width, height, shift_control, bwidth, bits;
28f77de2 1469 ram_addr_t page0, page1, region_start, region_end;
fec5e8c9 1470 DirtyBitmapSnapshot *snap = NULL;
a07cf92a 1471 int disp_width, multi_scan, multi_run;
799e709b
AL
1472 uint8_t *d;
1473 uint32_t v, addr1, addr;
2c7d8736 1474 vga_draw_line_func *vga_draw_line = NULL;
28f77de2 1475 bool share_surface, force_shadow = false;
49743df3 1476 pixman_format_code_t format;
2c7d8736
BH
1477#ifdef HOST_WORDS_BIGENDIAN
1478 bool byteswap = !s->big_endian_fb;
46c3a8c8 1479#else
2c7d8736 1480 bool byteswap = s->big_endian_fb;
b1424e03 1481#endif
799e709b
AL
1482
1483 full_update |= update_basic_params(s);
1484
a130a41e 1485 s->get_resolution(s, &width, &height);
17b0018b 1486 disp_width = width;
a89fe6c3 1487 depth = s->get_bpp(s);
09a79b49 1488
28f77de2 1489 region_start = (s->start_addr * 4);
b0898b42 1490 region_end = region_start + (ram_addr_t)s->line_offset * height;
a89fe6c3 1491 region_end += width * depth / 8; /* scanline length */
7cdc61be 1492 region_end -= s->line_offset;
a89fe6c3
GH
1493 if (region_end > s->vbe_size || depth == 0 || depth == 15) {
1494 /*
1495 * We land here on:
1496 * - wraps around (can happen with cirrus vbe modes)
1497 * - depth == 0 (256 color palette video mode)
1498 * - depth == 15
1499 *
1500 * Take the safe and slow route:
1501 * - create a dirty bitmap snapshot for all vga memory.
1502 * - force shadowing (so all vga memory access goes
1503 * through vga_read_*() helpers).
1504 *
1505 * Given this affects only vga features which are pretty much
1506 * unused by modern guests there should be no performance
1507 * impact.
1508 */
28f77de2
GH
1509 region_start = 0;
1510 region_end = s->vbe_size;
1511 force_shadow = true;
1512 }
1513
5e55efc9
BS
1514 shift_control = (s->gr[VGA_GFX_MODE] >> 5) & 3;
1515 double_scan = (s->cr[VGA_CRTC_MAX_SCAN] >> 7);
799e709b 1516 if (shift_control != 1) {
5e55efc9
BS
1517 multi_scan = (((s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1) << double_scan)
1518 - 1;
799e709b
AL
1519 } else {
1520 /* in CGA modes, multi_scan is ignored */
1521 /* XXX: is it correct ? */
1522 multi_scan = double_scan;
1523 }
1524 multi_run = multi_scan;
17b0018b
FB
1525 if (shift_control != s->shift_control ||
1526 double_scan != s->double_scan) {
799e709b 1527 full_update = 1;
e89f66ec 1528 s->shift_control = shift_control;
17b0018b 1529 s->double_scan = double_scan;
e89f66ec 1530 }
3b46e624 1531
aba35a6c 1532 if (shift_control == 0) {
94ef4f33 1533 if (sr(s, VGA_SEQ_CLOCK_MODE) & 8) {
aba35a6c 1534 disp_width <<= 1;
1535 }
1536 } else if (shift_control == 1) {
94ef4f33 1537 if (sr(s, VGA_SEQ_CLOCK_MODE) & 8) {
aba35a6c 1538 disp_width <<= 1;
1539 }
1540 }
1541
49743df3
BH
1542 /*
1543 * Check whether we can share the surface with the backend
1544 * or whether we need a shadow surface. We share native
1545 * endian surfaces for 15bpp and above and byteswapped
1546 * surfaces for 24bpp and above.
1547 */
1548 format = qemu_default_pixman_format(depth, !byteswap);
1549 if (format) {
1550 share_surface = dpy_gfx_check_format(s->con, format)
28f77de2 1551 && !s->force_shadow && !force_shadow;
49743df3
BH
1552 } else {
1553 share_surface = false;
1554 }
6bc2fd57 1555
e3697092
AJ
1556 if (s->line_offset != s->last_line_offset ||
1557 disp_width != s->last_width ||
1558 height != s->last_height ||
c3b10605 1559 s->last_depth != depth ||
55080993
BH
1560 s->last_byteswap != byteswap ||
1561 share_surface != is_buffer_shared(surface)) {
6bc2fd57
GH
1562 /* display parameters changed -> need new display surface */
1563 s->last_scr_width = disp_width;
1564 s->last_scr_height = height;
1565 s->last_width = disp_width;
1566 s->last_height = height;
1567 s->last_line_offset = s->line_offset;
1568 s->last_depth = depth;
1569 s->last_byteswap = byteswap;
1570 full_update = 1;
1571 }
1572 if (surface_data(surface) != s->vram_ptr + (s->start_addr * 4)
1573 && is_buffer_shared(surface)) {
1574 /* base address changed (page flip) -> shared display surfaces
1575 * must be updated with the new base address */
1576 full_update = 1;
1577 }
1578
1579 if (full_update) {
55080993 1580 if (share_surface) {
da229ef3 1581 surface = qemu_create_displaysurface_from(disp_width,
30f1e661
GH
1582 height, format, s->line_offset,
1583 s->vram_ptr + (s->start_addr * 4));
c78f7137 1584 dpy_gfx_replace_surface(s->con, surface);
e3697092 1585 } else {
c78f7137
GH
1586 qemu_console_resize(s->con, disp_width, height);
1587 surface = qemu_console_surface(s->con);
e3697092 1588 }
e3697092
AJ
1589 }
1590
799e709b 1591 if (shift_control == 0) {
17b0018b 1592 full_update |= update_palette16(s);
94ef4f33 1593 if (sr(s, VGA_SEQ_CLOCK_MODE) & 8) {
17b0018b 1594 v = VGA_DRAW_LINE4D2;
17b0018b
FB
1595 } else {
1596 v = VGA_DRAW_LINE4;
1597 }
15342721 1598 bits = 4;
799e709b 1599 } else if (shift_control == 1) {
17b0018b 1600 full_update |= update_palette16(s);
94ef4f33 1601 if (sr(s, VGA_SEQ_CLOCK_MODE) & 8) {
17b0018b 1602 v = VGA_DRAW_LINE2D2;
17b0018b
FB
1603 } else {
1604 v = VGA_DRAW_LINE2;
1605 }
15342721 1606 bits = 4;
17b0018b 1607 } else {
798b0c25
FB
1608 switch(s->get_bpp(s)) {
1609 default:
1610 case 0:
4fa0f5d2
FB
1611 full_update |= update_palette256(s);
1612 v = VGA_DRAW_LINE8D2;
15342721 1613 bits = 4;
798b0c25
FB
1614 break;
1615 case 8:
1616 full_update |= update_palette256(s);
1617 v = VGA_DRAW_LINE8;
15342721 1618 bits = 8;
798b0c25
FB
1619 break;
1620 case 15:
2c7d8736 1621 v = s->big_endian_fb ? VGA_DRAW_LINE15_BE : VGA_DRAW_LINE15_LE;
15342721 1622 bits = 16;
798b0c25
FB
1623 break;
1624 case 16:
2c7d8736 1625 v = s->big_endian_fb ? VGA_DRAW_LINE16_BE : VGA_DRAW_LINE16_LE;
15342721 1626 bits = 16;
798b0c25
FB
1627 break;
1628 case 24:
2c7d8736 1629 v = s->big_endian_fb ? VGA_DRAW_LINE24_BE : VGA_DRAW_LINE24_LE;
15342721 1630 bits = 24;
798b0c25
FB
1631 break;
1632 case 32:
2c7d8736 1633 v = s->big_endian_fb ? VGA_DRAW_LINE32_BE : VGA_DRAW_LINE32_LE;
15342721 1634 bits = 32;
798b0c25 1635 break;
4fa0f5d2 1636 }
17b0018b 1637 }
9e057c0b 1638 vga_draw_line = vga_draw_line_table[v];
17b0018b 1639
c78f7137 1640 if (!is_buffer_shared(surface) && s->cursor_invalidate) {
a8aa669b 1641 s->cursor_invalidate(s);
c78f7137 1642 }
3b46e624 1643
17b0018b 1644#if 0
f6c958c8 1645 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 1646 width, height, v, line_offset, s->cr[9], s->cr[VGA_CRTC_MODE],
94ef4f33 1647 s->line_compare, sr(s, VGA_SEQ_CLOCK_MODE));
17b0018b 1648#endif
e89f66ec 1649 addr1 = (s->start_addr * 4);
2c23ce22 1650 bwidth = DIV_ROUND_UP(width * bits, 8);
39cf7803 1651 y_start = -1;
c78f7137
GH
1652 d = surface_data(surface);
1653 linesize = surface_stride(surface);
17b0018b 1654 y1 = 0;
fec5e8c9
GH
1655
1656 if (!full_update) {
e6529415
GH
1657 if (s->line_compare < height) {
1658 /* split screen mode */
1659 region_start = 0;
1660 }
1661 snap = memory_region_snapshot_and_clear_dirty(&s->vram, region_start,
1662 region_end - region_start,
fec5e8c9
GH
1663 DIRTY_MEMORY_VGA);
1664 }
1665
e89f66ec
FB
1666 for(y = 0; y < height; y++) {
1667 addr = addr1;
5e55efc9 1668 if (!(s->cr[VGA_CRTC_MODE] & 1)) {
17b0018b 1669 int shift;
e89f66ec 1670 /* CGA compatibility handling */
5e55efc9 1671 shift = 14 + ((s->cr[VGA_CRTC_MODE] >> 6) & 1);
17b0018b 1672 addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
e89f66ec 1673 }
5e55efc9 1674 if (!(s->cr[VGA_CRTC_MODE] & 2)) {
17b0018b 1675 addr = (addr & ~0x8000) | ((y1 & 2) << 14);
e89f66ec 1676 }
734781c9 1677 update = full_update;
28f77de2
GH
1678 page0 = addr & s->vbe_size_mask;
1679 page1 = (addr + bwidth - 1) & s->vbe_size_mask;
fec5e8c9
GH
1680 if (full_update) {
1681 update = 1;
28f77de2
GH
1682 } else if (page1 < page0) {
1683 /* scanline wraps from end of video memory to the start */
1684 assert(force_shadow);
1685 update = memory_region_snapshot_get_dirty(&s->vram, snap,
115788d7 1686 page0, s->vbe_size - page0);
28f77de2 1687 update |= memory_region_snapshot_get_dirty(&s->vram, snap,
115788d7 1688 0, page1);
fec5e8c9
GH
1689 } else {
1690 update = memory_region_snapshot_get_dirty(&s->vram, snap,
1691 page0, page1 - page0);
1692 }
f3289f6f
GH
1693 /* explicit invalidation for the hardware cursor (cirrus only) */
1694 update |= vga_scanline_invalidated(s, y);
e89f66ec 1695 if (update) {
39cf7803
FB
1696 if (y_start < 0)
1697 y_start = y;
c78f7137 1698 if (!(is_buffer_shared(surface))) {
3d90c625 1699 vga_draw_line(s, d, addr, width);
7d957bd8
AL
1700 if (s->cursor_draw_line)
1701 s->cursor_draw_line(s, d, y);
1702 }
39cf7803
FB
1703 } else {
1704 if (y_start >= 0) {
1705 /* flush to display */
c78f7137 1706 dpy_gfx_update(s->con, 0, y_start,
a93a4a22 1707 disp_width, y - y_start);
39cf7803
FB
1708 y_start = -1;
1709 }
e89f66ec 1710 }
a07cf92a 1711 if (!multi_run) {
5e55efc9 1712 mask = (s->cr[VGA_CRTC_MODE] & 3) ^ 3;
f6c958c8 1713 if ((y1 & mask) == mask)
362f8117 1714 addr1 += s->line_offset;
f6c958c8 1715 y1++;
799e709b 1716 multi_run = multi_scan;
a07cf92a
FB
1717 } else {
1718 multi_run--;
e89f66ec 1719 }
f6c958c8
FB
1720 /* line compare acts on the displayed lines */
1721 if (y == s->line_compare)
1722 addr1 = 0;
e89f66ec
FB
1723 d += linesize;
1724 }
39cf7803
FB
1725 if (y_start >= 0) {
1726 /* flush to display */
c78f7137 1727 dpy_gfx_update(s->con, 0, y_start,
a93a4a22 1728 disp_width, y - y_start);
39cf7803 1729 }
fec5e8c9 1730 g_free(snap);
f3289f6f 1731 memset(s->invalidated_y_table, 0, sizeof(s->invalidated_y_table));
e89f66ec
FB
1732}
1733
cedd91d2 1734static void vga_draw_blank(VGACommonState *s, int full_update)
2aebb3eb 1735{
c78f7137 1736 DisplaySurface *surface = qemu_console_surface(s->con);
2c79f2a2 1737 int i, w;
2aebb3eb
FB
1738 uint8_t *d;
1739
1740 if (!full_update)
1741 return;
1742 if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
1743 return;
2bec46dc 1744
c78f7137
GH
1745 w = s->last_scr_width * surface_bytes_per_pixel(surface);
1746 d = surface_data(surface);
2aebb3eb 1747 for(i = 0; i < s->last_scr_height; i++) {
2c79f2a2 1748 memset(d, 0, w);
c78f7137 1749 d += surface_stride(surface);
2aebb3eb 1750 }
91155f8b 1751 dpy_gfx_update_full(s->con);
2aebb3eb
FB
1752}
1753
799e709b
AL
1754#define GMODE_TEXT 0
1755#define GMODE_GRAPH 1
1756#define GMODE_BLANK 2
1757
95219897 1758static void vga_update_display(void *opaque)
e89f66ec 1759{
cedd91d2 1760 VGACommonState *s = opaque;
c78f7137 1761 DisplaySurface *surface = qemu_console_surface(s->con);
799e709b 1762 int full_update, graphic_mode;
e89f66ec 1763
e9a07334
JK
1764 qemu_flush_coalesced_mmio_buffer();
1765
c78f7137 1766 if (surface_bits_per_pixel(surface) == 0) {
0f35920c 1767 /* nothing to do */
59a983b9 1768 } else {
3098b9fd 1769 full_update = 0;
df800210 1770 if (!(s->ar_index & 0x20)) {
799e709b
AL
1771 graphic_mode = GMODE_BLANK;
1772 } else {
5e55efc9 1773 graphic_mode = s->gr[VGA_GFX_MISC] & VGA_GR06_GRAPHICS_MODE;
799e709b
AL
1774 }
1775 if (graphic_mode != s->graphic_mode) {
1776 s->graphic_mode = graphic_mode;
bc72ad67 1777 s->cursor_blink_time = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
799e709b
AL
1778 full_update = 1;
1779 }
1780 switch(graphic_mode) {
2aebb3eb 1781 case GMODE_TEXT:
e89f66ec 1782 vga_draw_text(s, full_update);
2aebb3eb
FB
1783 break;
1784 case GMODE_GRAPH:
1785 vga_draw_graphic(s, full_update);
1786 break;
1787 case GMODE_BLANK:
1788 default:
1789 vga_draw_blank(s, full_update);
1790 break;
1791 }
e89f66ec
FB
1792 }
1793}
1794
a130a41e 1795/* force a full display refresh */
95219897 1796static void vga_invalidate_display(void *opaque)
a130a41e 1797{
cedd91d2 1798 VGACommonState *s = opaque;
3b46e624 1799
3098b9fd
AJ
1800 s->last_width = -1;
1801 s->last_height = -1;
a130a41e
FB
1802}
1803
03a3e7ba 1804void vga_common_reset(VGACommonState *s)
e89f66ec 1805{
6e6b7363
BS
1806 s->sr_index = 0;
1807 memset(s->sr, '\0', sizeof(s->sr));
94ef4f33 1808 memset(s->sr_vbe, '\0', sizeof(s->sr_vbe));
6e6b7363
BS
1809 s->gr_index = 0;
1810 memset(s->gr, '\0', sizeof(s->gr));
1811 s->ar_index = 0;
1812 memset(s->ar, '\0', sizeof(s->ar));
1813 s->ar_flip_flop = 0;
1814 s->cr_index = 0;
1815 memset(s->cr, '\0', sizeof(s->cr));
1816 s->msr = 0;
1817 s->fcr = 0;
1818 s->st00 = 0;
1819 s->st01 = 0;
1820 s->dac_state = 0;
1821 s->dac_sub_index = 0;
1822 s->dac_read_index = 0;
1823 s->dac_write_index = 0;
1824 memset(s->dac_cache, '\0', sizeof(s->dac_cache));
1825 s->dac_8bit = 0;
1826 memset(s->palette, '\0', sizeof(s->palette));
1827 s->bank_offset = 0;
6e6b7363
BS
1828 s->vbe_index = 0;
1829 memset(s->vbe_regs, '\0', sizeof(s->vbe_regs));
af92284b 1830 s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID5;
6e6b7363
BS
1831 s->vbe_start_addr = 0;
1832 s->vbe_line_offset = 0;
1833 s->vbe_bank_mask = (s->vram_size >> 16) - 1;
6e6b7363 1834 memset(s->font_offsets, '\0', sizeof(s->font_offsets));
799e709b 1835 s->graphic_mode = -1; /* force full update */
6e6b7363
BS
1836 s->shift_control = 0;
1837 s->double_scan = 0;
1838 s->line_offset = 0;
1839 s->line_compare = 0;
1840 s->start_addr = 0;
1841 s->plane_updated = 0;
1842 s->last_cw = 0;
1843 s->last_ch = 0;
1844 s->last_width = 0;
1845 s->last_height = 0;
1846 s->last_scr_width = 0;
1847 s->last_scr_height = 0;
1848 s->cursor_start = 0;
1849 s->cursor_end = 0;
1850 s->cursor_offset = 0;
c3b10605 1851 s->big_endian_fb = s->default_endian_fb;
6e6b7363
BS
1852 memset(s->invalidated_y_table, '\0', sizeof(s->invalidated_y_table));
1853 memset(s->last_palette, '\0', sizeof(s->last_palette));
1854 memset(s->last_ch_attr, '\0', sizeof(s->last_ch_attr));
1855 switch (vga_retrace_method) {
1856 case VGA_RETRACE_DUMB:
1857 break;
1858 case VGA_RETRACE_PRECISE:
1859 memset(&s->retrace_info, 0, sizeof (s->retrace_info));
1860 break;
1861 }
80763888 1862 vga_update_memory_access(s);
e89f66ec
FB
1863}
1864
03a3e7ba
JQ
1865static void vga_reset(void *opaque)
1866{
cedd91d2 1867 VGACommonState *s = opaque;
03a3e7ba
JQ
1868 vga_common_reset(s);
1869}
1870
4d3b6f6e
AZ
1871#define TEXTMODE_X(x) ((x) % width)
1872#define TEXTMODE_Y(x) ((x) / width)
1873#define VMEM2CHTYPE(v) ((v & 0xff0007ff) | \
1874 ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1))
1875/* relay text rendering to the display driver
1876 * instead of doing a full vga_update_display() */
c227f099 1877static void vga_update_text(void *opaque, console_ch_t *chardata)
4d3b6f6e 1878{
cedd91d2 1879 VGACommonState *s = opaque;
799e709b 1880 int graphic_mode, i, cursor_offset, cursor_visible;
4d3b6f6e
AZ
1881 int cw, cheight, width, height, size, c_min, c_max;
1882 uint32_t *src;
c227f099 1883 console_ch_t *dst, val;
4d3b6f6e 1884 char msg_buffer[80];
799e709b
AL
1885 int full_update = 0;
1886
e9a07334
JK
1887 qemu_flush_coalesced_mmio_buffer();
1888
799e709b
AL
1889 if (!(s->ar_index & 0x20)) {
1890 graphic_mode = GMODE_BLANK;
1891 } else {
5e55efc9 1892 graphic_mode = s->gr[VGA_GFX_MISC] & VGA_GR06_GRAPHICS_MODE;
799e709b
AL
1893 }
1894 if (graphic_mode != s->graphic_mode) {
1895 s->graphic_mode = graphic_mode;
1896 full_update = 1;
1897 }
1898 if (s->last_width == -1) {
1899 s->last_width = 0;
1900 full_update = 1;
1901 }
4d3b6f6e 1902
799e709b 1903 switch (graphic_mode) {
4d3b6f6e
AZ
1904 case GMODE_TEXT:
1905 /* TODO: update palette */
799e709b 1906 full_update |= update_basic_params(s);
4d3b6f6e 1907
799e709b 1908 /* total width & height */
5e55efc9 1909 cheight = (s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1;
799e709b 1910 cw = 8;
94ef4f33 1911 if (!(sr(s, VGA_SEQ_CLOCK_MODE) & VGA_SR01_CHAR_CLK_8DOTS)) {
799e709b 1912 cw = 9;
5e55efc9 1913 }
94ef4f33 1914 if (sr(s, VGA_SEQ_CLOCK_MODE) & 0x08) {
799e709b 1915 cw = 16; /* NOTE: no 18 pixel wide */
5e55efc9
BS
1916 }
1917 width = (s->cr[VGA_CRTC_H_DISP] + 1);
1918 if (s->cr[VGA_CRTC_V_TOTAL] == 100) {
799e709b
AL
1919 /* ugly hack for CGA 160x100x16 - explain me the logic */
1920 height = 100;
1921 } else {
5e55efc9
BS
1922 height = s->cr[VGA_CRTC_V_DISP_END] |
1923 ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) |
1924 ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3);
799e709b 1925 height = (height + 1) / cheight;
4d3b6f6e
AZ
1926 }
1927
1928 size = (height * width);
1929 if (size > CH_ATTR_SIZE) {
1930 if (!full_update)
1931 return;
1932
363a37d5
BS
1933 snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Text mode",
1934 width, height);
4d3b6f6e
AZ
1935 break;
1936 }
1937
799e709b
AL
1938 if (width != s->last_width || height != s->last_height ||
1939 cw != s->last_cw || cheight != s->last_ch) {
1940 s->last_scr_width = width * cw;
1941 s->last_scr_height = height * cheight;
c78f7137
GH
1942 qemu_console_resize(s->con, s->last_scr_width, s->last_scr_height);
1943 dpy_text_resize(s->con, width, height);
9678aedd 1944 s->last_depth = 0;
799e709b
AL
1945 s->last_width = width;
1946 s->last_height = height;
1947 s->last_ch = cheight;
1948 s->last_cw = cw;
1949 full_update = 1;
1950 }
1951
9678aedd
GH
1952 if (full_update) {
1953 s->full_update_gfx = 1;
1954 }
1955 if (s->full_update_text) {
1956 s->full_update_text = 0;
1957 full_update |= 1;
1958 }
1959
4d3b6f6e 1960 /* Update "hardware" cursor */
5e55efc9
BS
1961 cursor_offset = ((s->cr[VGA_CRTC_CURSOR_HI] << 8) |
1962 s->cr[VGA_CRTC_CURSOR_LO]) - s->start_addr;
4d3b6f6e 1963 if (cursor_offset != s->cursor_offset ||
5e55efc9
BS
1964 s->cr[VGA_CRTC_CURSOR_START] != s->cursor_start ||
1965 s->cr[VGA_CRTC_CURSOR_END] != s->cursor_end || full_update) {
1966 cursor_visible = !(s->cr[VGA_CRTC_CURSOR_START] & 0x20);
4d3b6f6e 1967 if (cursor_visible && cursor_offset < size && cursor_offset >= 0)
c78f7137 1968 dpy_text_cursor(s->con,
bf2fde70
GH
1969 TEXTMODE_X(cursor_offset),
1970 TEXTMODE_Y(cursor_offset));
4d3b6f6e 1971 else
c78f7137 1972 dpy_text_cursor(s->con, -1, -1);
4d3b6f6e 1973 s->cursor_offset = cursor_offset;
5e55efc9
BS
1974 s->cursor_start = s->cr[VGA_CRTC_CURSOR_START];
1975 s->cursor_end = s->cr[VGA_CRTC_CURSOR_END];
4d3b6f6e
AZ
1976 }
1977
1978 src = (uint32_t *) s->vram_ptr + s->start_addr;
1979 dst = chardata;
1980
1981 if (full_update) {
1982 for (i = 0; i < size; src ++, dst ++, i ++)
9ae19b65 1983 console_write_ch(dst, VMEM2CHTYPE(le32_to_cpu(*src)));
4d3b6f6e 1984
c78f7137 1985 dpy_text_update(s->con, 0, 0, width, height);
4d3b6f6e
AZ
1986 } else {
1987 c_max = 0;
1988
1989 for (i = 0; i < size; src ++, dst ++, i ++) {
9ae19b65 1990 console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
4d3b6f6e
AZ
1991 if (*dst != val) {
1992 *dst = val;
1993 c_max = i;
1994 break;
1995 }
1996 }
1997 c_min = i;
1998 for (; i < size; src ++, dst ++, i ++) {
9ae19b65 1999 console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
4d3b6f6e
AZ
2000 if (*dst != val) {
2001 *dst = val;
2002 c_max = i;
2003 }
2004 }
2005
2006 if (c_min <= c_max) {
2007 i = TEXTMODE_Y(c_min);
c78f7137 2008 dpy_text_update(s->con, 0, i, width, TEXTMODE_Y(c_max) - i + 1);
4d3b6f6e
AZ
2009 }
2010 }
2011
2012 return;
2013 case GMODE_GRAPH:
2014 if (!full_update)
2015 return;
2016
2017 s->get_resolution(s, &width, &height);
363a37d5
BS
2018 snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Graphic mode",
2019 width, height);
4d3b6f6e
AZ
2020 break;
2021 case GMODE_BLANK:
2022 default:
2023 if (!full_update)
2024 return;
2025
363a37d5 2026 snprintf(msg_buffer, sizeof(msg_buffer), "VGA Blank mode");
4d3b6f6e
AZ
2027 break;
2028 }
2029
2030 /* Display a message */
5228c2d3
AZ
2031 s->last_width = 60;
2032 s->last_height = height = 3;
c78f7137
GH
2033 dpy_text_cursor(s->con, -1, -1);
2034 dpy_text_resize(s->con, s->last_width, height);
4d3b6f6e 2035
5228c2d3 2036 for (dst = chardata, i = 0; i < s->last_width * height; i ++)
4d3b6f6e
AZ
2037 console_write_ch(dst ++, ' ');
2038
2039 size = strlen(msg_buffer);
5228c2d3
AZ
2040 width = (s->last_width - size) / 2;
2041 dst = chardata + s->last_width + width;
4d3b6f6e 2042 for (i = 0; i < size; i ++)
4083733d
OH
2043 console_write_ch(dst ++, ATTR2CHTYPE(msg_buffer[i], QEMU_COLOR_BLUE,
2044 QEMU_COLOR_BLACK, 1));
4d3b6f6e 2045
c78f7137 2046 dpy_text_update(s->con, 0, 0, s->last_width, height);
4d3b6f6e
AZ
2047}
2048
a8170e5e 2049static uint64_t vga_mem_read(void *opaque, hwaddr addr,
b1950430
AK
2050 unsigned size)
2051{
2052 VGACommonState *s = opaque;
2053
b2a5e761 2054 return vga_mem_readb(s, addr);
b1950430 2055}
e89f66ec 2056
a8170e5e 2057static void vga_mem_write(void *opaque, hwaddr addr,
b1950430
AK
2058 uint64_t data, unsigned size)
2059{
2060 VGACommonState *s = opaque;
2061
e7ae771f 2062 vga_mem_writeb(s, addr, data);
b1950430
AK
2063}
2064
2065const MemoryRegionOps vga_mem_ops = {
2066 .read = vga_mem_read,
2067 .write = vga_mem_write,
2068 .endianness = DEVICE_LITTLE_ENDIAN,
b2a5e761
AK
2069 .impl = {
2070 .min_access_size = 1,
2071 .max_access_size = 1,
2072 },
e89f66ec
FB
2073};
2074
11b6b345 2075static int vga_common_post_load(void *opaque, int version_id)
b0a21b53 2076{
0d65ddc3 2077 VGACommonState *s = opaque;
11b6b345
JQ
2078
2079 /* force refresh */
2080 s->graphic_mode = -1;
94ef4f33 2081 vbe_update_vgaregs(s);
138bc2df 2082 vga_update_memory_access(s);
11b6b345
JQ
2083 return 0;
2084}
2085
c3b10605
BH
2086static bool vga_endian_state_needed(void *opaque)
2087{
2088 VGACommonState *s = opaque;
2089
2090 /*
2091 * Only send the endian state if it's different from the
2092 * default one, thus ensuring backward compatibility for
2093 * migration of the common case
2094 */
2095 return s->default_endian_fb != s->big_endian_fb;
2096}
2097
73d22caf 2098static const VMStateDescription vmstate_vga_endian = {
c3b10605
BH
2099 .name = "vga.endian",
2100 .version_id = 1,
2101 .minimum_version_id = 1,
5cd8cada 2102 .needed = vga_endian_state_needed,
c3b10605
BH
2103 .fields = (VMStateField[]) {
2104 VMSTATE_BOOL(big_endian_fb, VGACommonState),
2105 VMSTATE_END_OF_LIST()
2106 }
2107};
2108
11b6b345
JQ
2109const VMStateDescription vmstate_vga_common = {
2110 .name = "vga",
2111 .version_id = 2,
2112 .minimum_version_id = 2,
11b6b345 2113 .post_load = vga_common_post_load,
d49805ae 2114 .fields = (VMStateField[]) {
11b6b345
JQ
2115 VMSTATE_UINT32(latch, VGACommonState),
2116 VMSTATE_UINT8(sr_index, VGACommonState),
2117 VMSTATE_PARTIAL_BUFFER(sr, VGACommonState, 8),
2118 VMSTATE_UINT8(gr_index, VGACommonState),
2119 VMSTATE_PARTIAL_BUFFER(gr, VGACommonState, 16),
2120 VMSTATE_UINT8(ar_index, VGACommonState),
2121 VMSTATE_BUFFER(ar, VGACommonState),
2122 VMSTATE_INT32(ar_flip_flop, VGACommonState),
2123 VMSTATE_UINT8(cr_index, VGACommonState),
2124 VMSTATE_BUFFER(cr, VGACommonState),
2125 VMSTATE_UINT8(msr, VGACommonState),
2126 VMSTATE_UINT8(fcr, VGACommonState),
2127 VMSTATE_UINT8(st00, VGACommonState),
2128 VMSTATE_UINT8(st01, VGACommonState),
2129
2130 VMSTATE_UINT8(dac_state, VGACommonState),
2131 VMSTATE_UINT8(dac_sub_index, VGACommonState),
2132 VMSTATE_UINT8(dac_read_index, VGACommonState),
2133 VMSTATE_UINT8(dac_write_index, VGACommonState),
2134 VMSTATE_BUFFER(dac_cache, VGACommonState),
2135 VMSTATE_BUFFER(palette, VGACommonState),
2136
2137 VMSTATE_INT32(bank_offset, VGACommonState),
d2164ad3 2138 VMSTATE_UINT8_EQUAL(is_vbe_vmstate, VGACommonState, NULL),
11b6b345
JQ
2139 VMSTATE_UINT16(vbe_index, VGACommonState),
2140 VMSTATE_UINT16_ARRAY(vbe_regs, VGACommonState, VBE_DISPI_INDEX_NB),
2141 VMSTATE_UINT32(vbe_start_addr, VGACommonState),
2142 VMSTATE_UINT32(vbe_line_offset, VGACommonState),
2143 VMSTATE_UINT32(vbe_bank_mask, VGACommonState),
11b6b345 2144 VMSTATE_END_OF_LIST()
c3b10605 2145 },
5cd8cada
JQ
2146 .subsections = (const VMStateDescription*[]) {
2147 &vmstate_vga_endian,
2148 NULL
11b6b345
JQ
2149 }
2150};
2151
380cd056
GH
2152static const GraphicHwOps vga_ops = {
2153 .invalidate = vga_invalidate_display,
2154 .gfx_update = vga_update_display,
2155 .text_update = vga_update_text,
2156};
2157
619616ce
RK
2158static inline uint32_t uint_clamp(uint32_t val, uint32_t vmin, uint32_t vmax)
2159{
2160 if (val < vmin) {
2161 return vmin;
2162 }
2163 if (val > vmax) {
2164 return vmax;
2165 }
2166 return val;
2167}
2168
1fcfdc43 2169void vga_common_init(VGACommonState *s, Object *obj)
e89f66ec 2170{
17b0018b 2171 int i, j, v, b;
e89f66ec
FB
2172
2173 for(i = 0;i < 256; i++) {
2174 v = 0;
2175 for(j = 0; j < 8; j++) {
2176 v |= ((i >> j) & 1) << (j * 4);
2177 }
2178 expand4[i] = v;
2179
2180 v = 0;
2181 for(j = 0; j < 4; j++) {
2182 v |= ((i >> (2 * j)) & 3) << (j * 4);
2183 }
2184 expand2[i] = v;
2185 }
17b0018b
FB
2186 for(i = 0; i < 16; i++) {
2187 v = 0;
2188 for(j = 0; j < 4; j++) {
2189 b = ((i >> j) & 1);
2190 v |= b << (2 * j);
2191 v |= b << (2 * j + 1);
2192 }
2193 expand4to8[i] = v;
2194 }
e89f66ec 2195
619616ce
RK
2196 s->vram_size_mb = uint_clamp(s->vram_size_mb, 1, 512);
2197 s->vram_size_mb = pow2ceil(s->vram_size_mb);
f0353b0d 2198 s->vram_size = s->vram_size_mb * MiB;
619616ce 2199
54a85d46
GH
2200 if (!s->vbe_size) {
2201 s->vbe_size = s->vram_size;
2202 }
3d90c625 2203 s->vbe_size_mask = s->vbe_size - 1;
4a1e244e 2204
2a3138ab 2205 s->is_vbe_vmstate = 1;
1cfe48c1 2206 memory_region_init_ram_nomigrate(&s->vram, obj, "vga.vram", s->vram_size,
f8ed85ac 2207 &error_fatal);
1fcfdc43 2208 vmstate_register_ram(&s->vram, s->global_vmstate ? NULL : DEVICE(obj));
c65adf9b 2209 xen_register_framebuffer(&s->vram);
b1950430 2210 s->vram_ptr = memory_region_get_ram_ptr(&s->vram);
798b0c25
FB
2211 s->get_bpp = vga_get_bpp;
2212 s->get_offsets = vga_get_offsets;
a130a41e 2213 s->get_resolution = vga_get_resolution;
380cd056 2214 s->hw_ops = &vga_ops;
cb5a7aa8 2215 switch (vga_retrace_method) {
2216 case VGA_RETRACE_DUMB:
2217 s->retrace = vga_dumb_retrace;
2218 s->update_retrace_info = vga_dumb_update_retrace_info;
2219 break;
2220
2221 case VGA_RETRACE_PRECISE:
2222 s->retrace = vga_precise_retrace;
2223 s->update_retrace_info = vga_precise_update_retrace_info;
cb5a7aa8 2224 break;
2225 }
2c7d8736
BH
2226
2227 /*
c3b10605 2228 * Set default fb endian based on target, could probably be turned
2c7d8736
BH
2229 * into a device attribute set by the machine/platform to remove
2230 * all target endian dependencies from this file.
2231 */
2232#ifdef TARGET_WORDS_BIGENDIAN
c3b10605 2233 s->default_endian_fb = true;
2c7d8736 2234#else
c3b10605 2235 s->default_endian_fb = false;
2c7d8736 2236#endif
b1950430 2237 vga_dirty_log_start(s);
798b0c25
FB
2238}
2239
0a039dc7
RH
2240static const MemoryRegionPortio vga_portio_list[] = {
2241 { 0x04, 2, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3b4 */
2242 { 0x0a, 1, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3ba */
2243 { 0x10, 16, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3c0 */
2244 { 0x24, 2, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3d4 */
2245 { 0x2a, 1, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3da */
2246 PORTIO_END_OF_LIST(),
2247};
e89f66ec 2248
0a039dc7
RH
2249static const MemoryRegionPortio vbe_portio_list[] = {
2250 { 0, 1, 2, .read = vbe_ioport_read_index, .write = vbe_ioport_write_index },
2251# ifdef TARGET_I386
2252 { 1, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data },
0a039dc7 2253# endif
df9ffb72 2254 { 2, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data },
0a039dc7
RH
2255 PORTIO_END_OF_LIST(),
2256};
4fa0f5d2 2257
0a039dc7 2258/* Used by both ISA and PCI */
c84b28ee 2259MemoryRegion *vga_init_io(VGACommonState *s, Object *obj,
0a039dc7
RH
2260 const MemoryRegionPortio **vga_ports,
2261 const MemoryRegionPortio **vbe_ports)
2262{
2263 MemoryRegion *vga_mem;
09a79b49 2264
0a039dc7 2265 *vga_ports = vga_portio_list;
0a039dc7 2266 *vbe_ports = vbe_portio_list;
4fa0f5d2 2267
7267c094 2268 vga_mem = g_malloc(sizeof(*vga_mem));
c84b28ee 2269 memory_region_init_io(vga_mem, obj, &vga_mem_ops, s,
b1950430 2270 "vga-lowmem", 0x20000);
bd8f2f5d 2271 memory_region_set_flush_coalesced(vga_mem);
b1950430
AK
2272
2273 return vga_mem;
7435b791
BS
2274}
2275
712f0cc7 2276void vga_init(VGACommonState *s, Object *obj, MemoryRegion *address_space,
0a039dc7 2277 MemoryRegion *address_space_io, bool init_vga_ports)
7435b791 2278{
b1950430 2279 MemoryRegion *vga_io_memory;
0a039dc7 2280 const MemoryRegionPortio *vga_ports, *vbe_ports;
7435b791
BS
2281
2282 qemu_register_reset(vga_reset, s);
2283
2284 s->bank_offset = 0;
2285
80763888
JK
2286 s->legacy_address_space = address_space;
2287
c84b28ee 2288 vga_io_memory = vga_init_io(s, obj, &vga_ports, &vbe_ports);
be20f9e9 2289 memory_region_add_subregion_overlap(address_space,
b19c1c08 2290 0x000a0000,
b1950430
AK
2291 vga_io_memory,
2292 1);
2293 memory_region_set_coalescing(vga_io_memory);
0a039dc7 2294 if (init_vga_ports) {
848696bf
KB
2295 portio_list_init(&s->vga_port_list, obj, vga_ports, s, "vga");
2296 portio_list_set_flush_coalesced(&s->vga_port_list);
2297 portio_list_add(&s->vga_port_list, address_space_io, 0x3b0);
0a039dc7
RH
2298 }
2299 if (vbe_ports) {
848696bf
KB
2300 portio_list_init(&s->vbe_port_list, obj, vbe_ports, s, "vbe");
2301 portio_list_add(&s->vbe_port_list, address_space_io, 0x1ce);
0a039dc7 2302 }
d2269f6f
FB
2303}
2304
83118327 2305void vga_init_vbe(VGACommonState *s, Object *obj, MemoryRegion *system_memory)
f0138a63 2306{
8294a64d
AK
2307 /* With pc-0.12 and below we map both the PCI BAR and the fixed VBE region,
2308 * so use an alias to avoid double-mapping the same region.
2309 */
83118327 2310 memory_region_init_alias(&s->vram_vbe, obj, "vram.vbe",
8294a64d 2311 &s->vram, 0, memory_region_size(&s->vram));
f0138a63 2312 /* XXX: use optimized standard vga accesses */
be20f9e9 2313 memory_region_add_subregion(system_memory,
b1950430 2314 VBE_DISPI_LFB_PHYSICAL_ADDRESS,
8294a64d 2315 &s->vram_vbe);
f0138a63 2316 s->vbe_mapped = 1;
f0138a63 2317}