]> Git Repo - qemu.git/blame - hw/vga.c
vga: export vga_ioport_{read,write}
[qemu.git] / hw / 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 */
87ecb68b
PB
24#include "hw.h"
25#include "console.h"
26#include "pc.h"
27#include "pci.h"
798b0c25 28#include "vga_int.h"
94470844 29#include "pixel_ops.h"
cb5a7aa8 30#include "qemu-timer.h"
2bec46dc 31#include "kvm.h"
e89f66ec 32
e89f66ec 33//#define DEBUG_VGA
17b0018b 34//#define DEBUG_VGA_MEM
a41bc9af
FB
35//#define DEBUG_VGA_REG
36
4fa0f5d2
FB
37//#define DEBUG_BOCHS_VBE
38
e89f66ec 39/* force some bits to zero */
798b0c25 40const uint8_t sr_mask[8] = {
9e622b15
BS
41 0x03,
42 0x3d,
43 0x0f,
44 0x3f,
45 0x0e,
46 0x00,
47 0x00,
48 0xff,
e89f66ec
FB
49};
50
798b0c25 51const uint8_t gr_mask[16] = {
9e622b15
BS
52 0x0f, /* 0x00 */
53 0x0f, /* 0x01 */
54 0x0f, /* 0x02 */
55 0x1f, /* 0x03 */
56 0x03, /* 0x04 */
57 0x7b, /* 0x05 */
58 0x0f, /* 0x06 */
59 0x0f, /* 0x07 */
60 0xff, /* 0x08 */
61 0x00, /* 0x09 */
62 0x00, /* 0x0a */
63 0x00, /* 0x0b */
64 0x00, /* 0x0c */
65 0x00, /* 0x0d */
66 0x00, /* 0x0e */
67 0x00, /* 0x0f */
e89f66ec
FB
68};
69
70#define cbswap_32(__x) \
71((uint32_t)( \
72 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
73 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
74 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
75 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
76
e2542fe2 77#ifdef HOST_WORDS_BIGENDIAN
e89f66ec
FB
78#define PAT(x) cbswap_32(x)
79#else
80#define PAT(x) (x)
81#endif
82
e2542fe2 83#ifdef HOST_WORDS_BIGENDIAN
b8ed223b
FB
84#define BIG 1
85#else
86#define BIG 0
87#endif
88
e2542fe2 89#ifdef HOST_WORDS_BIGENDIAN
b8ed223b
FB
90#define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
91#else
92#define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
93#endif
94
e89f66ec
FB
95static const uint32_t mask16[16] = {
96 PAT(0x00000000),
97 PAT(0x000000ff),
98 PAT(0x0000ff00),
99 PAT(0x0000ffff),
100 PAT(0x00ff0000),
101 PAT(0x00ff00ff),
102 PAT(0x00ffff00),
103 PAT(0x00ffffff),
104 PAT(0xff000000),
105 PAT(0xff0000ff),
106 PAT(0xff00ff00),
107 PAT(0xff00ffff),
108 PAT(0xffff0000),
109 PAT(0xffff00ff),
110 PAT(0xffffff00),
111 PAT(0xffffffff),
112};
113
114#undef PAT
115
e2542fe2 116#ifdef HOST_WORDS_BIGENDIAN
e89f66ec
FB
117#define PAT(x) (x)
118#else
119#define PAT(x) cbswap_32(x)
120#endif
121
122static const uint32_t dmask16[16] = {
123 PAT(0x00000000),
124 PAT(0x000000ff),
125 PAT(0x0000ff00),
126 PAT(0x0000ffff),
127 PAT(0x00ff0000),
128 PAT(0x00ff00ff),
129 PAT(0x00ffff00),
130 PAT(0x00ffffff),
131 PAT(0xff000000),
132 PAT(0xff0000ff),
133 PAT(0xff00ff00),
134 PAT(0xff00ffff),
135 PAT(0xffff0000),
136 PAT(0xffff00ff),
137 PAT(0xffffff00),
138 PAT(0xffffffff),
139};
140
141static const uint32_t dmask4[4] = {
142 PAT(0x00000000),
143 PAT(0x0000ffff),
144 PAT(0xffff0000),
145 PAT(0xffffffff),
146};
147
148static uint32_t expand4[256];
149static uint16_t expand2[256];
17b0018b 150static uint8_t expand4to8[16];
e89f66ec 151
a4a2f59c
JQ
152typedef VGACommonState VGAState;
153
95219897 154static void vga_screen_dump(void *opaque, const char *filename);
04a52b41
SS
155static char *screen_dump_filename;
156static DisplayChangeListener *screen_dump_dcl;
95219897 157
cb5a7aa8 158static void vga_dumb_update_retrace_info(VGAState *s)
159{
160 (void) s;
161}
162
163static void vga_precise_update_retrace_info(VGAState *s)
164{
165 int htotal_chars;
166 int hretr_start_char;
167 int hretr_skew_chars;
168 int hretr_end_char;
169
170 int vtotal_lines;
171 int vretr_start_line;
172 int vretr_end_line;
173
174 int div2, sldiv2, dots;
175 int clocking_mode;
176 int clock_sel;
b0f74c87 177 const int clk_hz[] = {25175000, 28322000, 25175000, 25175000};
cb5a7aa8 178 int64_t chars_per_sec;
179 struct vga_precise_retrace *r = &s->retrace_info.precise;
180
181 htotal_chars = s->cr[0x00] + 5;
182 hretr_start_char = s->cr[0x04];
183 hretr_skew_chars = (s->cr[0x05] >> 5) & 3;
184 hretr_end_char = s->cr[0x05] & 0x1f;
185
186 vtotal_lines = (s->cr[0x06]
187 | (((s->cr[0x07] & 1) | ((s->cr[0x07] >> 4) & 2)) << 8)) + 2
188 ;
189 vretr_start_line = s->cr[0x10]
190 | ((((s->cr[0x07] >> 2) & 1) | ((s->cr[0x07] >> 6) & 2)) << 8)
191 ;
192 vretr_end_line = s->cr[0x11] & 0xf;
193
194
195 div2 = (s->cr[0x17] >> 2) & 1;
196 sldiv2 = (s->cr[0x17] >> 3) & 1;
197
198 clocking_mode = (s->sr[0x01] >> 3) & 1;
199 clock_sel = (s->msr >> 2) & 3;
f87fc09b 200 dots = (s->msr & 1) ? 8 : 9;
cb5a7aa8 201
b0f74c87 202 chars_per_sec = clk_hz[clock_sel] / dots;
cb5a7aa8 203
204 htotal_chars <<= clocking_mode;
205
206 r->total_chars = vtotal_lines * htotal_chars;
cb5a7aa8 207 if (r->freq) {
208 r->ticks_per_char = ticks_per_sec / (r->total_chars * r->freq);
209 } else {
210 r->ticks_per_char = ticks_per_sec / chars_per_sec;
211 }
212
213 r->vstart = vretr_start_line;
214 r->vend = r->vstart + vretr_end_line + 1;
215
216 r->hstart = hretr_start_char + hretr_skew_chars;
217 r->hend = r->hstart + hretr_end_char + 1;
218 r->htotal = htotal_chars;
219
f87fc09b 220#if 0
cb5a7aa8 221 printf (
f87fc09b 222 "hz=%f\n"
cb5a7aa8 223 "htotal = %d\n"
224 "hretr_start = %d\n"
225 "hretr_skew = %d\n"
226 "hretr_end = %d\n"
227 "vtotal = %d\n"
228 "vretr_start = %d\n"
229 "vretr_end = %d\n"
230 "div2 = %d sldiv2 = %d\n"
231 "clocking_mode = %d\n"
232 "clock_sel = %d %d\n"
233 "dots = %d\n"
234 "ticks/char = %lld\n"
235 "\n",
f87fc09b 236 (double) ticks_per_sec / (r->ticks_per_char * r->total_chars),
cb5a7aa8 237 htotal_chars,
238 hretr_start_char,
239 hretr_skew_chars,
240 hretr_end_char,
241 vtotal_lines,
242 vretr_start_line,
243 vretr_end_line,
244 div2, sldiv2,
245 clocking_mode,
246 clock_sel,
b0f74c87 247 clk_hz[clock_sel],
cb5a7aa8 248 dots,
249 r->ticks_per_char
250 );
251#endif
252}
253
254static uint8_t vga_precise_retrace(VGAState *s)
255{
256 struct vga_precise_retrace *r = &s->retrace_info.precise;
257 uint8_t val = s->st01 & ~(ST01_V_RETRACE | ST01_DISP_ENABLE);
258
259 if (r->total_chars) {
260 int cur_line, cur_line_char, cur_char;
261 int64_t cur_tick;
262
263 cur_tick = qemu_get_clock(vm_clock);
264
265 cur_char = (cur_tick / r->ticks_per_char) % r->total_chars;
266 cur_line = cur_char / r->htotal;
267
268 if (cur_line >= r->vstart && cur_line <= r->vend) {
269 val |= ST01_V_RETRACE | ST01_DISP_ENABLE;
f87fc09b 270 } else {
271 cur_line_char = cur_char % r->htotal;
272 if (cur_line_char >= r->hstart && cur_line_char <= r->hend) {
273 val |= ST01_DISP_ENABLE;
274 }
cb5a7aa8 275 }
276
277 return val;
278 } else {
279 return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
280 }
281}
282
283static uint8_t vga_dumb_retrace(VGAState *s)
284{
285 return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
286}
287
43bf782b 288uint32_t vga_ioport_read(void *opaque, uint32_t addr)
e89f66ec 289{
43bf782b 290 VGACommonState *s = opaque;
e89f66ec
FB
291 int val, index;
292
293 /* check port range access depending on color/monochrome mode */
294 if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
295 (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION))) {
296 val = 0xff;
297 } else {
298 switch(addr) {
299 case 0x3c0:
300 if (s->ar_flip_flop == 0) {
301 val = s->ar_index;
302 } else {
303 val = 0;
304 }
305 break;
306 case 0x3c1:
307 index = s->ar_index & 0x1f;
5fafdf24 308 if (index < 21)
e89f66ec
FB
309 val = s->ar[index];
310 else
311 val = 0;
312 break;
313 case 0x3c2:
314 val = s->st00;
315 break;
316 case 0x3c4:
317 val = s->sr_index;
318 break;
319 case 0x3c5:
320 val = s->sr[s->sr_index];
a41bc9af
FB
321#ifdef DEBUG_VGA_REG
322 printf("vga: read SR%x = 0x%02x\n", s->sr_index, val);
323#endif
e89f66ec
FB
324 break;
325 case 0x3c7:
326 val = s->dac_state;
327 break;
e6eccb38
FB
328 case 0x3c8:
329 val = s->dac_write_index;
330 break;
e89f66ec
FB
331 case 0x3c9:
332 val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
333 if (++s->dac_sub_index == 3) {
334 s->dac_sub_index = 0;
335 s->dac_read_index++;
336 }
337 break;
338 case 0x3ca:
339 val = s->fcr;
340 break;
341 case 0x3cc:
342 val = s->msr;
343 break;
344 case 0x3ce:
345 val = s->gr_index;
346 break;
347 case 0x3cf:
348 val = s->gr[s->gr_index];
a41bc9af
FB
349#ifdef DEBUG_VGA_REG
350 printf("vga: read GR%x = 0x%02x\n", s->gr_index, val);
351#endif
e89f66ec
FB
352 break;
353 case 0x3b4:
354 case 0x3d4:
355 val = s->cr_index;
356 break;
357 case 0x3b5:
358 case 0x3d5:
359 val = s->cr[s->cr_index];
a41bc9af
FB
360#ifdef DEBUG_VGA_REG
361 printf("vga: read CR%x = 0x%02x\n", s->cr_index, val);
a41bc9af 362#endif
e89f66ec
FB
363 break;
364 case 0x3ba:
365 case 0x3da:
366 /* just toggle to fool polling */
cb5a7aa8 367 val = s->st01 = s->retrace(s);
e89f66ec
FB
368 s->ar_flip_flop = 0;
369 break;
370 default:
371 val = 0x00;
372 break;
373 }
374 }
4fa0f5d2 375#if defined(DEBUG_VGA)
e89f66ec
FB
376 printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
377#endif
378 return val;
379}
380
43bf782b 381void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
e89f66ec 382{
43bf782b 383 VGACommonState *s = opaque;
5467a722 384 int index;
e89f66ec
FB
385
386 /* check port range access depending on color/monochrome mode */
387 if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
388 (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION)))
389 return;
390
391#ifdef DEBUG_VGA
392 printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
393#endif
394
395 switch(addr) {
396 case 0x3c0:
397 if (s->ar_flip_flop == 0) {
398 val &= 0x3f;
399 s->ar_index = val;
400 } else {
401 index = s->ar_index & 0x1f;
402 switch(index) {
403 case 0x00 ... 0x0f:
404 s->ar[index] = val & 0x3f;
405 break;
406 case 0x10:
407 s->ar[index] = val & ~0x10;
408 break;
409 case 0x11:
410 s->ar[index] = val;
411 break;
412 case 0x12:
413 s->ar[index] = val & ~0xc0;
414 break;
415 case 0x13:
416 s->ar[index] = val & ~0xf0;
417 break;
418 case 0x14:
419 s->ar[index] = val & ~0xf0;
420 break;
421 default:
422 break;
423 }
424 }
425 s->ar_flip_flop ^= 1;
426 break;
427 case 0x3c2:
428 s->msr = val & ~0x10;
cb5a7aa8 429 s->update_retrace_info(s);
e89f66ec
FB
430 break;
431 case 0x3c4:
432 s->sr_index = val & 7;
433 break;
434 case 0x3c5:
a41bc9af
FB
435#ifdef DEBUG_VGA_REG
436 printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
437#endif
e89f66ec 438 s->sr[s->sr_index] = val & sr_mask[s->sr_index];
cb5a7aa8 439 if (s->sr_index == 1) s->update_retrace_info(s);
e89f66ec
FB
440 break;
441 case 0x3c7:
442 s->dac_read_index = val;
443 s->dac_sub_index = 0;
444 s->dac_state = 3;
445 break;
446 case 0x3c8:
447 s->dac_write_index = val;
448 s->dac_sub_index = 0;
449 s->dac_state = 0;
450 break;
451 case 0x3c9:
452 s->dac_cache[s->dac_sub_index] = val;
453 if (++s->dac_sub_index == 3) {
454 memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
455 s->dac_sub_index = 0;
456 s->dac_write_index++;
457 }
458 break;
459 case 0x3ce:
460 s->gr_index = val & 0x0f;
461 break;
462 case 0x3cf:
a41bc9af
FB
463#ifdef DEBUG_VGA_REG
464 printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
465#endif
e89f66ec
FB
466 s->gr[s->gr_index] = val & gr_mask[s->gr_index];
467 break;
468 case 0x3b4:
469 case 0x3d4:
470 s->cr_index = val;
471 break;
472 case 0x3b5:
473 case 0x3d5:
a41bc9af
FB
474#ifdef DEBUG_VGA_REG
475 printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
476#endif
e89f66ec 477 /* handle CR0-7 protection */
f6c958c8 478 if ((s->cr[0x11] & 0x80) && s->cr_index <= 7) {
e89f66ec
FB
479 /* can always write bit 4 of CR7 */
480 if (s->cr_index == 7)
481 s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
482 return;
483 }
484 switch(s->cr_index) {
485 case 0x01: /* horizontal display end */
486 case 0x07:
487 case 0x09:
488 case 0x0c:
489 case 0x0d:
e91c8a77 490 case 0x12: /* vertical display end */
e89f66ec
FB
491 s->cr[s->cr_index] = val;
492 break;
e89f66ec
FB
493 default:
494 s->cr[s->cr_index] = val;
495 break;
496 }
cb5a7aa8 497
498 switch(s->cr_index) {
499 case 0x00:
500 case 0x04:
501 case 0x05:
502 case 0x06:
503 case 0x07:
504 case 0x11:
505 case 0x17:
506 s->update_retrace_info(s);
507 break;
508 }
e89f66ec
FB
509 break;
510 case 0x3ba:
511 case 0x3da:
512 s->fcr = val & 0x10;
513 break;
514 }
515}
516
4fa0f5d2 517#ifdef CONFIG_BOCHS_VBE
09a79b49 518static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
4fa0f5d2 519{
0f35920c 520 VGAState *s = opaque;
4fa0f5d2 521 uint32_t val;
09a79b49
FB
522 val = s->vbe_index;
523 return val;
524}
4fa0f5d2 525
09a79b49
FB
526static uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr)
527{
528 VGAState *s = opaque;
529 uint32_t val;
530
8454df8b
FB
531 if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
532 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_GETCAPS) {
533 switch(s->vbe_index) {
534 /* XXX: do not hardcode ? */
535 case VBE_DISPI_INDEX_XRES:
536 val = VBE_DISPI_MAX_XRES;
537 break;
538 case VBE_DISPI_INDEX_YRES:
539 val = VBE_DISPI_MAX_YRES;
540 break;
541 case VBE_DISPI_INDEX_BPP:
542 val = VBE_DISPI_MAX_BPP;
543 break;
544 default:
5fafdf24 545 val = s->vbe_regs[s->vbe_index];
8454df8b
FB
546 break;
547 }
548 } else {
5fafdf24 549 val = s->vbe_regs[s->vbe_index];
8454df8b
FB
550 }
551 } else {
09a79b49 552 val = 0;
8454df8b 553 }
4fa0f5d2 554#ifdef DEBUG_BOCHS_VBE
09a79b49 555 printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val);
4fa0f5d2 556#endif
4fa0f5d2
FB
557 return val;
558}
559
09a79b49
FB
560static void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val)
561{
562 VGAState *s = opaque;
563 s->vbe_index = val;
564}
565
566static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
4fa0f5d2 567{
0f35920c 568 VGAState *s = opaque;
4fa0f5d2 569
09a79b49 570 if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
4fa0f5d2
FB
571#ifdef DEBUG_BOCHS_VBE
572 printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val);
573#endif
574 switch(s->vbe_index) {
575 case VBE_DISPI_INDEX_ID:
cae61cef
FB
576 if (val == VBE_DISPI_ID0 ||
577 val == VBE_DISPI_ID1 ||
37dd208d
FB
578 val == VBE_DISPI_ID2 ||
579 val == VBE_DISPI_ID3 ||
580 val == VBE_DISPI_ID4) {
cae61cef
FB
581 s->vbe_regs[s->vbe_index] = val;
582 }
4fa0f5d2
FB
583 break;
584 case VBE_DISPI_INDEX_XRES:
cae61cef
FB
585 if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) {
586 s->vbe_regs[s->vbe_index] = val;
587 }
4fa0f5d2
FB
588 break;
589 case VBE_DISPI_INDEX_YRES:
cae61cef
FB
590 if (val <= VBE_DISPI_MAX_YRES) {
591 s->vbe_regs[s->vbe_index] = val;
592 }
4fa0f5d2
FB
593 break;
594 case VBE_DISPI_INDEX_BPP:
595 if (val == 0)
596 val = 8;
5fafdf24 597 if (val == 4 || val == 8 || val == 15 ||
cae61cef
FB
598 val == 16 || val == 24 || val == 32) {
599 s->vbe_regs[s->vbe_index] = val;
600 }
4fa0f5d2
FB
601 break;
602 case VBE_DISPI_INDEX_BANK:
42fc925e
FB
603 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
604 val &= (s->vbe_bank_mask >> 2);
605 } else {
606 val &= s->vbe_bank_mask;
607 }
cae61cef 608 s->vbe_regs[s->vbe_index] = val;
26aa7d72 609 s->bank_offset = (val << 16);
4fa0f5d2
FB
610 break;
611 case VBE_DISPI_INDEX_ENABLE:
8454df8b
FB
612 if ((val & VBE_DISPI_ENABLED) &&
613 !(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
4fa0f5d2
FB
614 int h, shift_control;
615
5fafdf24 616 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] =
4fa0f5d2 617 s->vbe_regs[VBE_DISPI_INDEX_XRES];
5fafdf24 618 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] =
4fa0f5d2
FB
619 s->vbe_regs[VBE_DISPI_INDEX_YRES];
620 s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
621 s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
3b46e624 622
4fa0f5d2
FB
623 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
624 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1;
625 else
5fafdf24 626 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] *
4fa0f5d2
FB
627 ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
628 s->vbe_start_addr = 0;
8454df8b 629
4fa0f5d2
FB
630 /* clear the screen (should be done in BIOS) */
631 if (!(val & VBE_DISPI_NOCLEARMEM)) {
5fafdf24 632 memset(s->vram_ptr, 0,
4fa0f5d2
FB
633 s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
634 }
3b46e624 635
cae61cef
FB
636 /* we initialize the VGA graphic mode (should be done
637 in BIOS) */
638 s->gr[0x06] = (s->gr[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
4fa0f5d2
FB
639 s->cr[0x17] |= 3; /* no CGA modes */
640 s->cr[0x13] = s->vbe_line_offset >> 3;
641 /* width */
642 s->cr[0x01] = (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
8454df8b 643 /* height (only meaningful if < 1024) */
4fa0f5d2
FB
644 h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
645 s->cr[0x12] = h;
5fafdf24 646 s->cr[0x07] = (s->cr[0x07] & ~0x42) |
4fa0f5d2
FB
647 ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
648 /* line compare to 1023 */
649 s->cr[0x18] = 0xff;
650 s->cr[0x07] |= 0x10;
651 s->cr[0x09] |= 0x40;
3b46e624 652
4fa0f5d2
FB
653 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
654 shift_control = 0;
655 s->sr[0x01] &= ~8; /* no double line */
656 } else {
657 shift_control = 2;
646be93b 658 s->sr[4] |= 0x08; /* set chain 4 mode */
141253b2 659 s->sr[2] |= 0x0f; /* activate all planes */
4fa0f5d2
FB
660 }
661 s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5);
662 s->cr[0x09] &= ~0x9f; /* no double scan */
cae61cef
FB
663 } else {
664 /* XXX: the bios should do that */
26aa7d72 665 s->bank_offset = 0;
cae61cef 666 }
37dd208d 667 s->dac_8bit = (val & VBE_DISPI_8BIT_DAC) > 0;
141253b2 668 s->vbe_regs[s->vbe_index] = val;
cae61cef
FB
669 break;
670 case VBE_DISPI_INDEX_VIRT_WIDTH:
671 {
672 int w, h, line_offset;
673
674 if (val < s->vbe_regs[VBE_DISPI_INDEX_XRES])
675 return;
676 w = val;
677 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
678 line_offset = w >> 1;
679 else
680 line_offset = w * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
681 h = s->vram_size / line_offset;
682 /* XXX: support weird bochs semantics ? */
683 if (h < s->vbe_regs[VBE_DISPI_INDEX_YRES])
684 return;
685 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = w;
686 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h;
687 s->vbe_line_offset = line_offset;
688 }
689 break;
690 case VBE_DISPI_INDEX_X_OFFSET:
691 case VBE_DISPI_INDEX_Y_OFFSET:
692 {
693 int x;
694 s->vbe_regs[s->vbe_index] = val;
695 s->vbe_start_addr = s->vbe_line_offset * s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET];
696 x = s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET];
697 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
698 s->vbe_start_addr += x >> 1;
699 else
700 s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
701 s->vbe_start_addr >>= 2;
4fa0f5d2
FB
702 }
703 break;
704 default:
705 break;
706 }
4fa0f5d2
FB
707 }
708}
709#endif
710
e89f66ec 711/* called for accesses between 0xa0000 and 0xc0000 */
798b0c25 712uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr)
e89f66ec 713{
a4193c8a 714 VGAState *s = opaque;
e89f66ec
FB
715 int memory_map_mode, plane;
716 uint32_t ret;
3b46e624 717
e89f66ec
FB
718 /* convert to VGA memory offset */
719 memory_map_mode = (s->gr[6] >> 2) & 3;
26aa7d72 720 addr &= 0x1ffff;
e89f66ec
FB
721 switch(memory_map_mode) {
722 case 0:
e89f66ec
FB
723 break;
724 case 1:
26aa7d72 725 if (addr >= 0x10000)
e89f66ec 726 return 0xff;
cae61cef 727 addr += s->bank_offset;
e89f66ec
FB
728 break;
729 case 2:
26aa7d72 730 addr -= 0x10000;
e89f66ec
FB
731 if (addr >= 0x8000)
732 return 0xff;
733 break;
734 default:
735 case 3:
26aa7d72 736 addr -= 0x18000;
c92b2e84
FB
737 if (addr >= 0x8000)
738 return 0xff;
e89f66ec
FB
739 break;
740 }
3b46e624 741
e89f66ec
FB
742 if (s->sr[4] & 0x08) {
743 /* chain 4 mode : simplest access */
744 ret = s->vram_ptr[addr];
745 } else if (s->gr[5] & 0x10) {
746 /* odd/even mode (aka text mode mapping) */
747 plane = (s->gr[4] & 2) | (addr & 1);
748 ret = s->vram_ptr[((addr & ~1) << 1) | plane];
749 } else {
750 /* standard VGA latched access */
751 s->latch = ((uint32_t *)s->vram_ptr)[addr];
752
753 if (!(s->gr[5] & 0x08)) {
754 /* read mode 0 */
755 plane = s->gr[4];
b8ed223b 756 ret = GET_PLANE(s->latch, plane);
e89f66ec
FB
757 } else {
758 /* read mode 1 */
759 ret = (s->latch ^ mask16[s->gr[2]]) & mask16[s->gr[7]];
760 ret |= ret >> 16;
761 ret |= ret >> 8;
762 ret = (~ret) & 0xff;
763 }
764 }
765 return ret;
766}
767
a4193c8a 768static uint32_t vga_mem_readw(void *opaque, target_phys_addr_t addr)
e89f66ec
FB
769{
770 uint32_t v;
09a79b49 771#ifdef TARGET_WORDS_BIGENDIAN
a4193c8a
FB
772 v = vga_mem_readb(opaque, addr) << 8;
773 v |= vga_mem_readb(opaque, addr + 1);
09a79b49 774#else
a4193c8a
FB
775 v = vga_mem_readb(opaque, addr);
776 v |= vga_mem_readb(opaque, addr + 1) << 8;
09a79b49 777#endif
e89f66ec
FB
778 return v;
779}
780
a4193c8a 781static uint32_t vga_mem_readl(void *opaque, target_phys_addr_t addr)
e89f66ec
FB
782{
783 uint32_t v;
09a79b49 784#ifdef TARGET_WORDS_BIGENDIAN
a4193c8a
FB
785 v = vga_mem_readb(opaque, addr) << 24;
786 v |= vga_mem_readb(opaque, addr + 1) << 16;
787 v |= vga_mem_readb(opaque, addr + 2) << 8;
788 v |= vga_mem_readb(opaque, addr + 3);
09a79b49 789#else
a4193c8a
FB
790 v = vga_mem_readb(opaque, addr);
791 v |= vga_mem_readb(opaque, addr + 1) << 8;
792 v |= vga_mem_readb(opaque, addr + 2) << 16;
793 v |= vga_mem_readb(opaque, addr + 3) << 24;
09a79b49 794#endif
e89f66ec
FB
795 return v;
796}
797
e89f66ec 798/* called for accesses between 0xa0000 and 0xc0000 */
798b0c25 799void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
e89f66ec 800{
a4193c8a 801 VGAState *s = opaque;
546fa6ab 802 int memory_map_mode, plane, write_mode, b, func_select, mask;
e89f66ec
FB
803 uint32_t write_mask, bit_mask, set_mask;
804
17b0018b 805#ifdef DEBUG_VGA_MEM
0bf9e31a 806 printf("vga: [0x" TARGET_FMT_plx "] = 0x%02x\n", addr, val);
e89f66ec
FB
807#endif
808 /* convert to VGA memory offset */
809 memory_map_mode = (s->gr[6] >> 2) & 3;
26aa7d72 810 addr &= 0x1ffff;
e89f66ec
FB
811 switch(memory_map_mode) {
812 case 0:
e89f66ec
FB
813 break;
814 case 1:
26aa7d72 815 if (addr >= 0x10000)
e89f66ec 816 return;
cae61cef 817 addr += s->bank_offset;
e89f66ec
FB
818 break;
819 case 2:
26aa7d72 820 addr -= 0x10000;
e89f66ec
FB
821 if (addr >= 0x8000)
822 return;
823 break;
824 default:
825 case 3:
26aa7d72 826 addr -= 0x18000;
c92b2e84
FB
827 if (addr >= 0x8000)
828 return;
e89f66ec
FB
829 break;
830 }
3b46e624 831
e89f66ec
FB
832 if (s->sr[4] & 0x08) {
833 /* chain 4 mode : simplest access */
834 plane = addr & 3;
546fa6ab
FB
835 mask = (1 << plane);
836 if (s->sr[2] & mask) {
e89f66ec 837 s->vram_ptr[addr] = val;
17b0018b 838#ifdef DEBUG_VGA_MEM
0bf9e31a 839 printf("vga: chain4: [0x" TARGET_FMT_plx "]\n", addr);
e89f66ec 840#endif
546fa6ab 841 s->plane_updated |= mask; /* only used to detect font change */
4fa0f5d2 842 cpu_physical_memory_set_dirty(s->vram_offset + addr);
e89f66ec
FB
843 }
844 } else if (s->gr[5] & 0x10) {
845 /* odd/even mode (aka text mode mapping) */
846 plane = (s->gr[4] & 2) | (addr & 1);
546fa6ab
FB
847 mask = (1 << plane);
848 if (s->sr[2] & mask) {
e89f66ec
FB
849 addr = ((addr & ~1) << 1) | plane;
850 s->vram_ptr[addr] = val;
17b0018b 851#ifdef DEBUG_VGA_MEM
0bf9e31a 852 printf("vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr);
e89f66ec 853#endif
546fa6ab 854 s->plane_updated |= mask; /* only used to detect font change */
4fa0f5d2 855 cpu_physical_memory_set_dirty(s->vram_offset + addr);
e89f66ec
FB
856 }
857 } else {
858 /* standard VGA latched access */
859 write_mode = s->gr[5] & 3;
860 switch(write_mode) {
861 default:
862 case 0:
863 /* rotate */
864 b = s->gr[3] & 7;
865 val = ((val >> b) | (val << (8 - b))) & 0xff;
866 val |= val << 8;
867 val |= val << 16;
868
869 /* apply set/reset mask */
870 set_mask = mask16[s->gr[1]];
871 val = (val & ~set_mask) | (mask16[s->gr[0]] & set_mask);
872 bit_mask = s->gr[8];
873 break;
874 case 1:
875 val = s->latch;
876 goto do_write;
877 case 2:
878 val = mask16[val & 0x0f];
879 bit_mask = s->gr[8];
880 break;
881 case 3:
882 /* rotate */
883 b = s->gr[3] & 7;
a41bc9af 884 val = (val >> b) | (val << (8 - b));
e89f66ec
FB
885
886 bit_mask = s->gr[8] & val;
887 val = mask16[s->gr[0]];
888 break;
889 }
890
891 /* apply logical operation */
892 func_select = s->gr[3] >> 3;
893 switch(func_select) {
894 case 0:
895 default:
896 /* nothing to do */
897 break;
898 case 1:
899 /* and */
900 val &= s->latch;
901 break;
902 case 2:
903 /* or */
904 val |= s->latch;
905 break;
906 case 3:
907 /* xor */
908 val ^= s->latch;
909 break;
910 }
911
912 /* apply bit mask */
913 bit_mask |= bit_mask << 8;
914 bit_mask |= bit_mask << 16;
915 val = (val & bit_mask) | (s->latch & ~bit_mask);
916
917 do_write:
918 /* mask data according to sr[2] */
546fa6ab
FB
919 mask = s->sr[2];
920 s->plane_updated |= mask; /* only used to detect font change */
921 write_mask = mask16[mask];
5fafdf24
TS
922 ((uint32_t *)s->vram_ptr)[addr] =
923 (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
e89f66ec 924 (val & write_mask);
17b0018b 925#ifdef DEBUG_VGA_MEM
0bf9e31a
BS
926 printf("vga: latch: [0x" TARGET_FMT_plx "] mask=0x%08x val=0x%08x\n",
927 addr * 4, write_mask, val);
e89f66ec 928#endif
0bf9e31a 929 cpu_physical_memory_set_dirty(s->vram_offset + (addr << 2));
e89f66ec
FB
930 }
931}
932
a4193c8a 933static void vga_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
e89f66ec 934{
09a79b49 935#ifdef TARGET_WORDS_BIGENDIAN
a4193c8a
FB
936 vga_mem_writeb(opaque, addr, (val >> 8) & 0xff);
937 vga_mem_writeb(opaque, addr + 1, val & 0xff);
09a79b49 938#else
a4193c8a
FB
939 vga_mem_writeb(opaque, addr, val & 0xff);
940 vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
09a79b49 941#endif
e89f66ec
FB
942}
943
a4193c8a 944static void vga_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
e89f66ec 945{
09a79b49 946#ifdef TARGET_WORDS_BIGENDIAN
a4193c8a
FB
947 vga_mem_writeb(opaque, addr, (val >> 24) & 0xff);
948 vga_mem_writeb(opaque, addr + 1, (val >> 16) & 0xff);
949 vga_mem_writeb(opaque, addr + 2, (val >> 8) & 0xff);
950 vga_mem_writeb(opaque, addr + 3, val & 0xff);
09a79b49 951#else
a4193c8a
FB
952 vga_mem_writeb(opaque, addr, val & 0xff);
953 vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
954 vga_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff);
955 vga_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff);
09a79b49 956#endif
e89f66ec
FB
957}
958
e89f66ec
FB
959typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
960 const uint8_t *font_ptr, int h,
961 uint32_t fgcol, uint32_t bgcol);
962typedef void vga_draw_glyph9_func(uint8_t *d, int linesize,
5fafdf24 963 const uint8_t *font_ptr, int h,
e89f66ec 964 uint32_t fgcol, uint32_t bgcol, int dup9);
5fafdf24 965typedef void vga_draw_line_func(VGAState *s1, uint8_t *d,
e89f66ec
FB
966 const uint8_t *s, int width);
967
e89f66ec
FB
968#define DEPTH 8
969#include "vga_template.h"
970
971#define DEPTH 15
972#include "vga_template.h"
973
a2502b58
BS
974#define BGR_FORMAT
975#define DEPTH 15
976#include "vga_template.h"
977
978#define DEPTH 16
979#include "vga_template.h"
980
981#define BGR_FORMAT
e89f66ec
FB
982#define DEPTH 16
983#include "vga_template.h"
984
985#define DEPTH 32
986#include "vga_template.h"
987
d3079cd2
FB
988#define BGR_FORMAT
989#define DEPTH 32
990#include "vga_template.h"
991
17b0018b
FB
992static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
993{
994 unsigned int col;
995 col = rgb_to_pixel8(r, g, b);
996 col |= col << 8;
997 col |= col << 16;
998 return col;
999}
1000
1001static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b)
1002{
1003 unsigned int col;
1004 col = rgb_to_pixel15(r, g, b);
1005 col |= col << 16;
1006 return col;
1007}
1008
b29169d2
BS
1009static unsigned int rgb_to_pixel15bgr_dup(unsigned int r, unsigned int g,
1010 unsigned int b)
1011{
1012 unsigned int col;
1013 col = rgb_to_pixel15bgr(r, g, b);
1014 col |= col << 16;
1015 return col;
1016}
1017
17b0018b
FB
1018static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
1019{
1020 unsigned int col;
1021 col = rgb_to_pixel16(r, g, b);
1022 col |= col << 16;
1023 return col;
1024}
1025
b29169d2
BS
1026static unsigned int rgb_to_pixel16bgr_dup(unsigned int r, unsigned int g,
1027 unsigned int b)
1028{
1029 unsigned int col;
1030 col = rgb_to_pixel16bgr(r, g, b);
1031 col |= col << 16;
1032 return col;
1033}
1034
17b0018b
FB
1035static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
1036{
1037 unsigned int col;
1038 col = rgb_to_pixel32(r, g, b);
1039 return col;
1040}
1041
d3079cd2
FB
1042static unsigned int rgb_to_pixel32bgr_dup(unsigned int r, unsigned int g, unsigned b)
1043{
1044 unsigned int col;
1045 col = rgb_to_pixel32bgr(r, g, b);
1046 return col;
1047}
1048
e89f66ec
FB
1049/* return true if the palette was modified */
1050static int update_palette16(VGAState *s)
1051{
17b0018b 1052 int full_update, i;
e89f66ec 1053 uint32_t v, col, *palette;
e89f66ec
FB
1054
1055 full_update = 0;
1056 palette = s->last_palette;
1057 for(i = 0; i < 16; i++) {
1058 v = s->ar[i];
1059 if (s->ar[0x10] & 0x80)
1060 v = ((s->ar[0x14] & 0xf) << 4) | (v & 0xf);
1061 else
1062 v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f);
1063 v = v * 3;
5fafdf24
TS
1064 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
1065 c6_to_8(s->palette[v + 1]),
17b0018b
FB
1066 c6_to_8(s->palette[v + 2]));
1067 if (col != palette[i]) {
1068 full_update = 1;
1069 palette[i] = col;
e89f66ec 1070 }
17b0018b
FB
1071 }
1072 return full_update;
1073}
1074
1075/* return true if the palette was modified */
1076static int update_palette256(VGAState *s)
1077{
1078 int full_update, i;
1079 uint32_t v, col, *palette;
1080
1081 full_update = 0;
1082 palette = s->last_palette;
1083 v = 0;
1084 for(i = 0; i < 256; i++) {
37dd208d 1085 if (s->dac_8bit) {
5fafdf24
TS
1086 col = s->rgb_to_pixel(s->palette[v],
1087 s->palette[v + 1],
37dd208d
FB
1088 s->palette[v + 2]);
1089 } else {
5fafdf24
TS
1090 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
1091 c6_to_8(s->palette[v + 1]),
37dd208d
FB
1092 c6_to_8(s->palette[v + 2]));
1093 }
e89f66ec
FB
1094 if (col != palette[i]) {
1095 full_update = 1;
1096 palette[i] = col;
1097 }
17b0018b 1098 v += 3;
e89f66ec
FB
1099 }
1100 return full_update;
1101}
1102
5fafdf24
TS
1103static void vga_get_offsets(VGAState *s,
1104 uint32_t *pline_offset,
83acc96b
FB
1105 uint32_t *pstart_addr,
1106 uint32_t *pline_compare)
e89f66ec 1107{
83acc96b 1108 uint32_t start_addr, line_offset, line_compare;
4fa0f5d2
FB
1109#ifdef CONFIG_BOCHS_VBE
1110 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1111 line_offset = s->vbe_line_offset;
1112 start_addr = s->vbe_start_addr;
83acc96b 1113 line_compare = 65535;
4fa0f5d2
FB
1114 } else
1115#endif
3b46e624 1116 {
4fa0f5d2
FB
1117 /* compute line_offset in bytes */
1118 line_offset = s->cr[0x13];
4fa0f5d2 1119 line_offset <<= 3;
08e48902 1120
4fa0f5d2
FB
1121 /* starting address */
1122 start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8);
83acc96b
FB
1123
1124 /* line compare */
5fafdf24 1125 line_compare = s->cr[0x18] |
83acc96b
FB
1126 ((s->cr[0x07] & 0x10) << 4) |
1127 ((s->cr[0x09] & 0x40) << 3);
4fa0f5d2 1128 }
798b0c25
FB
1129 *pline_offset = line_offset;
1130 *pstart_addr = start_addr;
83acc96b 1131 *pline_compare = line_compare;
798b0c25
FB
1132}
1133
1134/* update start_addr and line_offset. Return TRUE if modified */
1135static int update_basic_params(VGAState *s)
1136{
1137 int full_update;
1138 uint32_t start_addr, line_offset, line_compare;
3b46e624 1139
798b0c25
FB
1140 full_update = 0;
1141
83acc96b 1142 s->get_offsets(s, &line_offset, &start_addr, &line_compare);
e89f66ec
FB
1143
1144 if (line_offset != s->line_offset ||
1145 start_addr != s->start_addr ||
1146 line_compare != s->line_compare) {
1147 s->line_offset = line_offset;
1148 s->start_addr = start_addr;
1149 s->line_compare = line_compare;
1150 full_update = 1;
1151 }
1152 return full_update;
1153}
1154
b29169d2 1155#define NB_DEPTHS 7
d3079cd2
FB
1156
1157static inline int get_depth_index(DisplayState *s)
e89f66ec 1158{
0e1f5a0c 1159 switch(ds_get_bits_per_pixel(s)) {
e89f66ec
FB
1160 default:
1161 case 8:
1162 return 0;
1163 case 15:
8927bcfd 1164 return 1;
e89f66ec 1165 case 16:
8927bcfd 1166 return 2;
e89f66ec 1167 case 32:
7b5d76da
AL
1168 if (is_surface_bgr(s->surface))
1169 return 4;
1170 else
1171 return 3;
e89f66ec
FB
1172 }
1173}
1174
d3079cd2 1175static vga_draw_glyph8_func *vga_draw_glyph8_table[NB_DEPTHS] = {
e89f66ec
FB
1176 vga_draw_glyph8_8,
1177 vga_draw_glyph8_16,
1178 vga_draw_glyph8_16,
1179 vga_draw_glyph8_32,
d3079cd2 1180 vga_draw_glyph8_32,
b29169d2
BS
1181 vga_draw_glyph8_16,
1182 vga_draw_glyph8_16,
e89f66ec
FB
1183};
1184
d3079cd2 1185static vga_draw_glyph8_func *vga_draw_glyph16_table[NB_DEPTHS] = {
17b0018b
FB
1186 vga_draw_glyph16_8,
1187 vga_draw_glyph16_16,
1188 vga_draw_glyph16_16,
1189 vga_draw_glyph16_32,
d3079cd2 1190 vga_draw_glyph16_32,
b29169d2
BS
1191 vga_draw_glyph16_16,
1192 vga_draw_glyph16_16,
17b0018b
FB
1193};
1194
d3079cd2 1195static vga_draw_glyph9_func *vga_draw_glyph9_table[NB_DEPTHS] = {
e89f66ec
FB
1196 vga_draw_glyph9_8,
1197 vga_draw_glyph9_16,
1198 vga_draw_glyph9_16,
1199 vga_draw_glyph9_32,
d3079cd2 1200 vga_draw_glyph9_32,
b29169d2
BS
1201 vga_draw_glyph9_16,
1202 vga_draw_glyph9_16,
e89f66ec 1203};
3b46e624 1204
e89f66ec
FB
1205static const uint8_t cursor_glyph[32 * 4] = {
1206 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1207 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1208 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1209 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1210 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1211 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1212 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1213 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1214 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1215 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1216 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1217 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1218 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1219 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1220 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1221 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
3b46e624 1222};
e89f66ec 1223
4c5e8c5c
BS
1224static void vga_get_text_resolution(VGAState *s, int *pwidth, int *pheight,
1225 int *pcwidth, int *pcheight)
1226{
1227 int width, cwidth, height, cheight;
1228
1229 /* total width & height */
1230 cheight = (s->cr[9] & 0x1f) + 1;
1231 cwidth = 8;
1232 if (!(s->sr[1] & 0x01))
1233 cwidth = 9;
1234 if (s->sr[1] & 0x08)
1235 cwidth = 16; /* NOTE: no 18 pixel wide */
1236 width = (s->cr[0x01] + 1);
1237 if (s->cr[0x06] == 100) {
1238 /* ugly hack for CGA 160x100x16 - explain me the logic */
1239 height = 100;
1240 } else {
1241 height = s->cr[0x12] |
1242 ((s->cr[0x07] & 0x02) << 7) |
1243 ((s->cr[0x07] & 0x40) << 3);
1244 height = (height + 1) / cheight;
1245 }
1246
1247 *pwidth = width;
1248 *pheight = height;
1249 *pcwidth = cwidth;
1250 *pcheight = cheight;
1251}
1252
7d957bd8
AL
1253typedef unsigned int rgb_to_pixel_dup_func(unsigned int r, unsigned int g, unsigned b);
1254
bdb19571
AL
1255static rgb_to_pixel_dup_func *rgb_to_pixel_dup_table[NB_DEPTHS] = {
1256 rgb_to_pixel8_dup,
1257 rgb_to_pixel15_dup,
1258 rgb_to_pixel16_dup,
1259 rgb_to_pixel32_dup,
1260 rgb_to_pixel32bgr_dup,
1261 rgb_to_pixel15bgr_dup,
1262 rgb_to_pixel16bgr_dup,
1263};
7d957bd8 1264
5fafdf24
TS
1265/*
1266 * Text mode update
e89f66ec
FB
1267 * Missing:
1268 * - double scan
5fafdf24 1269 * - double width
e89f66ec
FB
1270 * - underline
1271 * - flashing
1272 */
1273static void vga_draw_text(VGAState *s, int full_update)
1274{
1275 int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
1276 int cx_min, cx_max, linesize, x_incr;
1277 uint32_t offset, fgcol, bgcol, v, cursor_offset;
1278 uint8_t *d1, *d, *src, *s1, *dest, *cursor_ptr;
1279 const uint8_t *font_ptr, *font_base[2];
1280 int dup9, line_offset, depth_index;
1281 uint32_t *palette;
1282 uint32_t *ch_attr_ptr;
1283 vga_draw_glyph8_func *vga_draw_glyph8;
1284 vga_draw_glyph9_func *vga_draw_glyph9;
1285
e89f66ec
FB
1286 /* compute font data address (in plane 2) */
1287 v = s->sr[3];
1078f663 1288 offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
e89f66ec
FB
1289 if (offset != s->font_offsets[0]) {
1290 s->font_offsets[0] = offset;
1291 full_update = 1;
1292 }
1293 font_base[0] = s->vram_ptr + offset;
1294
1078f663 1295 offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
e89f66ec
FB
1296 font_base[1] = s->vram_ptr + offset;
1297 if (offset != s->font_offsets[1]) {
1298 s->font_offsets[1] = offset;
1299 full_update = 1;
1300 }
546fa6ab
FB
1301 if (s->plane_updated & (1 << 2)) {
1302 /* if the plane 2 was modified since the last display, it
1303 indicates the font may have been modified */
1304 s->plane_updated = 0;
1305 full_update = 1;
1306 }
799e709b 1307 full_update |= update_basic_params(s);
e89f66ec
FB
1308
1309 line_offset = s->line_offset;
1310 s1 = s->vram_ptr + (s->start_addr * 4);
1311
4c5e8c5c 1312 vga_get_text_resolution(s, &width, &height, &cw, &cheight);
0e1f5a0c 1313 x_incr = cw * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
3294b949
FB
1314 if ((height * width) > CH_ATTR_SIZE) {
1315 /* better than nothing: exit if transient size is too big */
1316 return;
1317 }
1318
799e709b
AL
1319 if (width != s->last_width || height != s->last_height ||
1320 cw != s->last_cw || cheight != s->last_ch || s->last_depth) {
1321 s->last_scr_width = width * cw;
1322 s->last_scr_height = height * cheight;
1323 qemu_console_resize(s->ds, s->last_scr_width, s->last_scr_height);
1324 s->last_depth = 0;
1325 s->last_width = width;
1326 s->last_height = height;
1327 s->last_ch = cheight;
1328 s->last_cw = cw;
1329 full_update = 1;
1330 }
7d957bd8
AL
1331 s->rgb_to_pixel =
1332 rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1333 full_update |= update_palette16(s);
1334 palette = s->last_palette;
1335 x_incr = cw * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
1336
e89f66ec
FB
1337 cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
1338 if (cursor_offset != s->cursor_offset ||
1339 s->cr[0xa] != s->cursor_start ||
1340 s->cr[0xb] != s->cursor_end) {
1341 /* if the cursor position changed, we update the old and new
1342 chars */
1343 if (s->cursor_offset < CH_ATTR_SIZE)
1344 s->last_ch_attr[s->cursor_offset] = -1;
1345 if (cursor_offset < CH_ATTR_SIZE)
1346 s->last_ch_attr[cursor_offset] = -1;
1347 s->cursor_offset = cursor_offset;
1348 s->cursor_start = s->cr[0xa];
1349 s->cursor_end = s->cr[0xb];
1350 }
39cf7803 1351 cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
3b46e624 1352
d3079cd2 1353 depth_index = get_depth_index(s->ds);
17b0018b
FB
1354 if (cw == 16)
1355 vga_draw_glyph8 = vga_draw_glyph16_table[depth_index];
1356 else
1357 vga_draw_glyph8 = vga_draw_glyph8_table[depth_index];
e89f66ec 1358 vga_draw_glyph9 = vga_draw_glyph9_table[depth_index];
3b46e624 1359
0e1f5a0c
AL
1360 dest = ds_get_data(s->ds);
1361 linesize = ds_get_linesize(s->ds);
e89f66ec
FB
1362 ch_attr_ptr = s->last_ch_attr;
1363 for(cy = 0; cy < height; cy++) {
1364 d1 = dest;
1365 src = s1;
1366 cx_min = width;
1367 cx_max = -1;
1368 for(cx = 0; cx < width; cx++) {
1369 ch_attr = *(uint16_t *)src;
1370 if (full_update || ch_attr != *ch_attr_ptr) {
1371 if (cx < cx_min)
1372 cx_min = cx;
1373 if (cx > cx_max)
1374 cx_max = cx;
1375 *ch_attr_ptr = ch_attr;
e2542fe2 1376#ifdef HOST_WORDS_BIGENDIAN
e89f66ec
FB
1377 ch = ch_attr >> 8;
1378 cattr = ch_attr & 0xff;
1379#else
1380 ch = ch_attr & 0xff;
1381 cattr = ch_attr >> 8;
1382#endif
1383 font_ptr = font_base[(cattr >> 3) & 1];
1384 font_ptr += 32 * 4 * ch;
1385 bgcol = palette[cattr >> 4];
1386 fgcol = palette[cattr & 0x0f];
17b0018b 1387 if (cw != 9) {
5fafdf24 1388 vga_draw_glyph8(d1, linesize,
e89f66ec
FB
1389 font_ptr, cheight, fgcol, bgcol);
1390 } else {
1391 dup9 = 0;
1392 if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))
1393 dup9 = 1;
5fafdf24 1394 vga_draw_glyph9(d1, linesize,
e89f66ec
FB
1395 font_ptr, cheight, fgcol, bgcol, dup9);
1396 }
1397 if (src == cursor_ptr &&
1398 !(s->cr[0x0a] & 0x20)) {
1399 int line_start, line_last, h;
1400 /* draw the cursor */
1401 line_start = s->cr[0x0a] & 0x1f;
1402 line_last = s->cr[0x0b] & 0x1f;
1403 /* XXX: check that */
1404 if (line_last > cheight - 1)
1405 line_last = cheight - 1;
1406 if (line_last >= line_start && line_start < cheight) {
1407 h = line_last - line_start + 1;
1408 d = d1 + linesize * line_start;
17b0018b 1409 if (cw != 9) {
5fafdf24 1410 vga_draw_glyph8(d, linesize,
e89f66ec
FB
1411 cursor_glyph, h, fgcol, bgcol);
1412 } else {
5fafdf24 1413 vga_draw_glyph9(d, linesize,
e89f66ec
FB
1414 cursor_glyph, h, fgcol, bgcol, 1);
1415 }
1416 }
1417 }
1418 }
1419 d1 += x_incr;
1420 src += 4;
1421 ch_attr_ptr++;
1422 }
1423 if (cx_max != -1) {
5fafdf24 1424 dpy_update(s->ds, cx_min * cw, cy * cheight,
e89f66ec
FB
1425 (cx_max - cx_min + 1) * cw, cheight);
1426 }
1427 dest += linesize * cheight;
1428 s1 += line_offset;
1429 }
1430}
1431
17b0018b
FB
1432enum {
1433 VGA_DRAW_LINE2,
1434 VGA_DRAW_LINE2D2,
1435 VGA_DRAW_LINE4,
1436 VGA_DRAW_LINE4D2,
1437 VGA_DRAW_LINE8D2,
1438 VGA_DRAW_LINE8,
1439 VGA_DRAW_LINE15,
1440 VGA_DRAW_LINE16,
4fa0f5d2 1441 VGA_DRAW_LINE24,
17b0018b
FB
1442 VGA_DRAW_LINE32,
1443 VGA_DRAW_LINE_NB,
1444};
1445
d3079cd2 1446static vga_draw_line_func *vga_draw_line_table[NB_DEPTHS * VGA_DRAW_LINE_NB] = {
e89f66ec
FB
1447 vga_draw_line2_8,
1448 vga_draw_line2_16,
1449 vga_draw_line2_16,
1450 vga_draw_line2_32,
d3079cd2 1451 vga_draw_line2_32,
b29169d2
BS
1452 vga_draw_line2_16,
1453 vga_draw_line2_16,
e89f66ec 1454
17b0018b
FB
1455 vga_draw_line2d2_8,
1456 vga_draw_line2d2_16,
1457 vga_draw_line2d2_16,
1458 vga_draw_line2d2_32,
d3079cd2 1459 vga_draw_line2d2_32,
b29169d2
BS
1460 vga_draw_line2d2_16,
1461 vga_draw_line2d2_16,
17b0018b 1462
e89f66ec
FB
1463 vga_draw_line4_8,
1464 vga_draw_line4_16,
1465 vga_draw_line4_16,
1466 vga_draw_line4_32,
d3079cd2 1467 vga_draw_line4_32,
b29169d2
BS
1468 vga_draw_line4_16,
1469 vga_draw_line4_16,
e89f66ec 1470
17b0018b
FB
1471 vga_draw_line4d2_8,
1472 vga_draw_line4d2_16,
1473 vga_draw_line4d2_16,
1474 vga_draw_line4d2_32,
d3079cd2 1475 vga_draw_line4d2_32,
b29169d2
BS
1476 vga_draw_line4d2_16,
1477 vga_draw_line4d2_16,
17b0018b
FB
1478
1479 vga_draw_line8d2_8,
1480 vga_draw_line8d2_16,
1481 vga_draw_line8d2_16,
1482 vga_draw_line8d2_32,
d3079cd2 1483 vga_draw_line8d2_32,
b29169d2
BS
1484 vga_draw_line8d2_16,
1485 vga_draw_line8d2_16,
17b0018b 1486
e89f66ec
FB
1487 vga_draw_line8_8,
1488 vga_draw_line8_16,
1489 vga_draw_line8_16,
1490 vga_draw_line8_32,
d3079cd2 1491 vga_draw_line8_32,
b29169d2
BS
1492 vga_draw_line8_16,
1493 vga_draw_line8_16,
e89f66ec
FB
1494
1495 vga_draw_line15_8,
1496 vga_draw_line15_15,
1497 vga_draw_line15_16,
1498 vga_draw_line15_32,
d3079cd2 1499 vga_draw_line15_32bgr,
b29169d2
BS
1500 vga_draw_line15_15bgr,
1501 vga_draw_line15_16bgr,
e89f66ec
FB
1502
1503 vga_draw_line16_8,
1504 vga_draw_line16_15,
1505 vga_draw_line16_16,
1506 vga_draw_line16_32,
d3079cd2 1507 vga_draw_line16_32bgr,
b29169d2
BS
1508 vga_draw_line16_15bgr,
1509 vga_draw_line16_16bgr,
e89f66ec 1510
4fa0f5d2
FB
1511 vga_draw_line24_8,
1512 vga_draw_line24_15,
1513 vga_draw_line24_16,
1514 vga_draw_line24_32,
d3079cd2 1515 vga_draw_line24_32bgr,
b29169d2
BS
1516 vga_draw_line24_15bgr,
1517 vga_draw_line24_16bgr,
4fa0f5d2 1518
e89f66ec
FB
1519 vga_draw_line32_8,
1520 vga_draw_line32_15,
1521 vga_draw_line32_16,
1522 vga_draw_line32_32,
d3079cd2 1523 vga_draw_line32_32bgr,
b29169d2
BS
1524 vga_draw_line32_15bgr,
1525 vga_draw_line32_16bgr,
d3079cd2
FB
1526};
1527
798b0c25
FB
1528static int vga_get_bpp(VGAState *s)
1529{
1530 int ret;
1531#ifdef CONFIG_BOCHS_VBE
1532 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1533 ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
5fafdf24 1534 } else
798b0c25
FB
1535#endif
1536 {
1537 ret = 0;
1538 }
1539 return ret;
1540}
1541
a130a41e
FB
1542static void vga_get_resolution(VGAState *s, int *pwidth, int *pheight)
1543{
1544 int width, height;
3b46e624 1545
8454df8b
FB
1546#ifdef CONFIG_BOCHS_VBE
1547 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1548 width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
1549 height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
5fafdf24 1550 } else
8454df8b
FB
1551#endif
1552 {
1553 width = (s->cr[0x01] + 1) * 8;
5fafdf24
TS
1554 height = s->cr[0x12] |
1555 ((s->cr[0x07] & 0x02) << 7) |
8454df8b
FB
1556 ((s->cr[0x07] & 0x40) << 3);
1557 height = (height + 1);
1558 }
a130a41e
FB
1559 *pwidth = width;
1560 *pheight = height;
1561}
1562
a8aa669b
FB
1563void vga_invalidate_scanlines(VGAState *s, int y1, int y2)
1564{
1565 int y;
1566 if (y1 >= VGA_MAX_HEIGHT)
1567 return;
1568 if (y2 >= VGA_MAX_HEIGHT)
1569 y2 = VGA_MAX_HEIGHT;
1570 for(y = y1; y < y2; y++) {
1571 s->invalidated_y_table[y >> 5] |= 1 << (y & 0x1f);
1572 }
1573}
1574
2bec46dc
AL
1575static void vga_sync_dirty_bitmap(VGAState *s)
1576{
1577 if (s->map_addr)
1578 cpu_physical_sync_dirty_bitmap(s->map_addr, s->map_end);
1579
1580 if (s->lfb_vram_mapped) {
1581 cpu_physical_sync_dirty_bitmap(isa_mem_base + 0xa0000, 0xa8000);
1582 cpu_physical_sync_dirty_bitmap(isa_mem_base + 0xa8000, 0xb0000);
1583 }
2bec46dc
AL
1584}
1585
799e709b
AL
1586/*
1587 * graphic modes
1588 */
1589static void vga_draw_graphic(VGAState *s, int full_update)
e89f66ec 1590{
12c7e75a
AK
1591 int y1, y, update, linesize, y_start, double_scan, mask, depth;
1592 int width, height, shift_control, line_offset, bwidth, bits;
1593 ram_addr_t page0, page1, page_min, page_max;
a07cf92a 1594 int disp_width, multi_scan, multi_run;
799e709b
AL
1595 uint8_t *d;
1596 uint32_t v, addr1, addr;
1597 vga_draw_line_func *vga_draw_line;
1598
1599 full_update |= update_basic_params(s);
1600
1601 if (!full_update)
1602 vga_sync_dirty_bitmap(s);
2bec46dc 1603
a130a41e 1604 s->get_resolution(s, &width, &height);
17b0018b 1605 disp_width = width;
09a79b49 1606
e89f66ec 1607 shift_control = (s->gr[0x05] >> 5) & 3;
f6c958c8 1608 double_scan = (s->cr[0x09] >> 7);
799e709b
AL
1609 if (shift_control != 1) {
1610 multi_scan = (((s->cr[0x09] & 0x1f) + 1) << double_scan) - 1;
1611 } else {
1612 /* in CGA modes, multi_scan is ignored */
1613 /* XXX: is it correct ? */
1614 multi_scan = double_scan;
1615 }
1616 multi_run = multi_scan;
17b0018b
FB
1617 if (shift_control != s->shift_control ||
1618 double_scan != s->double_scan) {
799e709b 1619 full_update = 1;
e89f66ec 1620 s->shift_control = shift_control;
17b0018b 1621 s->double_scan = double_scan;
e89f66ec 1622 }
3b46e624 1623
aba35a6c 1624 if (shift_control == 0) {
1625 if (s->sr[0x01] & 8) {
1626 disp_width <<= 1;
1627 }
1628 } else if (shift_control == 1) {
1629 if (s->sr[0x01] & 8) {
1630 disp_width <<= 1;
1631 }
1632 }
1633
799e709b 1634 depth = s->get_bpp(s);
e3697092
AJ
1635 if (s->line_offset != s->last_line_offset ||
1636 disp_width != s->last_width ||
1637 height != s->last_height ||
799e709b 1638 s->last_depth != depth) {
e2542fe2 1639#if defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
e3697092 1640 if (depth == 16 || depth == 32) {
0da2ea1b 1641#else
1642 if (depth == 32) {
1643#endif
b8c18e4c
AL
1644 qemu_free_displaysurface(s->ds);
1645 s->ds->surface = qemu_create_displaysurface_from(disp_width, height, depth,
1646 s->line_offset,
1647 s->vram_ptr + (s->start_addr * 4));
e2542fe2 1648#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
b8c18e4c 1649 s->ds->surface->pf = qemu_different_endianness_pixelformat(depth);
0da2ea1b 1650#endif
b8c18e4c 1651 dpy_resize(s->ds);
e3697092
AJ
1652 } else {
1653 qemu_console_resize(s->ds, disp_width, height);
1654 }
1655 s->last_scr_width = disp_width;
1656 s->last_scr_height = height;
1657 s->last_width = disp_width;
1658 s->last_height = height;
1659 s->last_line_offset = s->line_offset;
1660 s->last_depth = depth;
799e709b
AL
1661 full_update = 1;
1662 } else if (is_buffer_shared(s->ds->surface) &&
e3697092
AJ
1663 (full_update || s->ds->surface->data != s->vram_ptr + (s->start_addr * 4))) {
1664 s->ds->surface->data = s->vram_ptr + (s->start_addr * 4);
1665 dpy_setdata(s->ds);
1666 }
1667
1668 s->rgb_to_pixel =
1669 rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1670
799e709b 1671 if (shift_control == 0) {
17b0018b
FB
1672 full_update |= update_palette16(s);
1673 if (s->sr[0x01] & 8) {
1674 v = VGA_DRAW_LINE4D2;
17b0018b
FB
1675 } else {
1676 v = VGA_DRAW_LINE4;
1677 }
15342721 1678 bits = 4;
799e709b 1679 } else if (shift_control == 1) {
17b0018b
FB
1680 full_update |= update_palette16(s);
1681 if (s->sr[0x01] & 8) {
1682 v = VGA_DRAW_LINE2D2;
17b0018b
FB
1683 } else {
1684 v = VGA_DRAW_LINE2;
1685 }
15342721 1686 bits = 4;
17b0018b 1687 } else {
798b0c25
FB
1688 switch(s->get_bpp(s)) {
1689 default:
1690 case 0:
4fa0f5d2
FB
1691 full_update |= update_palette256(s);
1692 v = VGA_DRAW_LINE8D2;
15342721 1693 bits = 4;
798b0c25
FB
1694 break;
1695 case 8:
1696 full_update |= update_palette256(s);
1697 v = VGA_DRAW_LINE8;
15342721 1698 bits = 8;
798b0c25
FB
1699 break;
1700 case 15:
1701 v = VGA_DRAW_LINE15;
15342721 1702 bits = 16;
798b0c25
FB
1703 break;
1704 case 16:
1705 v = VGA_DRAW_LINE16;
15342721 1706 bits = 16;
798b0c25
FB
1707 break;
1708 case 24:
1709 v = VGA_DRAW_LINE24;
15342721 1710 bits = 24;
798b0c25
FB
1711 break;
1712 case 32:
1713 v = VGA_DRAW_LINE32;
15342721 1714 bits = 32;
798b0c25 1715 break;
4fa0f5d2 1716 }
17b0018b 1717 }
d3079cd2 1718 vga_draw_line = vga_draw_line_table[v * NB_DEPTHS + get_depth_index(s->ds)];
17b0018b 1719
7d957bd8 1720 if (!is_buffer_shared(s->ds->surface) && s->cursor_invalidate)
a8aa669b 1721 s->cursor_invalidate(s);
3b46e624 1722
e89f66ec 1723 line_offset = s->line_offset;
17b0018b 1724#if 0
f6c958c8 1725 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",
17b0018b
FB
1726 width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]);
1727#endif
e89f66ec 1728 addr1 = (s->start_addr * 4);
15342721 1729 bwidth = (width * bits + 7) / 8;
39cf7803 1730 y_start = -1;
12c7e75a
AK
1731 page_min = -1;
1732 page_max = 0;
0e1f5a0c
AL
1733 d = ds_get_data(s->ds);
1734 linesize = ds_get_linesize(s->ds);
17b0018b 1735 y1 = 0;
e89f66ec
FB
1736 for(y = 0; y < height; y++) {
1737 addr = addr1;
39cf7803 1738 if (!(s->cr[0x17] & 1)) {
17b0018b 1739 int shift;
e89f66ec 1740 /* CGA compatibility handling */
17b0018b
FB
1741 shift = 14 + ((s->cr[0x17] >> 6) & 1);
1742 addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
e89f66ec 1743 }
39cf7803 1744 if (!(s->cr[0x17] & 2)) {
17b0018b 1745 addr = (addr & ~0x8000) | ((y1 & 2) << 14);
e89f66ec 1746 }
4fa0f5d2
FB
1747 page0 = s->vram_offset + (addr & TARGET_PAGE_MASK);
1748 page1 = s->vram_offset + ((addr + bwidth - 1) & TARGET_PAGE_MASK);
5fafdf24 1749 update = full_update |
0a962c02
FB
1750 cpu_physical_memory_get_dirty(page0, VGA_DIRTY_FLAG) |
1751 cpu_physical_memory_get_dirty(page1, VGA_DIRTY_FLAG);
4fa0f5d2 1752 if ((page1 - page0) > TARGET_PAGE_SIZE) {
39cf7803 1753 /* if wide line, can use another page */
5fafdf24 1754 update |= cpu_physical_memory_get_dirty(page0 + TARGET_PAGE_SIZE,
0a962c02 1755 VGA_DIRTY_FLAG);
39cf7803 1756 }
a8aa669b
FB
1757 /* explicit invalidation for the hardware cursor */
1758 update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
e89f66ec 1759 if (update) {
39cf7803
FB
1760 if (y_start < 0)
1761 y_start = y;
e89f66ec
FB
1762 if (page0 < page_min)
1763 page_min = page0;
1764 if (page1 > page_max)
1765 page_max = page1;
7d957bd8
AL
1766 if (!(is_buffer_shared(s->ds->surface))) {
1767 vga_draw_line(s, d, s->vram_ptr + addr, width);
1768 if (s->cursor_draw_line)
1769 s->cursor_draw_line(s, d, y);
1770 }
39cf7803
FB
1771 } else {
1772 if (y_start >= 0) {
1773 /* flush to display */
5fafdf24 1774 dpy_update(s->ds, 0, y_start,
799e709b 1775 disp_width, y - y_start);
39cf7803
FB
1776 y_start = -1;
1777 }
e89f66ec 1778 }
a07cf92a 1779 if (!multi_run) {
f6c958c8
FB
1780 mask = (s->cr[0x17] & 3) ^ 3;
1781 if ((y1 & mask) == mask)
1782 addr1 += line_offset;
1783 y1++;
799e709b 1784 multi_run = multi_scan;
a07cf92a
FB
1785 } else {
1786 multi_run--;
e89f66ec 1787 }
f6c958c8
FB
1788 /* line compare acts on the displayed lines */
1789 if (y == s->line_compare)
1790 addr1 = 0;
e89f66ec
FB
1791 d += linesize;
1792 }
39cf7803
FB
1793 if (y_start >= 0) {
1794 /* flush to display */
5fafdf24 1795 dpy_update(s->ds, 0, y_start,
799e709b 1796 disp_width, y - y_start);
39cf7803 1797 }
e89f66ec 1798 /* reset modified pages */
12c7e75a 1799 if (page_max >= page_min) {
0a962c02
FB
1800 cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
1801 VGA_DIRTY_FLAG);
e89f66ec 1802 }
a8aa669b 1803 memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
e89f66ec
FB
1804}
1805
2aebb3eb
FB
1806static void vga_draw_blank(VGAState *s, int full_update)
1807{
1808 int i, w, val;
1809 uint8_t *d;
1810
1811 if (!full_update)
1812 return;
1813 if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
1814 return;
2bec46dc 1815
7d957bd8
AL
1816 s->rgb_to_pixel =
1817 rgb_to_pixel_dup_table[get_depth_index(s->ds)];
0e1f5a0c 1818 if (ds_get_bits_per_pixel(s->ds) == 8)
2aebb3eb
FB
1819 val = s->rgb_to_pixel(0, 0, 0);
1820 else
1821 val = 0;
0e1f5a0c
AL
1822 w = s->last_scr_width * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
1823 d = ds_get_data(s->ds);
2aebb3eb
FB
1824 for(i = 0; i < s->last_scr_height; i++) {
1825 memset(d, val, w);
0e1f5a0c 1826 d += ds_get_linesize(s->ds);
2aebb3eb 1827 }
5fafdf24 1828 dpy_update(s->ds, 0, 0,
2aebb3eb
FB
1829 s->last_scr_width, s->last_scr_height);
1830}
1831
799e709b
AL
1832#define GMODE_TEXT 0
1833#define GMODE_GRAPH 1
1834#define GMODE_BLANK 2
1835
95219897 1836static void vga_update_display(void *opaque)
e89f66ec 1837{
1a5ab757 1838 VGAState *s = opaque;
799e709b 1839 int full_update, graphic_mode;
e89f66ec 1840
0e1f5a0c 1841 if (ds_get_bits_per_pixel(s->ds) == 0) {
0f35920c 1842 /* nothing to do */
59a983b9 1843 } else {
0bd8246b
SS
1844 full_update = s->full_update;
1845 s->full_update = 0;
799e709b
AL
1846 if (!(s->ar_index & 0x20)) {
1847 graphic_mode = GMODE_BLANK;
1848 } else {
1849 graphic_mode = s->gr[6] & 1;
1850 }
1851 if (graphic_mode != s->graphic_mode) {
1852 s->graphic_mode = graphic_mode;
1853 full_update = 1;
1854 }
1855 switch(graphic_mode) {
2aebb3eb 1856 case GMODE_TEXT:
e89f66ec 1857 vga_draw_text(s, full_update);
2aebb3eb
FB
1858 break;
1859 case GMODE_GRAPH:
1860 vga_draw_graphic(s, full_update);
1861 break;
1862 case GMODE_BLANK:
1863 default:
1864 vga_draw_blank(s, full_update);
1865 break;
1866 }
e89f66ec
FB
1867 }
1868}
1869
a130a41e 1870/* force a full display refresh */
95219897 1871static void vga_invalidate_display(void *opaque)
a130a41e 1872{
1a5ab757 1873 VGAState *s = opaque;
3b46e624 1874
0bd8246b 1875 s->full_update = 1;
a130a41e
FB
1876}
1877
03a3e7ba 1878void vga_common_reset(VGACommonState *s)
e89f66ec 1879{
6e6b7363
BS
1880 s->lfb_addr = 0;
1881 s->lfb_end = 0;
1882 s->map_addr = 0;
1883 s->map_end = 0;
1884 s->lfb_vram_mapped = 0;
1885 s->bios_offset = 0;
1886 s->bios_size = 0;
1887 s->sr_index = 0;
1888 memset(s->sr, '\0', sizeof(s->sr));
1889 s->gr_index = 0;
1890 memset(s->gr, '\0', sizeof(s->gr));
1891 s->ar_index = 0;
1892 memset(s->ar, '\0', sizeof(s->ar));
1893 s->ar_flip_flop = 0;
1894 s->cr_index = 0;
1895 memset(s->cr, '\0', sizeof(s->cr));
1896 s->msr = 0;
1897 s->fcr = 0;
1898 s->st00 = 0;
1899 s->st01 = 0;
1900 s->dac_state = 0;
1901 s->dac_sub_index = 0;
1902 s->dac_read_index = 0;
1903 s->dac_write_index = 0;
1904 memset(s->dac_cache, '\0', sizeof(s->dac_cache));
1905 s->dac_8bit = 0;
1906 memset(s->palette, '\0', sizeof(s->palette));
1907 s->bank_offset = 0;
1908#ifdef CONFIG_BOCHS_VBE
1909 s->vbe_index = 0;
1910 memset(s->vbe_regs, '\0', sizeof(s->vbe_regs));
1911 s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0;
1912 s->vbe_start_addr = 0;
1913 s->vbe_line_offset = 0;
1914 s->vbe_bank_mask = (s->vram_size >> 16) - 1;
1915#endif
1916 memset(s->font_offsets, '\0', sizeof(s->font_offsets));
799e709b 1917 s->graphic_mode = -1; /* force full update */
6e6b7363
BS
1918 s->shift_control = 0;
1919 s->double_scan = 0;
1920 s->line_offset = 0;
1921 s->line_compare = 0;
1922 s->start_addr = 0;
1923 s->plane_updated = 0;
1924 s->last_cw = 0;
1925 s->last_ch = 0;
1926 s->last_width = 0;
1927 s->last_height = 0;
1928 s->last_scr_width = 0;
1929 s->last_scr_height = 0;
1930 s->cursor_start = 0;
1931 s->cursor_end = 0;
1932 s->cursor_offset = 0;
1933 memset(s->invalidated_y_table, '\0', sizeof(s->invalidated_y_table));
1934 memset(s->last_palette, '\0', sizeof(s->last_palette));
1935 memset(s->last_ch_attr, '\0', sizeof(s->last_ch_attr));
1936 switch (vga_retrace_method) {
1937 case VGA_RETRACE_DUMB:
1938 break;
1939 case VGA_RETRACE_PRECISE:
1940 memset(&s->retrace_info, 0, sizeof (s->retrace_info));
1941 break;
1942 }
e89f66ec
FB
1943}
1944
03a3e7ba
JQ
1945static void vga_reset(void *opaque)
1946{
1a5ab757 1947 VGAState *s = opaque;
03a3e7ba
JQ
1948 vga_common_reset(s);
1949}
1950
4d3b6f6e
AZ
1951#define TEXTMODE_X(x) ((x) % width)
1952#define TEXTMODE_Y(x) ((x) / width)
1953#define VMEM2CHTYPE(v) ((v & 0xff0007ff) | \
1954 ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1))
1955/* relay text rendering to the display driver
1956 * instead of doing a full vga_update_display() */
1957static void vga_update_text(void *opaque, console_ch_t *chardata)
1958{
1a5ab757 1959 VGAState *s = opaque;
799e709b 1960 int graphic_mode, i, cursor_offset, cursor_visible;
4d3b6f6e
AZ
1961 int cw, cheight, width, height, size, c_min, c_max;
1962 uint32_t *src;
1963 console_ch_t *dst, val;
1964 char msg_buffer[80];
799e709b
AL
1965 int full_update = 0;
1966
1967 if (!(s->ar_index & 0x20)) {
1968 graphic_mode = GMODE_BLANK;
1969 } else {
1970 graphic_mode = s->gr[6] & 1;
1971 }
1972 if (graphic_mode != s->graphic_mode) {
1973 s->graphic_mode = graphic_mode;
1974 full_update = 1;
1975 }
1976 if (s->last_width == -1) {
1977 s->last_width = 0;
1978 full_update = 1;
1979 }
4d3b6f6e 1980
799e709b 1981 switch (graphic_mode) {
4d3b6f6e
AZ
1982 case GMODE_TEXT:
1983 /* TODO: update palette */
799e709b 1984 full_update |= update_basic_params(s);
4d3b6f6e 1985
799e709b
AL
1986 /* total width & height */
1987 cheight = (s->cr[9] & 0x1f) + 1;
1988 cw = 8;
1989 if (!(s->sr[1] & 0x01))
1990 cw = 9;
1991 if (s->sr[1] & 0x08)
1992 cw = 16; /* NOTE: no 18 pixel wide */
1993 width = (s->cr[0x01] + 1);
1994 if (s->cr[0x06] == 100) {
1995 /* ugly hack for CGA 160x100x16 - explain me the logic */
1996 height = 100;
1997 } else {
1998 height = s->cr[0x12] |
1999 ((s->cr[0x07] & 0x02) << 7) |
2000 ((s->cr[0x07] & 0x40) << 3);
2001 height = (height + 1) / cheight;
4d3b6f6e
AZ
2002 }
2003
2004 size = (height * width);
2005 if (size > CH_ATTR_SIZE) {
2006 if (!full_update)
2007 return;
2008
363a37d5
BS
2009 snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Text mode",
2010 width, height);
4d3b6f6e
AZ
2011 break;
2012 }
2013
799e709b
AL
2014 if (width != s->last_width || height != s->last_height ||
2015 cw != s->last_cw || cheight != s->last_ch) {
2016 s->last_scr_width = width * cw;
2017 s->last_scr_height = height * cheight;
2018 s->ds->surface->width = width;
2019 s->ds->surface->height = height;
2020 dpy_resize(s->ds);
2021 s->last_width = width;
2022 s->last_height = height;
2023 s->last_ch = cheight;
2024 s->last_cw = cw;
2025 full_update = 1;
2026 }
2027
4d3b6f6e
AZ
2028 /* Update "hardware" cursor */
2029 cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
2030 if (cursor_offset != s->cursor_offset ||
2031 s->cr[0xa] != s->cursor_start ||
2032 s->cr[0xb] != s->cursor_end || full_update) {
2033 cursor_visible = !(s->cr[0xa] & 0x20);
2034 if (cursor_visible && cursor_offset < size && cursor_offset >= 0)
2035 dpy_cursor(s->ds,
2036 TEXTMODE_X(cursor_offset),
2037 TEXTMODE_Y(cursor_offset));
2038 else
2039 dpy_cursor(s->ds, -1, -1);
2040 s->cursor_offset = cursor_offset;
2041 s->cursor_start = s->cr[0xa];
2042 s->cursor_end = s->cr[0xb];
2043 }
2044
2045 src = (uint32_t *) s->vram_ptr + s->start_addr;
2046 dst = chardata;
2047
2048 if (full_update) {
2049 for (i = 0; i < size; src ++, dst ++, i ++)
2050 console_write_ch(dst, VMEM2CHTYPE(*src));
2051
2052 dpy_update(s->ds, 0, 0, width, height);
2053 } else {
2054 c_max = 0;
2055
2056 for (i = 0; i < size; src ++, dst ++, i ++) {
2057 console_write_ch(&val, VMEM2CHTYPE(*src));
2058 if (*dst != val) {
2059 *dst = val;
2060 c_max = i;
2061 break;
2062 }
2063 }
2064 c_min = i;
2065 for (; i < size; src ++, dst ++, i ++) {
2066 console_write_ch(&val, VMEM2CHTYPE(*src));
2067 if (*dst != val) {
2068 *dst = val;
2069 c_max = i;
2070 }
2071 }
2072
2073 if (c_min <= c_max) {
2074 i = TEXTMODE_Y(c_min);
2075 dpy_update(s->ds, 0, i, width, TEXTMODE_Y(c_max) - i + 1);
2076 }
2077 }
2078
2079 return;
2080 case GMODE_GRAPH:
2081 if (!full_update)
2082 return;
2083
2084 s->get_resolution(s, &width, &height);
363a37d5
BS
2085 snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Graphic mode",
2086 width, height);
4d3b6f6e
AZ
2087 break;
2088 case GMODE_BLANK:
2089 default:
2090 if (!full_update)
2091 return;
2092
363a37d5 2093 snprintf(msg_buffer, sizeof(msg_buffer), "VGA Blank mode");
4d3b6f6e
AZ
2094 break;
2095 }
2096
2097 /* Display a message */
5228c2d3
AZ
2098 s->last_width = 60;
2099 s->last_height = height = 3;
4d3b6f6e 2100 dpy_cursor(s->ds, -1, -1);
7d957bd8
AL
2101 s->ds->surface->width = s->last_width;
2102 s->ds->surface->height = height;
2103 dpy_resize(s->ds);
4d3b6f6e 2104
5228c2d3 2105 for (dst = chardata, i = 0; i < s->last_width * height; i ++)
4d3b6f6e
AZ
2106 console_write_ch(dst ++, ' ');
2107
2108 size = strlen(msg_buffer);
5228c2d3
AZ
2109 width = (s->last_width - size) / 2;
2110 dst = chardata + s->last_width + width;
4d3b6f6e
AZ
2111 for (i = 0; i < size; i ++)
2112 console_write_ch(dst ++, 0x00200100 | msg_buffer[i]);
2113
5228c2d3 2114 dpy_update(s->ds, 0, 0, s->last_width, height);
4d3b6f6e
AZ
2115}
2116
d60efc6b 2117static CPUReadMemoryFunc * const vga_mem_read[3] = {
e89f66ec
FB
2118 vga_mem_readb,
2119 vga_mem_readw,
2120 vga_mem_readl,
2121};
2122
d60efc6b 2123static CPUWriteMemoryFunc * const vga_mem_write[3] = {
e89f66ec
FB
2124 vga_mem_writeb,
2125 vga_mem_writew,
2126 vga_mem_writel,
2127};
2128
b0a21b53
FB
2129static void vga_save(QEMUFile *f, void *opaque)
2130{
2131 VGAState *s = opaque;
2132 int i;
2133
d2269f6f
FB
2134 if (s->pci_dev)
2135 pci_device_save(s->pci_dev, f);
2136
b0a21b53
FB
2137 qemu_put_be32s(f, &s->latch);
2138 qemu_put_8s(f, &s->sr_index);
2139 qemu_put_buffer(f, s->sr, 8);
2140 qemu_put_8s(f, &s->gr_index);
2141 qemu_put_buffer(f, s->gr, 16);
2142 qemu_put_8s(f, &s->ar_index);
2143 qemu_put_buffer(f, s->ar, 21);
bee8d684 2144 qemu_put_be32(f, s->ar_flip_flop);
b0a21b53
FB
2145 qemu_put_8s(f, &s->cr_index);
2146 qemu_put_buffer(f, s->cr, 256);
2147 qemu_put_8s(f, &s->msr);
2148 qemu_put_8s(f, &s->fcr);
bee8d684 2149 qemu_put_byte(f, s->st00);
b0a21b53
FB
2150 qemu_put_8s(f, &s->st01);
2151
2152 qemu_put_8s(f, &s->dac_state);
2153 qemu_put_8s(f, &s->dac_sub_index);
2154 qemu_put_8s(f, &s->dac_read_index);
2155 qemu_put_8s(f, &s->dac_write_index);
2156 qemu_put_buffer(f, s->dac_cache, 3);
2157 qemu_put_buffer(f, s->palette, 768);
2158
bee8d684 2159 qemu_put_be32(f, s->bank_offset);
b0a21b53
FB
2160#ifdef CONFIG_BOCHS_VBE
2161 qemu_put_byte(f, 1);
2162 qemu_put_be16s(f, &s->vbe_index);
2163 for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
2164 qemu_put_be16s(f, &s->vbe_regs[i]);
2165 qemu_put_be32s(f, &s->vbe_start_addr);
2166 qemu_put_be32s(f, &s->vbe_line_offset);
2167 qemu_put_be32s(f, &s->vbe_bank_mask);
2168#else
2169 qemu_put_byte(f, 0);
2170#endif
2171}
2172
2173static int vga_load(QEMUFile *f, void *opaque, int version_id)
2174{
2175 VGAState *s = opaque;
d2269f6f 2176 int is_vbe, i, ret;
b0a21b53 2177
d2269f6f 2178 if (version_id > 2)
b0a21b53
FB
2179 return -EINVAL;
2180
d2269f6f
FB
2181 if (s->pci_dev && version_id >= 2) {
2182 ret = pci_device_load(s->pci_dev, f);
2183 if (ret < 0)
2184 return ret;
2185 }
2186
b0a21b53
FB
2187 qemu_get_be32s(f, &s->latch);
2188 qemu_get_8s(f, &s->sr_index);
2189 qemu_get_buffer(f, s->sr, 8);
2190 qemu_get_8s(f, &s->gr_index);
2191 qemu_get_buffer(f, s->gr, 16);
2192 qemu_get_8s(f, &s->ar_index);
2193 qemu_get_buffer(f, s->ar, 21);
bee8d684 2194 s->ar_flip_flop=qemu_get_be32(f);
b0a21b53
FB
2195 qemu_get_8s(f, &s->cr_index);
2196 qemu_get_buffer(f, s->cr, 256);
2197 qemu_get_8s(f, &s->msr);
2198 qemu_get_8s(f, &s->fcr);
2199 qemu_get_8s(f, &s->st00);
2200 qemu_get_8s(f, &s->st01);
2201
2202 qemu_get_8s(f, &s->dac_state);
2203 qemu_get_8s(f, &s->dac_sub_index);
2204 qemu_get_8s(f, &s->dac_read_index);
2205 qemu_get_8s(f, &s->dac_write_index);
2206 qemu_get_buffer(f, s->dac_cache, 3);
2207 qemu_get_buffer(f, s->palette, 768);
2208
bee8d684 2209 s->bank_offset=qemu_get_be32(f);
b0a21b53
FB
2210 is_vbe = qemu_get_byte(f);
2211#ifdef CONFIG_BOCHS_VBE
2212 if (!is_vbe)
2213 return -EINVAL;
2214 qemu_get_be16s(f, &s->vbe_index);
2215 for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
2216 qemu_get_be16s(f, &s->vbe_regs[i]);
2217 qemu_get_be32s(f, &s->vbe_start_addr);
2218 qemu_get_be32s(f, &s->vbe_line_offset);
2219 qemu_get_be32s(f, &s->vbe_bank_mask);
2220#else
2221 if (is_vbe)
2222 return -EINVAL;
2223#endif
2224
2225 /* force refresh */
799e709b 2226 s->graphic_mode = -1;
b0a21b53
FB
2227 return 0;
2228}
2229
d2269f6f
FB
2230typedef struct PCIVGAState {
2231 PCIDevice dev;
2191dffc 2232 VGAState vga;
d2269f6f
FB
2233} PCIVGAState;
2234
2bec46dc
AL
2235void vga_dirty_log_start(VGAState *s)
2236{
2237 if (kvm_enabled() && s->map_addr)
2238 kvm_log_start(s->map_addr, s->map_end - s->map_addr);
2239
2240 if (kvm_enabled() && s->lfb_vram_mapped) {
2241 kvm_log_start(isa_mem_base + 0xa0000, 0x8000);
2242 kvm_log_start(isa_mem_base + 0xa8000, 0x8000);
2243 }
2244}
2245
5fafdf24 2246static void vga_map(PCIDevice *pci_dev, int region_num,
1078f663
FB
2247 uint32_t addr, uint32_t size, int type)
2248{
d2269f6f 2249 PCIVGAState *d = (PCIVGAState *)pci_dev;
2191dffc 2250 VGAState *s = &d->vga;
d5295253
FB
2251 if (region_num == PCI_ROM_SLOT) {
2252 cpu_register_physical_memory(addr, s->bios_size, s->bios_offset);
2253 } else {
2254 cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
e7f3dcc4
AL
2255 s->map_addr = addr;
2256 s->map_end = addr + s->vram_size;
2257 vga_dirty_log_start(s);
d5295253 2258 }
1078f663
FB
2259}
2260
a4a2f59c 2261void vga_common_init(VGACommonState *s, int vga_ram_size)
e89f66ec 2262{
17b0018b 2263 int i, j, v, b;
e89f66ec
FB
2264
2265 for(i = 0;i < 256; i++) {
2266 v = 0;
2267 for(j = 0; j < 8; j++) {
2268 v |= ((i >> j) & 1) << (j * 4);
2269 }
2270 expand4[i] = v;
2271
2272 v = 0;
2273 for(j = 0; j < 4; j++) {
2274 v |= ((i >> (2 * j)) & 3) << (j * 4);
2275 }
2276 expand2[i] = v;
2277 }
17b0018b
FB
2278 for(i = 0; i < 16; i++) {
2279 v = 0;
2280 for(j = 0; j < 4; j++) {
2281 b = ((i >> j) & 1);
2282 v |= b << (2 * j);
2283 v |= b << (2 * j + 1);
2284 }
2285 expand4to8[i] = v;
2286 }
e89f66ec 2287
b584726d
PB
2288 s->vram_offset = qemu_ram_alloc(vga_ram_size);
2289 s->vram_ptr = qemu_get_ram_ptr(s->vram_offset);
e89f66ec 2290 s->vram_size = vga_ram_size;
798b0c25
FB
2291 s->get_bpp = vga_get_bpp;
2292 s->get_offsets = vga_get_offsets;
a130a41e 2293 s->get_resolution = vga_get_resolution;
d34cab9f
TS
2294 s->update = vga_update_display;
2295 s->invalidate = vga_invalidate_display;
2296 s->screen_dump = vga_screen_dump;
4d3b6f6e 2297 s->text_update = vga_update_text;
cb5a7aa8 2298 switch (vga_retrace_method) {
2299 case VGA_RETRACE_DUMB:
2300 s->retrace = vga_dumb_retrace;
2301 s->update_retrace_info = vga_dumb_update_retrace_info;
2302 break;
2303
2304 case VGA_RETRACE_PRECISE:
2305 s->retrace = vga_precise_retrace;
2306 s->update_retrace_info = vga_precise_update_retrace_info;
cb5a7aa8 2307 break;
2308 }
6e6b7363 2309 vga_reset(s);
798b0c25
FB
2310}
2311
d2269f6f 2312/* used by both ISA and PCI */
d34cab9f 2313void vga_init(VGAState *s)
798b0c25 2314{
d2269f6f 2315 int vga_io_memory;
7b17d41e 2316
a08d4367 2317 qemu_register_reset(vga_reset, s);
d2269f6f 2318 register_savevm("vga", 0, 2, vga_save, vga_load, s);
b0a21b53 2319
0f35920c 2320 register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
e89f66ec 2321
0f35920c
FB
2322 register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
2323 register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);
2324 register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);
2325 register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);
e89f66ec 2326
0f35920c 2327 register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
e89f66ec 2328
0f35920c
FB
2329 register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);
2330 register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);
2331 register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
2332 register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
26aa7d72 2333 s->bank_offset = 0;
e89f66ec 2334
4fa0f5d2 2335#ifdef CONFIG_BOCHS_VBE
09a79b49
FB
2336#if defined (TARGET_I386)
2337 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
2338 register_ioport_read(0x1cf, 1, 2, vbe_ioport_read_data, s);
4fa0f5d2 2339
09a79b49
FB
2340 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
2341 register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data, s);
646be93b
FB
2342
2343 /* old Bochs IO ports */
09a79b49
FB
2344 register_ioport_read(0xff80, 1, 2, vbe_ioport_read_index, s);
2345 register_ioport_read(0xff81, 1, 2, vbe_ioport_read_data, s);
646be93b 2346
09a79b49 2347 register_ioport_write(0xff80, 1, 2, vbe_ioport_write_index, s);
5fafdf24 2348 register_ioport_write(0xff81, 1, 2, vbe_ioport_write_data, s);
09a79b49
FB
2349#else
2350 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
2351 register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data, s);
2352
2353 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
2354 register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data, s);
4fa0f5d2 2355#endif
09a79b49 2356#endif /* CONFIG_BOCHS_VBE */
4fa0f5d2 2357
1eed09cb 2358 vga_io_memory = cpu_register_io_memory(vga_mem_read, vga_mem_write, s);
5fafdf24 2359 cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
26aa7d72 2360 vga_io_memory);
f65ed4c1 2361 qemu_register_coalesced_mmio(isa_mem_base + 0x000a0000, 0x20000);
d2269f6f
FB
2362}
2363
2abec30b
TS
2364/* Memory mapped interface */
2365static uint32_t vga_mm_readb (void *opaque, target_phys_addr_t addr)
2366{
2367 VGAState *s = opaque;
2368
8da3ff18 2369 return vga_ioport_read(s, addr >> s->it_shift) & 0xff;
2abec30b
TS
2370}
2371
2372static void vga_mm_writeb (void *opaque,
2373 target_phys_addr_t addr, uint32_t value)
2374{
2375 VGAState *s = opaque;
2376
8da3ff18 2377 vga_ioport_write(s, addr >> s->it_shift, value & 0xff);
2abec30b
TS
2378}
2379
2380static uint32_t vga_mm_readw (void *opaque, target_phys_addr_t addr)
2381{
2382 VGAState *s = opaque;
2383
8da3ff18 2384 return vga_ioport_read(s, addr >> s->it_shift) & 0xffff;
2abec30b
TS
2385}
2386
2387static void vga_mm_writew (void *opaque,
2388 target_phys_addr_t addr, uint32_t value)
2389{
2390 VGAState *s = opaque;
2391
8da3ff18 2392 vga_ioport_write(s, addr >> s->it_shift, value & 0xffff);
2abec30b
TS
2393}
2394
2395static uint32_t vga_mm_readl (void *opaque, target_phys_addr_t addr)
2396{
2397 VGAState *s = opaque;
2398
8da3ff18 2399 return vga_ioport_read(s, addr >> s->it_shift);
2abec30b
TS
2400}
2401
2402static void vga_mm_writel (void *opaque,
2403 target_phys_addr_t addr, uint32_t value)
2404{
2405 VGAState *s = opaque;
2406
8da3ff18 2407 vga_ioport_write(s, addr >> s->it_shift, value);
2abec30b
TS
2408}
2409
d60efc6b 2410static CPUReadMemoryFunc * const vga_mm_read_ctrl[] = {
2abec30b
TS
2411 &vga_mm_readb,
2412 &vga_mm_readw,
2413 &vga_mm_readl,
2414};
2415
d60efc6b 2416static CPUWriteMemoryFunc * const vga_mm_write_ctrl[] = {
2abec30b
TS
2417 &vga_mm_writeb,
2418 &vga_mm_writew,
2419 &vga_mm_writel,
2420};
2421
2422static void vga_mm_init(VGAState *s, target_phys_addr_t vram_base,
2423 target_phys_addr_t ctrl_base, int it_shift)
2424{
2425 int s_ioport_ctrl, vga_io_memory;
2426
2abec30b 2427 s->it_shift = it_shift;
1eed09cb
AK
2428 s_ioport_ctrl = cpu_register_io_memory(vga_mm_read_ctrl, vga_mm_write_ctrl, s);
2429 vga_io_memory = cpu_register_io_memory(vga_mem_read, vga_mem_write, s);
2abec30b
TS
2430
2431 register_savevm("vga", 0, 2, vga_save, vga_load, s);
2432
2433 cpu_register_physical_memory(ctrl_base, 0x100000, s_ioport_ctrl);
2434 s->bank_offset = 0;
2435 cpu_register_physical_memory(vram_base + 0x000a0000, 0x20000, vga_io_memory);
f65ed4c1 2436 qemu_register_coalesced_mmio(vram_base + 0x000a0000, 0x20000);
2abec30b
TS
2437}
2438
fbe1b595 2439int isa_vga_init(void)
d2269f6f
FB
2440{
2441 VGAState *s;
2442
2443 s = qemu_mallocz(sizeof(VGAState));
d2269f6f 2444
fbe1b595 2445 vga_common_init(s, VGA_RAM_SIZE);
d2269f6f 2446 vga_init(s);
1078f663 2447
3023f332
AL
2448 s->ds = graphic_console_init(s->update, s->invalidate,
2449 s->screen_dump, s->text_update, s);
d34cab9f 2450
4fa0f5d2 2451#ifdef CONFIG_BOCHS_VBE
d2269f6f 2452 /* XXX: use optimized standard vga accesses */
5fafdf24 2453 cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
fbe1b595 2454 VGA_RAM_SIZE, s->vram_offset);
7138fcfb 2455#endif
d2269f6f
FB
2456 return 0;
2457}
2458
fbe1b595 2459int isa_vga_mm_init(target_phys_addr_t vram_base,
b584726d 2460 target_phys_addr_t ctrl_base, int it_shift)
2abec30b
TS
2461{
2462 VGAState *s;
2463
2464 s = qemu_mallocz(sizeof(VGAState));
2abec30b 2465
fbe1b595 2466 vga_common_init(s, VGA_RAM_SIZE);
2abec30b
TS
2467 vga_mm_init(s, vram_base, ctrl_base, it_shift);
2468
3023f332
AL
2469 s->ds = graphic_console_init(s->update, s->invalidate,
2470 s->screen_dump, s->text_update, s);
2abec30b
TS
2471
2472#ifdef CONFIG_BOCHS_VBE
2473 /* XXX: use optimized standard vga accesses */
2474 cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
fbe1b595 2475 VGA_RAM_SIZE, s->vram_offset);
2abec30b
TS
2476#endif
2477 return 0;
2478}
2479
92a3ecda
AL
2480static void pci_vga_write_config(PCIDevice *d,
2481 uint32_t address, uint32_t val, int len)
2482{
2483 PCIVGAState *pvs = container_of(d, PCIVGAState, dev);
2191dffc 2484 VGAState *s = &pvs->vga;
92a3ecda 2485
92a3ecda 2486 pci_default_write_config(d, address, val, len);
e7f3dcc4
AL
2487 if (s->map_addr && pvs->dev.io_regions[0].addr == -1)
2488 s->map_addr = 0;
92a3ecda
AL
2489}
2490
81a322d4 2491static int pci_vga_initfn(PCIDevice *dev)
d2269f6f 2492{
a414c306 2493 PCIVGAState *d = DO_UPCAST(PCIVGAState, dev, dev);
2191dffc 2494 VGAState *s = &d->vga;
a414c306
GH
2495 uint8_t *pci_conf = d->dev.config;
2496
2497 // vga + console init
2498 vga_common_init(s, VGA_RAM_SIZE);
2499 vga_init(s);
2500 s->pci_dev = &d->dev;
2501 s->ds = graphic_console_init(s->update, s->invalidate,
2502 s->screen_dump, s->text_update, s);
2503
2504 // dummy VGA (same as Bochs ID)
2505 pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_QEMU);
2506 pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_QEMU_VGA);
2507 pci_config_set_class(pci_conf, PCI_CLASS_DISPLAY_VGA);
2508 pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type
2509
2510 /* XXX: VGA_RAM_SIZE must be a power of two */
2511 pci_register_bar(&d->dev, 0, VGA_RAM_SIZE,
2512 PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
2513
2514 if (s->bios_size) {
d2269f6f 2515 unsigned int bios_total_size;
d2269f6f
FB
2516 /* must be a power of two */
2517 bios_total_size = 1;
a414c306 2518 while (bios_total_size < s->bios_size)
d2269f6f 2519 bios_total_size <<= 1;
28c2c264 2520 pci_register_bar(&d->dev, PCI_ROM_SLOT, bios_total_size,
a414c306 2521 PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
81a322d4
GH
2522 }
2523 return 0;
a414c306
GH
2524}
2525
2526int pci_vga_init(PCIBus *bus,
2527 unsigned long vga_bios_offset, int vga_bios_size)
2528{
2529 PCIDevice *dev;
2530
2531 dev = pci_create("VGA", NULL);
2532 qdev_prop_set_uint32(&dev->qdev, "bios-offset", vga_bios_offset);
2533 qdev_prop_set_uint32(&dev->qdev, "bios-size", vga_bios_offset);
2534 qdev_init(&dev->qdev);
2535
e89f66ec
FB
2536 return 0;
2537}
59a983b9 2538
a414c306
GH
2539static PCIDeviceInfo vga_info = {
2540 .qdev.name = "VGA",
2541 .qdev.size = sizeof(PCIVGAState),
2542 .init = pci_vga_initfn,
2543 .config_write = pci_vga_write_config,
2544 .qdev.props = (Property[]) {
2191dffc
JQ
2545 DEFINE_PROP_HEX32("bios-offset", PCIVGAState, vga.bios_offset, 0),
2546 DEFINE_PROP_HEX32("bios-size", PCIVGAState, vga.bios_size, 0),
df59cbc6 2547 DEFINE_PROP_END_OF_LIST(),
a414c306
GH
2548 }
2549};
2550
2551static void vga_register(void)
2552{
2553 pci_qdev_register(&vga_info);
2554}
2555device_init(vga_register);
2556
59a983b9
FB
2557/********************************************************/
2558/* vga screen dump */
2559
04a52b41 2560static void vga_save_dpy_update(DisplayState *ds,
59a983b9
FB
2561 int x, int y, int w, int h)
2562{
04a52b41
SS
2563 if (screen_dump_filename) {
2564 ppm_save(screen_dump_filename, ds->surface);
2565 screen_dump_filename = NULL;
2566 }
59a983b9
FB
2567}
2568
7d957bd8 2569static void vga_save_dpy_resize(DisplayState *s)
59a983b9 2570{
59a983b9
FB
2571}
2572
2573static void vga_save_dpy_refresh(DisplayState *s)
2574{
2575}
2576
e07d630a 2577int ppm_save(const char *filename, struct DisplaySurface *ds)
59a983b9
FB
2578{
2579 FILE *f;
2580 uint8_t *d, *d1;
e07d630a 2581 uint32_t v;
59a983b9 2582 int y, x;
e07d630a 2583 uint8_t r, g, b;
59a983b9
FB
2584
2585 f = fopen(filename, "wb");
2586 if (!f)
2587 return -1;
2588 fprintf(f, "P6\n%d %d\n%d\n",
e07d630a
AL
2589 ds->width, ds->height, 255);
2590 d1 = ds->data;
2591 for(y = 0; y < ds->height; y++) {
59a983b9 2592 d = d1;
e07d630a
AL
2593 for(x = 0; x < ds->width; x++) {
2594 if (ds->pf.bits_per_pixel == 32)
2595 v = *(uint32_t *)d;
2596 else
2597 v = (uint32_t) (*(uint16_t *)d);
2598 r = ((v >> ds->pf.rshift) & ds->pf.rmax) * 256 /
2599 (ds->pf.rmax + 1);
2600 g = ((v >> ds->pf.gshift) & ds->pf.gmax) * 256 /
2601 (ds->pf.gmax + 1);
2602 b = ((v >> ds->pf.bshift) & ds->pf.bmax) * 256 /
2603 (ds->pf.bmax + 1);
2604 fputc(r, f);
2605 fputc(g, f);
2606 fputc(b, f);
2607 d += ds->pf.bytes_per_pixel;
59a983b9 2608 }
e07d630a 2609 d1 += ds->linesize;
59a983b9
FB
2610 }
2611 fclose(f);
2612 return 0;
2613}
2614
04a52b41 2615static DisplayChangeListener* vga_screen_dump_init(DisplayState *ds)
4c5e8c5c 2616{
04a52b41 2617 DisplayChangeListener *dcl;
4c5e8c5c 2618
04a52b41
SS
2619 dcl = qemu_mallocz(sizeof(DisplayChangeListener));
2620 dcl->dpy_update = vga_save_dpy_update;
2621 dcl->dpy_resize = vga_save_dpy_resize;
2622 dcl->dpy_refresh = vga_save_dpy_refresh;
2623 register_displaychangelistener(ds, dcl);
2624 return dcl;
4c5e8c5c
BS
2625}
2626
2627/* save the vga display in a PPM image even if no display is
2628 available */
2629static void vga_screen_dump(void *opaque, const char *filename)
2630{
1a5ab757 2631 VGAState *s = opaque;
4c5e8c5c 2632
04a52b41
SS
2633 if (!screen_dump_dcl)
2634 screen_dump_dcl = vga_screen_dump_init(s->ds);
2635
2636 screen_dump_filename = (char *)filename;
9d1b494a 2637 vga_invalidate_display(s);
04a52b41 2638 vga_hw_update();
4c5e8c5c 2639}
04a52b41 2640
This page took 0.736056 seconds and 4 git commands to generate.