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