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