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