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