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