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