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