]> git.proxmox.com Git - mirror_qemu.git/blame - hw/display/vga.c
vga: factor out vga register setup
[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);
4fa0f5d2
FB
766 break;
767 case VBE_DISPI_INDEX_BANK:
3bf18170 768 val &= s->vbe_bank_mask;
cae61cef 769 s->vbe_regs[s->vbe_index] = val;
26aa7d72 770 s->bank_offset = (val << 16);
80763888 771 vga_update_memory_access(s);
4fa0f5d2
FB
772 break;
773 case VBE_DISPI_INDEX_ENABLE:
8454df8b
FB
774 if ((val & VBE_DISPI_ENABLED) &&
775 !(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
4fa0f5d2 776
c1b886c4 777 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = 0;
4fa0f5d2
FB
778 s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
779 s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
c1b886c4
GH
780 s->vbe_regs[VBE_DISPI_INDEX_ENABLE] |= VBE_DISPI_ENABLED;
781 vbe_fixup_regs(s);
7fa5c2c5 782 vbe_update_vgaregs(s);
8454df8b 783
ace89b8f 784 /* clear the screen */
4fa0f5d2 785 if (!(val & VBE_DISPI_NOCLEARMEM)) {
5fafdf24 786 memset(s->vram_ptr, 0,
4fa0f5d2
FB
787 s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
788 }
cae61cef 789 } else {
26aa7d72 790 s->bank_offset = 0;
cae61cef 791 }
37dd208d 792 s->dac_8bit = (val & VBE_DISPI_8BIT_DAC) > 0;
141253b2 793 s->vbe_regs[s->vbe_index] = val;
80763888 794 vga_update_memory_access(s);
cae61cef 795 break;
4fa0f5d2
FB
796 default:
797 break;
798 }
4fa0f5d2
FB
799 }
800}
4fa0f5d2 801
e89f66ec 802/* called for accesses between 0xa0000 and 0xc0000 */
a8170e5e 803uint32_t vga_mem_readb(VGACommonState *s, hwaddr addr)
e89f66ec 804{
e89f66ec
FB
805 int memory_map_mode, plane;
806 uint32_t ret;
3b46e624 807
e89f66ec 808 /* convert to VGA memory offset */
5e55efc9 809 memory_map_mode = (s->gr[VGA_GFX_MISC] >> 2) & 3;
26aa7d72 810 addr &= 0x1ffff;
e89f66ec
FB
811 switch(memory_map_mode) {
812 case 0:
e89f66ec
FB
813 break;
814 case 1:
26aa7d72 815 if (addr >= 0x10000)
e89f66ec 816 return 0xff;
cae61cef 817 addr += s->bank_offset;
e89f66ec
FB
818 break;
819 case 2:
26aa7d72 820 addr -= 0x10000;
e89f66ec
FB
821 if (addr >= 0x8000)
822 return 0xff;
823 break;
824 default:
825 case 3:
26aa7d72 826 addr -= 0x18000;
c92b2e84
FB
827 if (addr >= 0x8000)
828 return 0xff;
e89f66ec
FB
829 break;
830 }
3b46e624 831
5e55efc9 832 if (s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
e89f66ec 833 /* chain 4 mode : simplest access */
3bf18170 834 assert(addr < s->vram_size);
e89f66ec 835 ret = s->vram_ptr[addr];
5e55efc9 836 } else if (s->gr[VGA_GFX_MODE] & 0x10) {
e89f66ec 837 /* odd/even mode (aka text mode mapping) */
5e55efc9 838 plane = (s->gr[VGA_GFX_PLANE_READ] & 2) | (addr & 1);
3bf18170
GH
839 addr = ((addr & ~1) << 1) | plane;
840 if (addr >= s->vram_size) {
841 return 0xff;
842 }
843 ret = s->vram_ptr[addr];
e89f66ec
FB
844 } else {
845 /* standard VGA latched access */
3bf18170
GH
846 if (addr * sizeof(uint32_t) >= s->vram_size) {
847 return 0xff;
848 }
e89f66ec
FB
849 s->latch = ((uint32_t *)s->vram_ptr)[addr];
850
5e55efc9 851 if (!(s->gr[VGA_GFX_MODE] & 0x08)) {
e89f66ec 852 /* read mode 0 */
5e55efc9 853 plane = s->gr[VGA_GFX_PLANE_READ];
b8ed223b 854 ret = GET_PLANE(s->latch, plane);
e89f66ec
FB
855 } else {
856 /* read mode 1 */
5e55efc9
BS
857 ret = (s->latch ^ mask16[s->gr[VGA_GFX_COMPARE_VALUE]]) &
858 mask16[s->gr[VGA_GFX_COMPARE_MASK]];
e89f66ec
FB
859 ret |= ret >> 16;
860 ret |= ret >> 8;
861 ret = (~ret) & 0xff;
862 }
863 }
864 return ret;
865}
866
e89f66ec 867/* called for accesses between 0xa0000 and 0xc0000 */
a8170e5e 868void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
e89f66ec 869{
546fa6ab 870 int memory_map_mode, plane, write_mode, b, func_select, mask;
e89f66ec
FB
871 uint32_t write_mask, bit_mask, set_mask;
872
17b0018b 873#ifdef DEBUG_VGA_MEM
0bf9e31a 874 printf("vga: [0x" TARGET_FMT_plx "] = 0x%02x\n", addr, val);
e89f66ec
FB
875#endif
876 /* convert to VGA memory offset */
5e55efc9 877 memory_map_mode = (s->gr[VGA_GFX_MISC] >> 2) & 3;
26aa7d72 878 addr &= 0x1ffff;
e89f66ec
FB
879 switch(memory_map_mode) {
880 case 0:
e89f66ec
FB
881 break;
882 case 1:
26aa7d72 883 if (addr >= 0x10000)
e89f66ec 884 return;
cae61cef 885 addr += s->bank_offset;
e89f66ec
FB
886 break;
887 case 2:
26aa7d72 888 addr -= 0x10000;
e89f66ec
FB
889 if (addr >= 0x8000)
890 return;
891 break;
892 default:
893 case 3:
26aa7d72 894 addr -= 0x18000;
c92b2e84
FB
895 if (addr >= 0x8000)
896 return;
e89f66ec
FB
897 break;
898 }
3b46e624 899
5e55efc9 900 if (s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
e89f66ec
FB
901 /* chain 4 mode : simplest access */
902 plane = addr & 3;
546fa6ab 903 mask = (1 << plane);
5e55efc9 904 if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
3bf18170 905 assert(addr < s->vram_size);
e89f66ec 906 s->vram_ptr[addr] = val;
17b0018b 907#ifdef DEBUG_VGA_MEM
0bf9e31a 908 printf("vga: chain4: [0x" TARGET_FMT_plx "]\n", addr);
e89f66ec 909#endif
546fa6ab 910 s->plane_updated |= mask; /* only used to detect font change */
fd4aa979 911 memory_region_set_dirty(&s->vram, addr, 1);
e89f66ec 912 }
5e55efc9 913 } else if (s->gr[VGA_GFX_MODE] & 0x10) {
e89f66ec 914 /* odd/even mode (aka text mode mapping) */
5e55efc9 915 plane = (s->gr[VGA_GFX_PLANE_READ] & 2) | (addr & 1);
546fa6ab 916 mask = (1 << plane);
5e55efc9 917 if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
e89f66ec 918 addr = ((addr & ~1) << 1) | plane;
3bf18170
GH
919 if (addr >= s->vram_size) {
920 return;
921 }
e89f66ec 922 s->vram_ptr[addr] = val;
17b0018b 923#ifdef DEBUG_VGA_MEM
0bf9e31a 924 printf("vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr);
e89f66ec 925#endif
546fa6ab 926 s->plane_updated |= mask; /* only used to detect font change */
fd4aa979 927 memory_region_set_dirty(&s->vram, addr, 1);
e89f66ec
FB
928 }
929 } else {
930 /* standard VGA latched access */
5e55efc9 931 write_mode = s->gr[VGA_GFX_MODE] & 3;
e89f66ec
FB
932 switch(write_mode) {
933 default:
934 case 0:
935 /* rotate */
5e55efc9 936 b = s->gr[VGA_GFX_DATA_ROTATE] & 7;
e89f66ec
FB
937 val = ((val >> b) | (val << (8 - b))) & 0xff;
938 val |= val << 8;
939 val |= val << 16;
940
941 /* apply set/reset mask */
5e55efc9
BS
942 set_mask = mask16[s->gr[VGA_GFX_SR_ENABLE]];
943 val = (val & ~set_mask) |
944 (mask16[s->gr[VGA_GFX_SR_VALUE]] & set_mask);
945 bit_mask = s->gr[VGA_GFX_BIT_MASK];
e89f66ec
FB
946 break;
947 case 1:
948 val = s->latch;
949 goto do_write;
950 case 2:
951 val = mask16[val & 0x0f];
5e55efc9 952 bit_mask = s->gr[VGA_GFX_BIT_MASK];
e89f66ec
FB
953 break;
954 case 3:
955 /* rotate */
5e55efc9 956 b = s->gr[VGA_GFX_DATA_ROTATE] & 7;
a41bc9af 957 val = (val >> b) | (val << (8 - b));
e89f66ec 958
5e55efc9
BS
959 bit_mask = s->gr[VGA_GFX_BIT_MASK] & val;
960 val = mask16[s->gr[VGA_GFX_SR_VALUE]];
e89f66ec
FB
961 break;
962 }
963
964 /* apply logical operation */
5e55efc9 965 func_select = s->gr[VGA_GFX_DATA_ROTATE] >> 3;
e89f66ec
FB
966 switch(func_select) {
967 case 0:
968 default:
969 /* nothing to do */
970 break;
971 case 1:
972 /* and */
973 val &= s->latch;
974 break;
975 case 2:
976 /* or */
977 val |= s->latch;
978 break;
979 case 3:
980 /* xor */
981 val ^= s->latch;
982 break;
983 }
984
985 /* apply bit mask */
986 bit_mask |= bit_mask << 8;
987 bit_mask |= bit_mask << 16;
988 val = (val & bit_mask) | (s->latch & ~bit_mask);
989
990 do_write:
991 /* mask data according to sr[2] */
5e55efc9 992 mask = s->sr[VGA_SEQ_PLANE_WRITE];
546fa6ab
FB
993 s->plane_updated |= mask; /* only used to detect font change */
994 write_mask = mask16[mask];
3bf18170
GH
995 if (addr * sizeof(uint32_t) >= s->vram_size) {
996 return;
997 }
5fafdf24
TS
998 ((uint32_t *)s->vram_ptr)[addr] =
999 (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
e89f66ec 1000 (val & write_mask);
17b0018b 1001#ifdef DEBUG_VGA_MEM
0bf9e31a
BS
1002 printf("vga: latch: [0x" TARGET_FMT_plx "] mask=0x%08x val=0x%08x\n",
1003 addr * 4, write_mask, val);
e89f66ec 1004#endif
fd4aa979 1005 memory_region_set_dirty(&s->vram, addr << 2, sizeof(uint32_t));
e89f66ec
FB
1006 }
1007}
1008
cedd91d2 1009typedef void vga_draw_line_func(VGACommonState *s1, uint8_t *d,
e89f66ec
FB
1010 const uint8_t *s, int width);
1011
e657d8ef 1012#include "vga-helpers.h"
e89f66ec 1013
e89f66ec 1014/* return true if the palette was modified */
cedd91d2 1015static int update_palette16(VGACommonState *s)
e89f66ec 1016{
17b0018b 1017 int full_update, i;
e89f66ec 1018 uint32_t v, col, *palette;
e89f66ec
FB
1019
1020 full_update = 0;
1021 palette = s->last_palette;
1022 for(i = 0; i < 16; i++) {
1023 v = s->ar[i];
5e55efc9
BS
1024 if (s->ar[VGA_ATC_MODE] & 0x80) {
1025 v = ((s->ar[VGA_ATC_COLOR_PAGE] & 0xf) << 4) | (v & 0xf);
1026 } else {
1027 v = ((s->ar[VGA_ATC_COLOR_PAGE] & 0xc) << 4) | (v & 0x3f);
1028 }
e89f66ec 1029 v = v * 3;
d3c2343a
BH
1030 col = rgb_to_pixel32(c6_to_8(s->palette[v]),
1031 c6_to_8(s->palette[v + 1]),
1032 c6_to_8(s->palette[v + 2]));
17b0018b
FB
1033 if (col != palette[i]) {
1034 full_update = 1;
1035 palette[i] = col;
e89f66ec 1036 }
17b0018b
FB
1037 }
1038 return full_update;
1039}
1040
1041/* return true if the palette was modified */
cedd91d2 1042static int update_palette256(VGACommonState *s)
17b0018b
FB
1043{
1044 int full_update, i;
1045 uint32_t v, col, *palette;
1046
1047 full_update = 0;
1048 palette = s->last_palette;
1049 v = 0;
1050 for(i = 0; i < 256; i++) {
37dd208d 1051 if (s->dac_8bit) {
d3c2343a
BH
1052 col = rgb_to_pixel32(s->palette[v],
1053 s->palette[v + 1],
1054 s->palette[v + 2]);
37dd208d 1055 } else {
d3c2343a
BH
1056 col = rgb_to_pixel32(c6_to_8(s->palette[v]),
1057 c6_to_8(s->palette[v + 1]),
1058 c6_to_8(s->palette[v + 2]));
37dd208d 1059 }
e89f66ec
FB
1060 if (col != palette[i]) {
1061 full_update = 1;
1062 palette[i] = col;
1063 }
17b0018b 1064 v += 3;
e89f66ec
FB
1065 }
1066 return full_update;
1067}
1068
cedd91d2 1069static void vga_get_offsets(VGACommonState *s,
5fafdf24 1070 uint32_t *pline_offset,
83acc96b
FB
1071 uint32_t *pstart_addr,
1072 uint32_t *pline_compare)
e89f66ec 1073{
83acc96b 1074 uint32_t start_addr, line_offset, line_compare;
a96d8bea 1075
bfa0f151 1076 if (vbe_enabled(s)) {
4fa0f5d2
FB
1077 line_offset = s->vbe_line_offset;
1078 start_addr = s->vbe_start_addr;
83acc96b 1079 line_compare = 65535;
a96d8bea 1080 } else {
4fa0f5d2 1081 /* compute line_offset in bytes */
5e55efc9 1082 line_offset = s->cr[VGA_CRTC_OFFSET];
4fa0f5d2 1083 line_offset <<= 3;
08e48902 1084
4fa0f5d2 1085 /* starting address */
5e55efc9
BS
1086 start_addr = s->cr[VGA_CRTC_START_LO] |
1087 (s->cr[VGA_CRTC_START_HI] << 8);
83acc96b
FB
1088
1089 /* line compare */
5e55efc9
BS
1090 line_compare = s->cr[VGA_CRTC_LINE_COMPARE] |
1091 ((s->cr[VGA_CRTC_OVERFLOW] & 0x10) << 4) |
1092 ((s->cr[VGA_CRTC_MAX_SCAN] & 0x40) << 3);
4fa0f5d2 1093 }
798b0c25
FB
1094 *pline_offset = line_offset;
1095 *pstart_addr = start_addr;
83acc96b 1096 *pline_compare = line_compare;
798b0c25
FB
1097}
1098
1099/* update start_addr and line_offset. Return TRUE if modified */
cedd91d2 1100static int update_basic_params(VGACommonState *s)
798b0c25
FB
1101{
1102 int full_update;
1103 uint32_t start_addr, line_offset, line_compare;
3b46e624 1104
798b0c25
FB
1105 full_update = 0;
1106
83acc96b 1107 s->get_offsets(s, &line_offset, &start_addr, &line_compare);
e89f66ec
FB
1108
1109 if (line_offset != s->line_offset ||
1110 start_addr != s->start_addr ||
1111 line_compare != s->line_compare) {
1112 s->line_offset = line_offset;
1113 s->start_addr = start_addr;
1114 s->line_compare = line_compare;
1115 full_update = 1;
1116 }
1117 return full_update;
1118}
1119
3b46e624 1120
e89f66ec
FB
1121static const uint8_t cursor_glyph[32 * 4] = {
1122 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1123 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1124 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1125 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1126 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1127 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1128 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1129 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1130 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1131 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1132 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1133 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1134 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1135 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1136 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1137 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
3b46e624 1138};
e89f66ec 1139
cedd91d2 1140static void vga_get_text_resolution(VGACommonState *s, int *pwidth, int *pheight,
4c5e8c5c
BS
1141 int *pcwidth, int *pcheight)
1142{
1143 int width, cwidth, height, cheight;
1144
1145 /* total width & height */
5e55efc9 1146 cheight = (s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1;
4c5e8c5c 1147 cwidth = 8;
5e55efc9 1148 if (!(s->sr[VGA_SEQ_CLOCK_MODE] & VGA_SR01_CHAR_CLK_8DOTS)) {
4c5e8c5c 1149 cwidth = 9;
5e55efc9
BS
1150 }
1151 if (s->sr[VGA_SEQ_CLOCK_MODE] & 0x08) {
4c5e8c5c 1152 cwidth = 16; /* NOTE: no 18 pixel wide */
5e55efc9
BS
1153 }
1154 width = (s->cr[VGA_CRTC_H_DISP] + 1);
1155 if (s->cr[VGA_CRTC_V_TOTAL] == 100) {
4c5e8c5c
BS
1156 /* ugly hack for CGA 160x100x16 - explain me the logic */
1157 height = 100;
1158 } else {
5e55efc9
BS
1159 height = s->cr[VGA_CRTC_V_DISP_END] |
1160 ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) |
1161 ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3);
4c5e8c5c
BS
1162 height = (height + 1) / cheight;
1163 }
1164
1165 *pwidth = width;
1166 *pheight = height;
1167 *pcwidth = cwidth;
1168 *pcheight = cheight;
1169}
1170
5fafdf24
TS
1171/*
1172 * Text mode update
e89f66ec
FB
1173 * Missing:
1174 * - double scan
5fafdf24 1175 * - double width
e89f66ec
FB
1176 * - underline
1177 * - flashing
1178 */
cedd91d2 1179static void vga_draw_text(VGACommonState *s, int full_update)
e89f66ec 1180{
c78f7137 1181 DisplaySurface *surface = qemu_console_surface(s->con);
e89f66ec 1182 int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
cae334cd 1183 int cx_min, cx_max, linesize, x_incr, line, line1;
e89f66ec 1184 uint32_t offset, fgcol, bgcol, v, cursor_offset;
d1984194 1185 uint8_t *d1, *d, *src, *dest, *cursor_ptr;
e89f66ec 1186 const uint8_t *font_ptr, *font_base[2];
9e057c0b 1187 int dup9, line_offset;
e89f66ec
FB
1188 uint32_t *palette;
1189 uint32_t *ch_attr_ptr;
bc72ad67 1190 int64_t now = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
e89f66ec 1191
e89f66ec 1192 /* compute font data address (in plane 2) */
5e55efc9 1193 v = s->sr[VGA_SEQ_CHARACTER_MAP];
1078f663 1194 offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
e89f66ec
FB
1195 if (offset != s->font_offsets[0]) {
1196 s->font_offsets[0] = offset;
1197 full_update = 1;
1198 }
1199 font_base[0] = s->vram_ptr + offset;
1200
1078f663 1201 offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
e89f66ec
FB
1202 font_base[1] = s->vram_ptr + offset;
1203 if (offset != s->font_offsets[1]) {
1204 s->font_offsets[1] = offset;
1205 full_update = 1;
1206 }
ad37168c 1207 if (s->plane_updated & (1 << 2) || s->has_chain4_alias) {
546fa6ab
FB
1208 /* if the plane 2 was modified since the last display, it
1209 indicates the font may have been modified */
1210 s->plane_updated = 0;
1211 full_update = 1;
1212 }
799e709b 1213 full_update |= update_basic_params(s);
e89f66ec
FB
1214
1215 line_offset = s->line_offset;
e89f66ec 1216
4c5e8c5c 1217 vga_get_text_resolution(s, &width, &height, &cw, &cheight);
1b296044
SW
1218 if ((height * width) <= 1) {
1219 /* better than nothing: exit if transient size is too small */
1220 return;
1221 }
3294b949
FB
1222 if ((height * width) > CH_ATTR_SIZE) {
1223 /* better than nothing: exit if transient size is too big */
1224 return;
1225 }
1226
799e709b
AL
1227 if (width != s->last_width || height != s->last_height ||
1228 cw != s->last_cw || cheight != s->last_ch || s->last_depth) {
1229 s->last_scr_width = width * cw;
1230 s->last_scr_height = height * cheight;
c78f7137
GH
1231 qemu_console_resize(s->con, s->last_scr_width, s->last_scr_height);
1232 surface = qemu_console_surface(s->con);
1233 dpy_text_resize(s->con, width, height);
799e709b
AL
1234 s->last_depth = 0;
1235 s->last_width = width;
1236 s->last_height = height;
1237 s->last_ch = cheight;
1238 s->last_cw = cw;
1239 full_update = 1;
1240 }
7d957bd8
AL
1241 full_update |= update_palette16(s);
1242 palette = s->last_palette;
c78f7137 1243 x_incr = cw * surface_bytes_per_pixel(surface);
7d957bd8 1244
9678aedd
GH
1245 if (full_update) {
1246 s->full_update_text = 1;
1247 }
1248 if (s->full_update_gfx) {
1249 s->full_update_gfx = 0;
1250 full_update |= 1;
1251 }
1252
5e55efc9
BS
1253 cursor_offset = ((s->cr[VGA_CRTC_CURSOR_HI] << 8) |
1254 s->cr[VGA_CRTC_CURSOR_LO]) - s->start_addr;
e89f66ec 1255 if (cursor_offset != s->cursor_offset ||
5e55efc9
BS
1256 s->cr[VGA_CRTC_CURSOR_START] != s->cursor_start ||
1257 s->cr[VGA_CRTC_CURSOR_END] != s->cursor_end) {
e89f66ec
FB
1258 /* if the cursor position changed, we update the old and new
1259 chars */
1260 if (s->cursor_offset < CH_ATTR_SIZE)
1261 s->last_ch_attr[s->cursor_offset] = -1;
1262 if (cursor_offset < CH_ATTR_SIZE)
1263 s->last_ch_attr[cursor_offset] = -1;
1264 s->cursor_offset = cursor_offset;
5e55efc9
BS
1265 s->cursor_start = s->cr[VGA_CRTC_CURSOR_START];
1266 s->cursor_end = s->cr[VGA_CRTC_CURSOR_END];
e89f66ec 1267 }
39cf7803 1268 cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
9aa0ff0b
JK
1269 if (now >= s->cursor_blink_time) {
1270 s->cursor_blink_time = now + VGA_TEXT_CURSOR_PERIOD_MS / 2;
1271 s->cursor_visible_phase = !s->cursor_visible_phase;
1272 }
3b46e624 1273
c78f7137
GH
1274 dest = surface_data(surface);
1275 linesize = surface_stride(surface);
e89f66ec 1276 ch_attr_ptr = s->last_ch_attr;
d1984194 1277 line = 0;
1278 offset = s->start_addr * 4;
e89f66ec
FB
1279 for(cy = 0; cy < height; cy++) {
1280 d1 = dest;
d1984194 1281 src = s->vram_ptr + offset;
e89f66ec
FB
1282 cx_min = width;
1283 cx_max = -1;
1284 for(cx = 0; cx < width; cx++) {
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
b51d7b2e 1439void vga_sync_dirty_bitmap(VGACommonState *s)
2bec46dc 1440{
b1950430 1441 memory_region_sync_dirty_bitmap(&s->vram);
2bec46dc
AL
1442}
1443
50af3246
JQ
1444void vga_dirty_log_start(VGACommonState *s)
1445{
b1950430 1446 memory_region_set_log(&s->vram, true, DIRTY_MEMORY_VGA);
b5cc6e32
AL
1447}
1448
1449void vga_dirty_log_stop(VGACommonState *s)
1450{
b1950430 1451 memory_region_set_log(&s->vram, false, DIRTY_MEMORY_VGA);
b5cc6e32
AL
1452}
1453
799e709b
AL
1454/*
1455 * graphic modes
1456 */
cedd91d2 1457static void vga_draw_graphic(VGACommonState *s, int full_update)
e89f66ec 1458{
c78f7137 1459 DisplaySurface *surface = qemu_console_surface(s->con);
12c7e75a
AK
1460 int y1, y, update, linesize, y_start, double_scan, mask, depth;
1461 int width, height, shift_control, line_offset, bwidth, bits;
c227f099 1462 ram_addr_t page0, page1, page_min, page_max;
a07cf92a 1463 int disp_width, multi_scan, multi_run;
799e709b
AL
1464 uint8_t *d;
1465 uint32_t v, addr1, addr;
2c7d8736 1466 vga_draw_line_func *vga_draw_line = NULL;
55080993 1467 bool share_surface;
49743df3 1468 pixman_format_code_t format;
2c7d8736
BH
1469#ifdef HOST_WORDS_BIGENDIAN
1470 bool byteswap = !s->big_endian_fb;
46c3a8c8 1471#else
2c7d8736 1472 bool byteswap = s->big_endian_fb;
b1424e03 1473#endif
799e709b
AL
1474
1475 full_update |= update_basic_params(s);
1476
1477 if (!full_update)
1478 vga_sync_dirty_bitmap(s);
2bec46dc 1479
a130a41e 1480 s->get_resolution(s, &width, &height);
17b0018b 1481 disp_width = width;
09a79b49 1482
5e55efc9
BS
1483 shift_control = (s->gr[VGA_GFX_MODE] >> 5) & 3;
1484 double_scan = (s->cr[VGA_CRTC_MAX_SCAN] >> 7);
799e709b 1485 if (shift_control != 1) {
5e55efc9
BS
1486 multi_scan = (((s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1) << double_scan)
1487 - 1;
799e709b
AL
1488 } else {
1489 /* in CGA modes, multi_scan is ignored */
1490 /* XXX: is it correct ? */
1491 multi_scan = double_scan;
1492 }
1493 multi_run = multi_scan;
17b0018b
FB
1494 if (shift_control != s->shift_control ||
1495 double_scan != s->double_scan) {
799e709b 1496 full_update = 1;
e89f66ec 1497 s->shift_control = shift_control;
17b0018b 1498 s->double_scan = double_scan;
e89f66ec 1499 }
3b46e624 1500
aba35a6c 1501 if (shift_control == 0) {
5e55efc9 1502 if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
aba35a6c 1503 disp_width <<= 1;
1504 }
1505 } else if (shift_control == 1) {
5e55efc9 1506 if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
aba35a6c 1507 disp_width <<= 1;
1508 }
1509 }
1510
799e709b 1511 depth = s->get_bpp(s);
55080993 1512
49743df3
BH
1513 /*
1514 * Check whether we can share the surface with the backend
1515 * or whether we need a shadow surface. We share native
1516 * endian surfaces for 15bpp and above and byteswapped
1517 * surfaces for 24bpp and above.
1518 */
1519 format = qemu_default_pixman_format(depth, !byteswap);
1520 if (format) {
1521 share_surface = dpy_gfx_check_format(s->con, format)
1522 && !s->force_shadow;
1523 } else {
1524 share_surface = false;
1525 }
e3697092
AJ
1526 if (s->line_offset != s->last_line_offset ||
1527 disp_width != s->last_width ||
1528 height != s->last_height ||
c3b10605 1529 s->last_depth != depth ||
55080993
BH
1530 s->last_byteswap != byteswap ||
1531 share_surface != is_buffer_shared(surface)) {
1532 if (share_surface) {
da229ef3 1533 surface = qemu_create_displaysurface_from(disp_width,
30f1e661
GH
1534 height, format, s->line_offset,
1535 s->vram_ptr + (s->start_addr * 4));
c78f7137 1536 dpy_gfx_replace_surface(s->con, surface);
55080993
BH
1537#ifdef DEBUG_VGA
1538 printf("VGA: Using shared surface for depth=%d swap=%d\n",
1539 depth, byteswap);
1540#endif
e3697092 1541 } else {
c78f7137
GH
1542 qemu_console_resize(s->con, disp_width, height);
1543 surface = qemu_console_surface(s->con);
55080993
BH
1544#ifdef DEBUG_VGA
1545 printf("VGA: Using shadow surface for depth=%d swap=%d\n",
1546 depth, byteswap);
1547#endif
e3697092
AJ
1548 }
1549 s->last_scr_width = disp_width;
1550 s->last_scr_height = height;
1551 s->last_width = disp_width;
1552 s->last_height = height;
1553 s->last_line_offset = s->line_offset;
1554 s->last_depth = depth;
c3b10605 1555 s->last_byteswap = byteswap;
799e709b 1556 full_update = 1;
c78f7137
GH
1557 } else if (is_buffer_shared(surface) &&
1558 (full_update || surface_data(surface) != s->vram_ptr
1fd2510a 1559 + (s->start_addr * 4))) {
30f1e661
GH
1560 pixman_format_code_t format =
1561 qemu_default_pixman_format(depth, !byteswap);
da229ef3 1562 surface = qemu_create_displaysurface_from(disp_width,
30f1e661
GH
1563 height, format, s->line_offset,
1564 s->vram_ptr + (s->start_addr * 4));
c78f7137 1565 dpy_gfx_replace_surface(s->con, surface);
e3697092
AJ
1566 }
1567
799e709b 1568 if (shift_control == 0) {
17b0018b 1569 full_update |= update_palette16(s);
5e55efc9 1570 if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
17b0018b 1571 v = VGA_DRAW_LINE4D2;
17b0018b
FB
1572 } else {
1573 v = VGA_DRAW_LINE4;
1574 }
15342721 1575 bits = 4;
799e709b 1576 } else if (shift_control == 1) {
17b0018b 1577 full_update |= update_palette16(s);
5e55efc9 1578 if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
17b0018b 1579 v = VGA_DRAW_LINE2D2;
17b0018b
FB
1580 } else {
1581 v = VGA_DRAW_LINE2;
1582 }
15342721 1583 bits = 4;
17b0018b 1584 } else {
798b0c25
FB
1585 switch(s->get_bpp(s)) {
1586 default:
1587 case 0:
4fa0f5d2
FB
1588 full_update |= update_palette256(s);
1589 v = VGA_DRAW_LINE8D2;
15342721 1590 bits = 4;
798b0c25
FB
1591 break;
1592 case 8:
1593 full_update |= update_palette256(s);
1594 v = VGA_DRAW_LINE8;
15342721 1595 bits = 8;
798b0c25
FB
1596 break;
1597 case 15:
2c7d8736 1598 v = s->big_endian_fb ? VGA_DRAW_LINE15_BE : VGA_DRAW_LINE15_LE;
15342721 1599 bits = 16;
798b0c25
FB
1600 break;
1601 case 16:
2c7d8736 1602 v = s->big_endian_fb ? VGA_DRAW_LINE16_BE : VGA_DRAW_LINE16_LE;
15342721 1603 bits = 16;
798b0c25
FB
1604 break;
1605 case 24:
2c7d8736 1606 v = s->big_endian_fb ? VGA_DRAW_LINE24_BE : VGA_DRAW_LINE24_LE;
15342721 1607 bits = 24;
798b0c25
FB
1608 break;
1609 case 32:
2c7d8736 1610 v = s->big_endian_fb ? VGA_DRAW_LINE32_BE : VGA_DRAW_LINE32_LE;
15342721 1611 bits = 32;
798b0c25 1612 break;
4fa0f5d2 1613 }
17b0018b 1614 }
9e057c0b 1615 vga_draw_line = vga_draw_line_table[v];
17b0018b 1616
c78f7137 1617 if (!is_buffer_shared(surface) && s->cursor_invalidate) {
a8aa669b 1618 s->cursor_invalidate(s);
c78f7137 1619 }
3b46e624 1620
e89f66ec 1621 line_offset = s->line_offset;
17b0018b 1622#if 0
f6c958c8 1623 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
1624 width, height, v, line_offset, s->cr[9], s->cr[VGA_CRTC_MODE],
1625 s->line_compare, s->sr[VGA_SEQ_CLOCK_MODE]);
17b0018b 1626#endif
e89f66ec 1627 addr1 = (s->start_addr * 4);
15342721 1628 bwidth = (width * bits + 7) / 8;
39cf7803 1629 y_start = -1;
12c7e75a
AK
1630 page_min = -1;
1631 page_max = 0;
c78f7137
GH
1632 d = surface_data(surface);
1633 linesize = surface_stride(surface);
17b0018b 1634 y1 = 0;
e89f66ec
FB
1635 for(y = 0; y < height; y++) {
1636 addr = addr1;
5e55efc9 1637 if (!(s->cr[VGA_CRTC_MODE] & 1)) {
17b0018b 1638 int shift;
e89f66ec 1639 /* CGA compatibility handling */
5e55efc9 1640 shift = 14 + ((s->cr[VGA_CRTC_MODE] >> 6) & 1);
17b0018b 1641 addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
e89f66ec 1642 }
5e55efc9 1643 if (!(s->cr[VGA_CRTC_MODE] & 2)) {
17b0018b 1644 addr = (addr & ~0x8000) | ((y1 & 2) << 14);
e89f66ec 1645 }
734781c9 1646 update = full_update;
cd7a45c9
BS
1647 page0 = addr;
1648 page1 = addr + bwidth - 1;
734781c9
JK
1649 update |= memory_region_get_dirty(&s->vram, page0, page1 - page0,
1650 DIRTY_MEMORY_VGA);
a8aa669b
FB
1651 /* explicit invalidation for the hardware cursor */
1652 update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
e89f66ec 1653 if (update) {
39cf7803
FB
1654 if (y_start < 0)
1655 y_start = y;
e89f66ec
FB
1656 if (page0 < page_min)
1657 page_min = page0;
1658 if (page1 > page_max)
1659 page_max = page1;
c78f7137 1660 if (!(is_buffer_shared(surface))) {
7d957bd8
AL
1661 vga_draw_line(s, d, s->vram_ptr + addr, width);
1662 if (s->cursor_draw_line)
1663 s->cursor_draw_line(s, d, y);
1664 }
39cf7803
FB
1665 } else {
1666 if (y_start >= 0) {
1667 /* flush to display */
c78f7137 1668 dpy_gfx_update(s->con, 0, y_start,
a93a4a22 1669 disp_width, y - y_start);
39cf7803
FB
1670 y_start = -1;
1671 }
e89f66ec 1672 }
a07cf92a 1673 if (!multi_run) {
5e55efc9 1674 mask = (s->cr[VGA_CRTC_MODE] & 3) ^ 3;
f6c958c8
FB
1675 if ((y1 & mask) == mask)
1676 addr1 += line_offset;
1677 y1++;
799e709b 1678 multi_run = multi_scan;
a07cf92a
FB
1679 } else {
1680 multi_run--;
e89f66ec 1681 }
f6c958c8
FB
1682 /* line compare acts on the displayed lines */
1683 if (y == s->line_compare)
1684 addr1 = 0;
e89f66ec
FB
1685 d += linesize;
1686 }
39cf7803
FB
1687 if (y_start >= 0) {
1688 /* flush to display */
c78f7137 1689 dpy_gfx_update(s->con, 0, y_start,
a93a4a22 1690 disp_width, y - y_start);
39cf7803 1691 }
e89f66ec 1692 /* reset modified pages */
12c7e75a 1693 if (page_max >= page_min) {
b1950430
AK
1694 memory_region_reset_dirty(&s->vram,
1695 page_min,
cd7a45c9 1696 page_max - page_min,
b1950430 1697 DIRTY_MEMORY_VGA);
e89f66ec 1698 }
a8aa669b 1699 memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
e89f66ec
FB
1700}
1701
cedd91d2 1702static void vga_draw_blank(VGACommonState *s, int full_update)
2aebb3eb 1703{
c78f7137 1704 DisplaySurface *surface = qemu_console_surface(s->con);
2c79f2a2 1705 int i, w;
2aebb3eb
FB
1706 uint8_t *d;
1707
1708 if (!full_update)
1709 return;
1710 if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
1711 return;
2bec46dc 1712
c78f7137
GH
1713 w = s->last_scr_width * surface_bytes_per_pixel(surface);
1714 d = surface_data(surface);
2aebb3eb 1715 for(i = 0; i < s->last_scr_height; i++) {
2c79f2a2 1716 memset(d, 0, w);
c78f7137 1717 d += surface_stride(surface);
2aebb3eb 1718 }
c78f7137 1719 dpy_gfx_update(s->con, 0, 0,
a93a4a22 1720 s->last_scr_width, s->last_scr_height);
2aebb3eb
FB
1721}
1722
799e709b
AL
1723#define GMODE_TEXT 0
1724#define GMODE_GRAPH 1
1725#define GMODE_BLANK 2
1726
95219897 1727static void vga_update_display(void *opaque)
e89f66ec 1728{
cedd91d2 1729 VGACommonState *s = opaque;
c78f7137 1730 DisplaySurface *surface = qemu_console_surface(s->con);
799e709b 1731 int full_update, graphic_mode;
e89f66ec 1732
e9a07334
JK
1733 qemu_flush_coalesced_mmio_buffer();
1734
c78f7137 1735 if (surface_bits_per_pixel(surface) == 0) {
0f35920c 1736 /* nothing to do */
59a983b9 1737 } else {
3098b9fd 1738 full_update = 0;
df800210 1739 if (!(s->ar_index & 0x20)) {
799e709b
AL
1740 graphic_mode = GMODE_BLANK;
1741 } else {
5e55efc9 1742 graphic_mode = s->gr[VGA_GFX_MISC] & VGA_GR06_GRAPHICS_MODE;
799e709b
AL
1743 }
1744 if (graphic_mode != s->graphic_mode) {
1745 s->graphic_mode = graphic_mode;
bc72ad67 1746 s->cursor_blink_time = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
799e709b
AL
1747 full_update = 1;
1748 }
1749 switch(graphic_mode) {
2aebb3eb 1750 case GMODE_TEXT:
e89f66ec 1751 vga_draw_text(s, full_update);
2aebb3eb
FB
1752 break;
1753 case GMODE_GRAPH:
1754 vga_draw_graphic(s, full_update);
1755 break;
1756 case GMODE_BLANK:
1757 default:
1758 vga_draw_blank(s, full_update);
1759 break;
1760 }
e89f66ec
FB
1761 }
1762}
1763
a130a41e 1764/* force a full display refresh */
95219897 1765static void vga_invalidate_display(void *opaque)
a130a41e 1766{
cedd91d2 1767 VGACommonState *s = opaque;
3b46e624 1768
3098b9fd
AJ
1769 s->last_width = -1;
1770 s->last_height = -1;
a130a41e
FB
1771}
1772
03a3e7ba 1773void vga_common_reset(VGACommonState *s)
e89f66ec 1774{
6e6b7363
BS
1775 s->sr_index = 0;
1776 memset(s->sr, '\0', sizeof(s->sr));
1777 s->gr_index = 0;
1778 memset(s->gr, '\0', sizeof(s->gr));
1779 s->ar_index = 0;
1780 memset(s->ar, '\0', sizeof(s->ar));
1781 s->ar_flip_flop = 0;
1782 s->cr_index = 0;
1783 memset(s->cr, '\0', sizeof(s->cr));
1784 s->msr = 0;
1785 s->fcr = 0;
1786 s->st00 = 0;
1787 s->st01 = 0;
1788 s->dac_state = 0;
1789 s->dac_sub_index = 0;
1790 s->dac_read_index = 0;
1791 s->dac_write_index = 0;
1792 memset(s->dac_cache, '\0', sizeof(s->dac_cache));
1793 s->dac_8bit = 0;
1794 memset(s->palette, '\0', sizeof(s->palette));
1795 s->bank_offset = 0;
6e6b7363
BS
1796 s->vbe_index = 0;
1797 memset(s->vbe_regs, '\0', sizeof(s->vbe_regs));
af92284b 1798 s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID5;
6e6b7363
BS
1799 s->vbe_start_addr = 0;
1800 s->vbe_line_offset = 0;
1801 s->vbe_bank_mask = (s->vram_size >> 16) - 1;
6e6b7363 1802 memset(s->font_offsets, '\0', sizeof(s->font_offsets));
799e709b 1803 s->graphic_mode = -1; /* force full update */
6e6b7363
BS
1804 s->shift_control = 0;
1805 s->double_scan = 0;
1806 s->line_offset = 0;
1807 s->line_compare = 0;
1808 s->start_addr = 0;
1809 s->plane_updated = 0;
1810 s->last_cw = 0;
1811 s->last_ch = 0;
1812 s->last_width = 0;
1813 s->last_height = 0;
1814 s->last_scr_width = 0;
1815 s->last_scr_height = 0;
1816 s->cursor_start = 0;
1817 s->cursor_end = 0;
1818 s->cursor_offset = 0;
c3b10605 1819 s->big_endian_fb = s->default_endian_fb;
6e6b7363
BS
1820 memset(s->invalidated_y_table, '\0', sizeof(s->invalidated_y_table));
1821 memset(s->last_palette, '\0', sizeof(s->last_palette));
1822 memset(s->last_ch_attr, '\0', sizeof(s->last_ch_attr));
1823 switch (vga_retrace_method) {
1824 case VGA_RETRACE_DUMB:
1825 break;
1826 case VGA_RETRACE_PRECISE:
1827 memset(&s->retrace_info, 0, sizeof (s->retrace_info));
1828 break;
1829 }
80763888 1830 vga_update_memory_access(s);
e89f66ec
FB
1831}
1832
03a3e7ba
JQ
1833static void vga_reset(void *opaque)
1834{
cedd91d2 1835 VGACommonState *s = opaque;
03a3e7ba
JQ
1836 vga_common_reset(s);
1837}
1838
4d3b6f6e
AZ
1839#define TEXTMODE_X(x) ((x) % width)
1840#define TEXTMODE_Y(x) ((x) / width)
1841#define VMEM2CHTYPE(v) ((v & 0xff0007ff) | \
1842 ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1))
1843/* relay text rendering to the display driver
1844 * instead of doing a full vga_update_display() */
c227f099 1845static void vga_update_text(void *opaque, console_ch_t *chardata)
4d3b6f6e 1846{
cedd91d2 1847 VGACommonState *s = opaque;
799e709b 1848 int graphic_mode, i, cursor_offset, cursor_visible;
4d3b6f6e
AZ
1849 int cw, cheight, width, height, size, c_min, c_max;
1850 uint32_t *src;
c227f099 1851 console_ch_t *dst, val;
4d3b6f6e 1852 char msg_buffer[80];
799e709b
AL
1853 int full_update = 0;
1854
e9a07334
JK
1855 qemu_flush_coalesced_mmio_buffer();
1856
799e709b
AL
1857 if (!(s->ar_index & 0x20)) {
1858 graphic_mode = GMODE_BLANK;
1859 } else {
5e55efc9 1860 graphic_mode = s->gr[VGA_GFX_MISC] & VGA_GR06_GRAPHICS_MODE;
799e709b
AL
1861 }
1862 if (graphic_mode != s->graphic_mode) {
1863 s->graphic_mode = graphic_mode;
1864 full_update = 1;
1865 }
1866 if (s->last_width == -1) {
1867 s->last_width = 0;
1868 full_update = 1;
1869 }
4d3b6f6e 1870
799e709b 1871 switch (graphic_mode) {
4d3b6f6e
AZ
1872 case GMODE_TEXT:
1873 /* TODO: update palette */
799e709b 1874 full_update |= update_basic_params(s);
4d3b6f6e 1875
799e709b 1876 /* total width & height */
5e55efc9 1877 cheight = (s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1;
799e709b 1878 cw = 8;
5e55efc9 1879 if (!(s->sr[VGA_SEQ_CLOCK_MODE] & VGA_SR01_CHAR_CLK_8DOTS)) {
799e709b 1880 cw = 9;
5e55efc9
BS
1881 }
1882 if (s->sr[VGA_SEQ_CLOCK_MODE] & 0x08) {
799e709b 1883 cw = 16; /* NOTE: no 18 pixel wide */
5e55efc9
BS
1884 }
1885 width = (s->cr[VGA_CRTC_H_DISP] + 1);
1886 if (s->cr[VGA_CRTC_V_TOTAL] == 100) {
799e709b
AL
1887 /* ugly hack for CGA 160x100x16 - explain me the logic */
1888 height = 100;
1889 } else {
5e55efc9
BS
1890 height = s->cr[VGA_CRTC_V_DISP_END] |
1891 ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) |
1892 ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3);
799e709b 1893 height = (height + 1) / cheight;
4d3b6f6e
AZ
1894 }
1895
1896 size = (height * width);
1897 if (size > CH_ATTR_SIZE) {
1898 if (!full_update)
1899 return;
1900
363a37d5
BS
1901 snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Text mode",
1902 width, height);
4d3b6f6e
AZ
1903 break;
1904 }
1905
799e709b
AL
1906 if (width != s->last_width || height != s->last_height ||
1907 cw != s->last_cw || cheight != s->last_ch) {
1908 s->last_scr_width = width * cw;
1909 s->last_scr_height = height * cheight;
c78f7137
GH
1910 qemu_console_resize(s->con, s->last_scr_width, s->last_scr_height);
1911 dpy_text_resize(s->con, width, height);
9678aedd 1912 s->last_depth = 0;
799e709b
AL
1913 s->last_width = width;
1914 s->last_height = height;
1915 s->last_ch = cheight;
1916 s->last_cw = cw;
1917 full_update = 1;
1918 }
1919
9678aedd
GH
1920 if (full_update) {
1921 s->full_update_gfx = 1;
1922 }
1923 if (s->full_update_text) {
1924 s->full_update_text = 0;
1925 full_update |= 1;
1926 }
1927
4d3b6f6e 1928 /* Update "hardware" cursor */
5e55efc9
BS
1929 cursor_offset = ((s->cr[VGA_CRTC_CURSOR_HI] << 8) |
1930 s->cr[VGA_CRTC_CURSOR_LO]) - s->start_addr;
4d3b6f6e 1931 if (cursor_offset != s->cursor_offset ||
5e55efc9
BS
1932 s->cr[VGA_CRTC_CURSOR_START] != s->cursor_start ||
1933 s->cr[VGA_CRTC_CURSOR_END] != s->cursor_end || full_update) {
1934 cursor_visible = !(s->cr[VGA_CRTC_CURSOR_START] & 0x20);
4d3b6f6e 1935 if (cursor_visible && cursor_offset < size && cursor_offset >= 0)
c78f7137 1936 dpy_text_cursor(s->con,
bf2fde70
GH
1937 TEXTMODE_X(cursor_offset),
1938 TEXTMODE_Y(cursor_offset));
4d3b6f6e 1939 else
c78f7137 1940 dpy_text_cursor(s->con, -1, -1);
4d3b6f6e 1941 s->cursor_offset = cursor_offset;
5e55efc9
BS
1942 s->cursor_start = s->cr[VGA_CRTC_CURSOR_START];
1943 s->cursor_end = s->cr[VGA_CRTC_CURSOR_END];
4d3b6f6e
AZ
1944 }
1945
1946 src = (uint32_t *) s->vram_ptr + s->start_addr;
1947 dst = chardata;
1948
1949 if (full_update) {
1950 for (i = 0; i < size; src ++, dst ++, i ++)
9ae19b65 1951 console_write_ch(dst, VMEM2CHTYPE(le32_to_cpu(*src)));
4d3b6f6e 1952
c78f7137 1953 dpy_text_update(s->con, 0, 0, width, height);
4d3b6f6e
AZ
1954 } else {
1955 c_max = 0;
1956
1957 for (i = 0; i < size; src ++, dst ++, i ++) {
9ae19b65 1958 console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
4d3b6f6e
AZ
1959 if (*dst != val) {
1960 *dst = val;
1961 c_max = i;
1962 break;
1963 }
1964 }
1965 c_min = i;
1966 for (; i < size; src ++, dst ++, i ++) {
9ae19b65 1967 console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
4d3b6f6e
AZ
1968 if (*dst != val) {
1969 *dst = val;
1970 c_max = i;
1971 }
1972 }
1973
1974 if (c_min <= c_max) {
1975 i = TEXTMODE_Y(c_min);
c78f7137 1976 dpy_text_update(s->con, 0, i, width, TEXTMODE_Y(c_max) - i + 1);
4d3b6f6e
AZ
1977 }
1978 }
1979
1980 return;
1981 case GMODE_GRAPH:
1982 if (!full_update)
1983 return;
1984
1985 s->get_resolution(s, &width, &height);
363a37d5
BS
1986 snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Graphic mode",
1987 width, height);
4d3b6f6e
AZ
1988 break;
1989 case GMODE_BLANK:
1990 default:
1991 if (!full_update)
1992 return;
1993
363a37d5 1994 snprintf(msg_buffer, sizeof(msg_buffer), "VGA Blank mode");
4d3b6f6e
AZ
1995 break;
1996 }
1997
1998 /* Display a message */
5228c2d3
AZ
1999 s->last_width = 60;
2000 s->last_height = height = 3;
c78f7137
GH
2001 dpy_text_cursor(s->con, -1, -1);
2002 dpy_text_resize(s->con, s->last_width, height);
4d3b6f6e 2003
5228c2d3 2004 for (dst = chardata, i = 0; i < s->last_width * height; i ++)
4d3b6f6e
AZ
2005 console_write_ch(dst ++, ' ');
2006
2007 size = strlen(msg_buffer);
5228c2d3
AZ
2008 width = (s->last_width - size) / 2;
2009 dst = chardata + s->last_width + width;
4d3b6f6e 2010 for (i = 0; i < size; i ++)
4083733d
OH
2011 console_write_ch(dst ++, ATTR2CHTYPE(msg_buffer[i], QEMU_COLOR_BLUE,
2012 QEMU_COLOR_BLACK, 1));
4d3b6f6e 2013
c78f7137 2014 dpy_text_update(s->con, 0, 0, s->last_width, height);
4d3b6f6e
AZ
2015}
2016
a8170e5e 2017static uint64_t vga_mem_read(void *opaque, hwaddr addr,
b1950430
AK
2018 unsigned size)
2019{
2020 VGACommonState *s = opaque;
2021
b2a5e761 2022 return vga_mem_readb(s, addr);
b1950430 2023}
e89f66ec 2024
a8170e5e 2025static void vga_mem_write(void *opaque, hwaddr addr,
b1950430
AK
2026 uint64_t data, unsigned size)
2027{
2028 VGACommonState *s = opaque;
2029
e7ae771f 2030 vga_mem_writeb(s, addr, data);
b1950430
AK
2031}
2032
2033const MemoryRegionOps vga_mem_ops = {
2034 .read = vga_mem_read,
2035 .write = vga_mem_write,
2036 .endianness = DEVICE_LITTLE_ENDIAN,
b2a5e761
AK
2037 .impl = {
2038 .min_access_size = 1,
2039 .max_access_size = 1,
2040 },
e89f66ec
FB
2041};
2042
11b6b345 2043static int vga_common_post_load(void *opaque, int version_id)
b0a21b53 2044{
0d65ddc3 2045 VGACommonState *s = opaque;
11b6b345
JQ
2046
2047 /* force refresh */
2048 s->graphic_mode = -1;
2049 return 0;
2050}
2051
c3b10605
BH
2052static bool vga_endian_state_needed(void *opaque)
2053{
2054 VGACommonState *s = opaque;
2055
2056 /*
2057 * Only send the endian state if it's different from the
2058 * default one, thus ensuring backward compatibility for
2059 * migration of the common case
2060 */
2061 return s->default_endian_fb != s->big_endian_fb;
2062}
2063
73d22caf 2064static const VMStateDescription vmstate_vga_endian = {
c3b10605
BH
2065 .name = "vga.endian",
2066 .version_id = 1,
2067 .minimum_version_id = 1,
5cd8cada 2068 .needed = vga_endian_state_needed,
c3b10605
BH
2069 .fields = (VMStateField[]) {
2070 VMSTATE_BOOL(big_endian_fb, VGACommonState),
2071 VMSTATE_END_OF_LIST()
2072 }
2073};
2074
11b6b345
JQ
2075const VMStateDescription vmstate_vga_common = {
2076 .name = "vga",
2077 .version_id = 2,
2078 .minimum_version_id = 2,
11b6b345 2079 .post_load = vga_common_post_load,
d49805ae 2080 .fields = (VMStateField[]) {
11b6b345
JQ
2081 VMSTATE_UINT32(latch, VGACommonState),
2082 VMSTATE_UINT8(sr_index, VGACommonState),
2083 VMSTATE_PARTIAL_BUFFER(sr, VGACommonState, 8),
2084 VMSTATE_UINT8(gr_index, VGACommonState),
2085 VMSTATE_PARTIAL_BUFFER(gr, VGACommonState, 16),
2086 VMSTATE_UINT8(ar_index, VGACommonState),
2087 VMSTATE_BUFFER(ar, VGACommonState),
2088 VMSTATE_INT32(ar_flip_flop, VGACommonState),
2089 VMSTATE_UINT8(cr_index, VGACommonState),
2090 VMSTATE_BUFFER(cr, VGACommonState),
2091 VMSTATE_UINT8(msr, VGACommonState),
2092 VMSTATE_UINT8(fcr, VGACommonState),
2093 VMSTATE_UINT8(st00, VGACommonState),
2094 VMSTATE_UINT8(st01, VGACommonState),
2095
2096 VMSTATE_UINT8(dac_state, VGACommonState),
2097 VMSTATE_UINT8(dac_sub_index, VGACommonState),
2098 VMSTATE_UINT8(dac_read_index, VGACommonState),
2099 VMSTATE_UINT8(dac_write_index, VGACommonState),
2100 VMSTATE_BUFFER(dac_cache, VGACommonState),
2101 VMSTATE_BUFFER(palette, VGACommonState),
2102
2103 VMSTATE_INT32(bank_offset, VGACommonState),
2104 VMSTATE_UINT8_EQUAL(is_vbe_vmstate, VGACommonState),
11b6b345
JQ
2105 VMSTATE_UINT16(vbe_index, VGACommonState),
2106 VMSTATE_UINT16_ARRAY(vbe_regs, VGACommonState, VBE_DISPI_INDEX_NB),
2107 VMSTATE_UINT32(vbe_start_addr, VGACommonState),
2108 VMSTATE_UINT32(vbe_line_offset, VGACommonState),
2109 VMSTATE_UINT32(vbe_bank_mask, VGACommonState),
11b6b345 2110 VMSTATE_END_OF_LIST()
c3b10605 2111 },
5cd8cada
JQ
2112 .subsections = (const VMStateDescription*[]) {
2113 &vmstate_vga_endian,
2114 NULL
11b6b345
JQ
2115 }
2116};
2117
380cd056
GH
2118static const GraphicHwOps vga_ops = {
2119 .invalidate = vga_invalidate_display,
2120 .gfx_update = vga_update_display,
2121 .text_update = vga_update_text,
2122};
2123
619616ce
RK
2124static inline uint32_t uint_clamp(uint32_t val, uint32_t vmin, uint32_t vmax)
2125{
2126 if (val < vmin) {
2127 return vmin;
2128 }
2129 if (val > vmax) {
2130 return vmax;
2131 }
2132 return val;
2133}
2134
e2bbfc8e 2135void vga_common_init(VGACommonState *s, Object *obj, bool global_vmstate)
e89f66ec 2136{
17b0018b 2137 int i, j, v, b;
e89f66ec
FB
2138
2139 for(i = 0;i < 256; i++) {
2140 v = 0;
2141 for(j = 0; j < 8; j++) {
2142 v |= ((i >> j) & 1) << (j * 4);
2143 }
2144 expand4[i] = v;
2145
2146 v = 0;
2147 for(j = 0; j < 4; j++) {
2148 v |= ((i >> (2 * j)) & 3) << (j * 4);
2149 }
2150 expand2[i] = v;
2151 }
17b0018b
FB
2152 for(i = 0; i < 16; i++) {
2153 v = 0;
2154 for(j = 0; j < 4; j++) {
2155 b = ((i >> j) & 1);
2156 v |= b << (2 * j);
2157 v |= b << (2 * j + 1);
2158 }
2159 expand4to8[i] = v;
2160 }
e89f66ec 2161
619616ce
RK
2162 s->vram_size_mb = uint_clamp(s->vram_size_mb, 1, 512);
2163 s->vram_size_mb = pow2ceil(s->vram_size_mb);
2164 s->vram_size = s->vram_size_mb << 20;
2165
54a85d46
GH
2166 if (!s->vbe_size) {
2167 s->vbe_size = s->vram_size;
2168 }
4a1e244e 2169
2a3138ab 2170 s->is_vbe_vmstate = 1;
49946538 2171 memory_region_init_ram(&s->vram, obj, "vga.vram", s->vram_size,
f8ed85ac 2172 &error_fatal);
e2bbfc8e 2173 vmstate_register_ram(&s->vram, global_vmstate ? NULL : DEVICE(obj));
c65adf9b 2174 xen_register_framebuffer(&s->vram);
b1950430 2175 s->vram_ptr = memory_region_get_ram_ptr(&s->vram);
798b0c25
FB
2176 s->get_bpp = vga_get_bpp;
2177 s->get_offsets = vga_get_offsets;
a130a41e 2178 s->get_resolution = vga_get_resolution;
380cd056 2179 s->hw_ops = &vga_ops;
cb5a7aa8 2180 switch (vga_retrace_method) {
2181 case VGA_RETRACE_DUMB:
2182 s->retrace = vga_dumb_retrace;
2183 s->update_retrace_info = vga_dumb_update_retrace_info;
2184 break;
2185
2186 case VGA_RETRACE_PRECISE:
2187 s->retrace = vga_precise_retrace;
2188 s->update_retrace_info = vga_precise_update_retrace_info;
cb5a7aa8 2189 break;
2190 }
2c7d8736
BH
2191
2192 /*
c3b10605 2193 * Set default fb endian based on target, could probably be turned
2c7d8736
BH
2194 * into a device attribute set by the machine/platform to remove
2195 * all target endian dependencies from this file.
2196 */
2197#ifdef TARGET_WORDS_BIGENDIAN
c3b10605 2198 s->default_endian_fb = true;
2c7d8736 2199#else
c3b10605 2200 s->default_endian_fb = false;
2c7d8736 2201#endif
b1950430 2202 vga_dirty_log_start(s);
798b0c25
FB
2203}
2204
0a039dc7
RH
2205static const MemoryRegionPortio vga_portio_list[] = {
2206 { 0x04, 2, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3b4 */
2207 { 0x0a, 1, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3ba */
2208 { 0x10, 16, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3c0 */
2209 { 0x24, 2, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3d4 */
2210 { 0x2a, 1, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3da */
2211 PORTIO_END_OF_LIST(),
2212};
e89f66ec 2213
0a039dc7
RH
2214static const MemoryRegionPortio vbe_portio_list[] = {
2215 { 0, 1, 2, .read = vbe_ioport_read_index, .write = vbe_ioport_write_index },
2216# ifdef TARGET_I386
2217 { 1, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data },
0a039dc7 2218# endif
df9ffb72 2219 { 2, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data },
0a039dc7
RH
2220 PORTIO_END_OF_LIST(),
2221};
4fa0f5d2 2222
0a039dc7 2223/* Used by both ISA and PCI */
c84b28ee 2224MemoryRegion *vga_init_io(VGACommonState *s, Object *obj,
0a039dc7
RH
2225 const MemoryRegionPortio **vga_ports,
2226 const MemoryRegionPortio **vbe_ports)
2227{
2228 MemoryRegion *vga_mem;
09a79b49 2229
0a039dc7 2230 *vga_ports = vga_portio_list;
0a039dc7 2231 *vbe_ports = vbe_portio_list;
4fa0f5d2 2232
7267c094 2233 vga_mem = g_malloc(sizeof(*vga_mem));
c84b28ee 2234 memory_region_init_io(vga_mem, obj, &vga_mem_ops, s,
b1950430 2235 "vga-lowmem", 0x20000);
bd8f2f5d 2236 memory_region_set_flush_coalesced(vga_mem);
b1950430
AK
2237
2238 return vga_mem;
7435b791
BS
2239}
2240
712f0cc7 2241void vga_init(VGACommonState *s, Object *obj, MemoryRegion *address_space,
0a039dc7 2242 MemoryRegion *address_space_io, bool init_vga_ports)
7435b791 2243{
b1950430 2244 MemoryRegion *vga_io_memory;
0a039dc7 2245 const MemoryRegionPortio *vga_ports, *vbe_ports;
7435b791
BS
2246
2247 qemu_register_reset(vga_reset, s);
2248
2249 s->bank_offset = 0;
2250
80763888
JK
2251 s->legacy_address_space = address_space;
2252
c84b28ee 2253 vga_io_memory = vga_init_io(s, obj, &vga_ports, &vbe_ports);
be20f9e9 2254 memory_region_add_subregion_overlap(address_space,
b19c1c08 2255 0x000a0000,
b1950430
AK
2256 vga_io_memory,
2257 1);
2258 memory_region_set_coalescing(vga_io_memory);
0a039dc7 2259 if (init_vga_ports) {
848696bf
KB
2260 portio_list_init(&s->vga_port_list, obj, vga_ports, s, "vga");
2261 portio_list_set_flush_coalesced(&s->vga_port_list);
2262 portio_list_add(&s->vga_port_list, address_space_io, 0x3b0);
0a039dc7
RH
2263 }
2264 if (vbe_ports) {
848696bf
KB
2265 portio_list_init(&s->vbe_port_list, obj, vbe_ports, s, "vbe");
2266 portio_list_add(&s->vbe_port_list, address_space_io, 0x1ce);
0a039dc7 2267 }
d2269f6f
FB
2268}
2269
83118327 2270void vga_init_vbe(VGACommonState *s, Object *obj, MemoryRegion *system_memory)
f0138a63 2271{
8294a64d
AK
2272 /* With pc-0.12 and below we map both the PCI BAR and the fixed VBE region,
2273 * so use an alias to avoid double-mapping the same region.
2274 */
83118327 2275 memory_region_init_alias(&s->vram_vbe, obj, "vram.vbe",
8294a64d 2276 &s->vram, 0, memory_region_size(&s->vram));
f0138a63 2277 /* XXX: use optimized standard vga accesses */
be20f9e9 2278 memory_region_add_subregion(system_memory,
b1950430 2279 VBE_DISPI_LFB_PHYSICAL_ADDRESS,
8294a64d 2280 &s->vram_vbe);
f0138a63 2281 s->vbe_mapped = 1;
f0138a63 2282}