Statistics
| Branch: | Revision:

root / hw / vga.c @ b0f74c87

History | View | Annotate | Download (69.3 kB)

1
/*
2
 * QEMU VGA Emulator.
3
 *
4
 * Copyright (c) 2003 Fabrice Bellard
5
 *
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
 */
24
#include "hw.h"
25
#include "console.h"
26
#include "pc.h"
27
#include "pci.h"
28
#include "vga_int.h"
29
#include "pixel_ops.h"
30
#include "qemu-timer.h"
31

    
32
//#define DEBUG_VGA
33
//#define DEBUG_VGA_MEM
34
//#define DEBUG_VGA_REG
35

    
36
//#define DEBUG_BOCHS_VBE
37

    
38
/* force some bits to zero */
39
const uint8_t sr_mask[8] = {
40
    (uint8_t)~0xfc,
41
    (uint8_t)~0xc2,
42
    (uint8_t)~0xf0,
43
    (uint8_t)~0xc0,
44
    (uint8_t)~0xf1,
45
    (uint8_t)~0xff,
46
    (uint8_t)~0xff,
47
    (uint8_t)~0x00,
48
};
49

    
50
const uint8_t gr_mask[16] = {
51
    (uint8_t)~0xf0, /* 0x00 */
52
    (uint8_t)~0xf0, /* 0x01 */
53
    (uint8_t)~0xf0, /* 0x02 */
54
    (uint8_t)~0xe0, /* 0x03 */
55
    (uint8_t)~0xfc, /* 0x04 */
56
    (uint8_t)~0x84, /* 0x05 */
57
    (uint8_t)~0xf0, /* 0x06 */
58
    (uint8_t)~0xf0, /* 0x07 */
59
    (uint8_t)~0x00, /* 0x08 */
60
    (uint8_t)~0xff, /* 0x09 */
61
    (uint8_t)~0xff, /* 0x0a */
62
    (uint8_t)~0xff, /* 0x0b */
63
    (uint8_t)~0xff, /* 0x0c */
64
    (uint8_t)~0xff, /* 0x0d */
65
    (uint8_t)~0xff, /* 0x0e */
66
    (uint8_t)~0xff, /* 0x0f */
67
};
68

    
69
#define cbswap_32(__x) \
70
((uint32_t)( \
71
                (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
72
                (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) <<  8) | \
73
                (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >>  8) | \
74
                (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
75

    
76
#ifdef WORDS_BIGENDIAN
77
#define PAT(x) cbswap_32(x)
78
#else
79
#define PAT(x) (x)
80
#endif
81

    
82
#ifdef WORDS_BIGENDIAN
83
#define BIG 1
84
#else
85
#define BIG 0
86
#endif
87

    
88
#ifdef WORDS_BIGENDIAN
89
#define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
90
#else
91
#define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
92
#endif
93

    
94
static const uint32_t mask16[16] = {
95
    PAT(0x00000000),
96
    PAT(0x000000ff),
97
    PAT(0x0000ff00),
98
    PAT(0x0000ffff),
99
    PAT(0x00ff0000),
100
    PAT(0x00ff00ff),
101
    PAT(0x00ffff00),
102
    PAT(0x00ffffff),
103
    PAT(0xff000000),
104
    PAT(0xff0000ff),
105
    PAT(0xff00ff00),
106
    PAT(0xff00ffff),
107
    PAT(0xffff0000),
108
    PAT(0xffff00ff),
109
    PAT(0xffffff00),
110
    PAT(0xffffffff),
111
};
112

    
113
#undef PAT
114

    
115
#ifdef WORDS_BIGENDIAN
116
#define PAT(x) (x)
117
#else
118
#define PAT(x) cbswap_32(x)
119
#endif
120

    
121
static const uint32_t dmask16[16] = {
122
    PAT(0x00000000),
123
    PAT(0x000000ff),
124
    PAT(0x0000ff00),
125
    PAT(0x0000ffff),
126
    PAT(0x00ff0000),
127
    PAT(0x00ff00ff),
128
    PAT(0x00ffff00),
129
    PAT(0x00ffffff),
130
    PAT(0xff000000),
131
    PAT(0xff0000ff),
132
    PAT(0xff00ff00),
133
    PAT(0xff00ffff),
134
    PAT(0xffff0000),
135
    PAT(0xffff00ff),
136
    PAT(0xffffff00),
137
    PAT(0xffffffff),
138
};
139

    
140
static const uint32_t dmask4[4] = {
141
    PAT(0x00000000),
142
    PAT(0x0000ffff),
143
    PAT(0xffff0000),
144
    PAT(0xffffffff),
145
};
146

    
147
static uint32_t expand4[256];
148
static uint16_t expand2[256];
149
static uint8_t expand4to8[16];
150

    
151
static void vga_screen_dump(void *opaque, const char *filename);
152

    
153
static void vga_dumb_update_retrace_info(VGAState *s)
154
{
155
    (void) s;
156
}
157

    
158
static void vga_precise_update_retrace_info(VGAState *s)
159
{
160
    int htotal_chars;
161
    int hretr_start_char;
162
    int hretr_skew_chars;
163
    int hretr_end_char;
164

    
165
    int vtotal_lines;
166
    int vretr_start_line;
167
    int vretr_end_line;
168

    
169
    int div2, sldiv2, dots;
170
    int clocking_mode;
171
    int clock_sel;
172
    const int clk_hz[] = {25175000, 28322000, 25175000, 25175000};
173
    int64_t chars_per_sec;
174
    struct vga_precise_retrace *r = &s->retrace_info.precise;
175

    
176
    htotal_chars = s->cr[0x00] + 5;
177
    hretr_start_char = s->cr[0x04];
178
    hretr_skew_chars = (s->cr[0x05] >> 5) & 3;
179
    hretr_end_char = s->cr[0x05] & 0x1f;
180

    
181
    vtotal_lines = (s->cr[0x06]
182
                    | (((s->cr[0x07] & 1) | ((s->cr[0x07] >> 4) & 2)) << 8)) + 2
183
        ;
184
    vretr_start_line = s->cr[0x10]
185
        | ((((s->cr[0x07] >> 2) & 1) | ((s->cr[0x07] >> 6) & 2)) << 8)
186
        ;
187
    vretr_end_line = s->cr[0x11] & 0xf;
188

    
189

    
190
    div2 = (s->cr[0x17] >> 2) & 1;
191
    sldiv2 = (s->cr[0x17] >> 3) & 1;
192

    
193
    clocking_mode = (s->sr[0x01] >> 3) & 1;
194
    clock_sel = (s->msr >> 2) & 3;
195
    dots = (s->msr & 1) ? 8 : 9;
196

    
197
    chars_per_sec = clk_hz[clock_sel] / dots;
198

    
199
    htotal_chars <<= clocking_mode;
200

    
201
    r->total_chars = vtotal_lines * htotal_chars;
202
    if (r->freq) {
203
        r->ticks_per_char = ticks_per_sec / (r->total_chars * r->freq);
204
    } else {
205
        r->ticks_per_char = ticks_per_sec / chars_per_sec;
206
    }
207

    
208
    r->vstart = vretr_start_line;
209
    r->vend = r->vstart + vretr_end_line + 1;
210

    
211
    r->hstart = hretr_start_char + hretr_skew_chars;
212
    r->hend = r->hstart + hretr_end_char + 1;
213
    r->htotal = htotal_chars;
214

    
215
#if 0
216
    printf (
217
        "hz=%f\n"
218
        "htotal = %d\n"
219
        "hretr_start = %d\n"
220
        "hretr_skew = %d\n"
221
        "hretr_end = %d\n"
222
        "vtotal = %d\n"
223
        "vretr_start = %d\n"
224
        "vretr_end = %d\n"
225
        "div2 = %d sldiv2 = %d\n"
226
        "clocking_mode = %d\n"
227
        "clock_sel = %d %d\n"
228
        "dots = %d\n"
229
        "ticks/char = %lld\n"
230
        "\n",
231
        (double) ticks_per_sec / (r->ticks_per_char * r->total_chars),
232
        htotal_chars,
233
        hretr_start_char,
234
        hretr_skew_chars,
235
        hretr_end_char,
236
        vtotal_lines,
237
        vretr_start_line,
238
        vretr_end_line,
239
        div2, sldiv2,
240
        clocking_mode,
241
        clock_sel,
242
        clk_hz[clock_sel],
243
        dots,
244
        r->ticks_per_char
245
        );
246
#endif
247
}
248

    
249
static uint8_t vga_precise_retrace(VGAState *s)
250
{
251
    struct vga_precise_retrace *r = &s->retrace_info.precise;
252
    uint8_t val = s->st01 & ~(ST01_V_RETRACE | ST01_DISP_ENABLE);
253

    
254
    if (r->total_chars) {
255
        int cur_line, cur_line_char, cur_char;
256
        int64_t cur_tick;
257

    
258
        cur_tick = qemu_get_clock(vm_clock);
259

    
260
        cur_char = (cur_tick / r->ticks_per_char) % r->total_chars;
261
        cur_line = cur_char / r->htotal;
262

    
263
        if (cur_line >= r->vstart && cur_line <= r->vend) {
264
            val |= ST01_V_RETRACE | ST01_DISP_ENABLE;
265
        } else {
266
            cur_line_char = cur_char % r->htotal;
267
            if (cur_line_char >= r->hstart && cur_line_char <= r->hend) {
268
                val |= ST01_DISP_ENABLE;
269
            }
270
        }
271

    
272
        return val;
273
    } else {
274
        return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
275
    }
276
}
277

    
278
static uint8_t vga_dumb_retrace(VGAState *s)
279
{
280
    return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
281
}
282

    
283
static uint32_t vga_ioport_read(void *opaque, uint32_t addr)
284
{
285
    VGAState *s = opaque;
286
    int val, index;
287

    
288
    /* check port range access depending on color/monochrome mode */
289
    if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
290
        (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION))) {
291
        val = 0xff;
292
    } else {
293
        switch(addr) {
294
        case 0x3c0:
295
            if (s->ar_flip_flop == 0) {
296
                val = s->ar_index;
297
            } else {
298
                val = 0;
299
            }
300
            break;
301
        case 0x3c1:
302
            index = s->ar_index & 0x1f;
303
            if (index < 21)
304
                val = s->ar[index];
305
            else
306
                val = 0;
307
            break;
308
        case 0x3c2:
309
            val = s->st00;
310
            break;
311
        case 0x3c4:
312
            val = s->sr_index;
313
            break;
314
        case 0x3c5:
315
            val = s->sr[s->sr_index];
316
#ifdef DEBUG_VGA_REG
317
            printf("vga: read SR%x = 0x%02x\n", s->sr_index, val);
318
#endif
319
            break;
320
        case 0x3c7:
321
            val = s->dac_state;
322
            break;
323
        case 0x3c8:
324
            val = s->dac_write_index;
325
            break;
326
        case 0x3c9:
327
            val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
328
            if (++s->dac_sub_index == 3) {
329
                s->dac_sub_index = 0;
330
                s->dac_read_index++;
331
            }
332
            break;
333
        case 0x3ca:
334
            val = s->fcr;
335
            break;
336
        case 0x3cc:
337
            val = s->msr;
338
            break;
339
        case 0x3ce:
340
            val = s->gr_index;
341
            break;
342
        case 0x3cf:
343
            val = s->gr[s->gr_index];
344
#ifdef DEBUG_VGA_REG
345
            printf("vga: read GR%x = 0x%02x\n", s->gr_index, val);
346
#endif
347
            break;
348
        case 0x3b4:
349
        case 0x3d4:
350
            val = s->cr_index;
351
            break;
352
        case 0x3b5:
353
        case 0x3d5:
354
            val = s->cr[s->cr_index];
355
#ifdef DEBUG_VGA_REG
356
            printf("vga: read CR%x = 0x%02x\n", s->cr_index, val);
357
#endif
358
            break;
359
        case 0x3ba:
360
        case 0x3da:
361
            /* just toggle to fool polling */
362
            val = s->st01 = s->retrace(s);
363
            s->ar_flip_flop = 0;
364
            break;
365
        default:
366
            val = 0x00;
367
            break;
368
        }
369
    }
370
#if defined(DEBUG_VGA)
371
    printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
372
#endif
373
    return val;
374
}
375

    
376
static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
377
{
378
    VGAState *s = opaque;
379
    int index;
380

    
381
    /* check port range access depending on color/monochrome mode */
382
    if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
383
        (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION)))
384
        return;
385

    
386
#ifdef DEBUG_VGA
387
    printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
388
#endif
389

    
390
    switch(addr) {
391
    case 0x3c0:
392
        if (s->ar_flip_flop == 0) {
393
            val &= 0x3f;
394
            s->ar_index = val;
395
        } else {
396
            index = s->ar_index & 0x1f;
397
            switch(index) {
398
            case 0x00 ... 0x0f:
399
                s->ar[index] = val & 0x3f;
400
                break;
401
            case 0x10:
402
                s->ar[index] = val & ~0x10;
403
                break;
404
            case 0x11:
405
                s->ar[index] = val;
406
                break;
407
            case 0x12:
408
                s->ar[index] = val & ~0xc0;
409
                break;
410
            case 0x13:
411
                s->ar[index] = val & ~0xf0;
412
                break;
413
            case 0x14:
414
                s->ar[index] = val & ~0xf0;
415
                break;
416
            default:
417
                break;
418
            }
419
        }
420
        s->ar_flip_flop ^= 1;
421
        break;
422
    case 0x3c2:
423
        s->msr = val & ~0x10;
424
        s->update_retrace_info(s);
425
        break;
426
    case 0x3c4:
427
        s->sr_index = val & 7;
428
        break;
429
    case 0x3c5:
430
#ifdef DEBUG_VGA_REG
431
        printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
432
#endif
433
        s->sr[s->sr_index] = val & sr_mask[s->sr_index];
434
        if (s->sr_index == 1) s->update_retrace_info(s);
435
        break;
436
    case 0x3c7:
437
        s->dac_read_index = val;
438
        s->dac_sub_index = 0;
439
        s->dac_state = 3;
440
        break;
441
    case 0x3c8:
442
        s->dac_write_index = val;
443
        s->dac_sub_index = 0;
444
        s->dac_state = 0;
445
        break;
446
    case 0x3c9:
447
        s->dac_cache[s->dac_sub_index] = val;
448
        if (++s->dac_sub_index == 3) {
449
            memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
450
            s->dac_sub_index = 0;
451
            s->dac_write_index++;
452
        }
453
        break;
454
    case 0x3ce:
455
        s->gr_index = val & 0x0f;
456
        break;
457
    case 0x3cf:
458
#ifdef DEBUG_VGA_REG
459
        printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
460
#endif
461
        s->gr[s->gr_index] = val & gr_mask[s->gr_index];
462
        break;
463
    case 0x3b4:
464
    case 0x3d4:
465
        s->cr_index = val;
466
        break;
467
    case 0x3b5:
468
    case 0x3d5:
469
#ifdef DEBUG_VGA_REG
470
        printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
471
#endif
472
        /* handle CR0-7 protection */
473
        if ((s->cr[0x11] & 0x80) && s->cr_index <= 7) {
474
            /* can always write bit 4 of CR7 */
475
            if (s->cr_index == 7)
476
                s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
477
            return;
478
        }
479
        switch(s->cr_index) {
480
        case 0x01: /* horizontal display end */
481
        case 0x07:
482
        case 0x09:
483
        case 0x0c:
484
        case 0x0d:
485
        case 0x12: /* vertical display end */
486
            s->cr[s->cr_index] = val;
487
            break;
488
        default:
489
            s->cr[s->cr_index] = val;
490
            break;
491
        }
492

    
493
        switch(s->cr_index) {
494
        case 0x00:
495
        case 0x04:
496
        case 0x05:
497
        case 0x06:
498
        case 0x07:
499
        case 0x11:
500
        case 0x17:
501
            s->update_retrace_info(s);
502
            break;
503
        }
504
        break;
505
    case 0x3ba:
506
    case 0x3da:
507
        s->fcr = val & 0x10;
508
        break;
509
    }
510
}
511

    
512
#ifdef CONFIG_BOCHS_VBE
513
static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
514
{
515
    VGAState *s = opaque;
516
    uint32_t val;
517
    val = s->vbe_index;
518
    return val;
519
}
520

    
521
static uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr)
522
{
523
    VGAState *s = opaque;
524
    uint32_t val;
525

    
526
    if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
527
        if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_GETCAPS) {
528
            switch(s->vbe_index) {
529
                /* XXX: do not hardcode ? */
530
            case VBE_DISPI_INDEX_XRES:
531
                val = VBE_DISPI_MAX_XRES;
532
                break;
533
            case VBE_DISPI_INDEX_YRES:
534
                val = VBE_DISPI_MAX_YRES;
535
                break;
536
            case VBE_DISPI_INDEX_BPP:
537
                val = VBE_DISPI_MAX_BPP;
538
                break;
539
            default:
540
                val = s->vbe_regs[s->vbe_index];
541
                break;
542
            }
543
        } else {
544
            val = s->vbe_regs[s->vbe_index];
545
        }
546
    } else {
547
        val = 0;
548
    }
549
#ifdef DEBUG_BOCHS_VBE
550
    printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val);
551
#endif
552
    return val;
553
}
554

    
555
static void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val)
556
{
557
    VGAState *s = opaque;
558
    s->vbe_index = val;
559
}
560

    
561
static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
562
{
563
    VGAState *s = opaque;
564

    
565
    if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
566
#ifdef DEBUG_BOCHS_VBE
567
        printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val);
568
#endif
569
        switch(s->vbe_index) {
570
        case VBE_DISPI_INDEX_ID:
571
            if (val == VBE_DISPI_ID0 ||
572
                val == VBE_DISPI_ID1 ||
573
                val == VBE_DISPI_ID2 ||
574
                val == VBE_DISPI_ID3 ||
575
                val == VBE_DISPI_ID4) {
576
                s->vbe_regs[s->vbe_index] = val;
577
            }
578
            break;
579
        case VBE_DISPI_INDEX_XRES:
580
            if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) {
581
                s->vbe_regs[s->vbe_index] = val;
582
            }
583
            break;
584
        case VBE_DISPI_INDEX_YRES:
585
            if (val <= VBE_DISPI_MAX_YRES) {
586
                s->vbe_regs[s->vbe_index] = val;
587
            }
588
            break;
589
        case VBE_DISPI_INDEX_BPP:
590
            if (val == 0)
591
                val = 8;
592
            if (val == 4 || val == 8 || val == 15 ||
593
                val == 16 || val == 24 || val == 32) {
594
                s->vbe_regs[s->vbe_index] = val;
595
            }
596
            break;
597
        case VBE_DISPI_INDEX_BANK:
598
            if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
599
              val &= (s->vbe_bank_mask >> 2);
600
            } else {
601
              val &= s->vbe_bank_mask;
602
            }
603
            s->vbe_regs[s->vbe_index] = val;
604
            s->bank_offset = (val << 16);
605
            break;
606
        case VBE_DISPI_INDEX_ENABLE:
607
            if ((val & VBE_DISPI_ENABLED) &&
608
                !(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
609
                int h, shift_control;
610

    
611
                s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] =
612
                    s->vbe_regs[VBE_DISPI_INDEX_XRES];
613
                s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] =
614
                    s->vbe_regs[VBE_DISPI_INDEX_YRES];
615
                s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
616
                s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
617

    
618
                if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
619
                    s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1;
620
                else
621
                    s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] *
622
                        ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
623
                s->vbe_start_addr = 0;
624

    
625
                /* clear the screen (should be done in BIOS) */
626
                if (!(val & VBE_DISPI_NOCLEARMEM)) {
627
                    memset(s->vram_ptr, 0,
628
                           s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
629
                }
630

    
631
                /* we initialize the VGA graphic mode (should be done
632
                   in BIOS) */
633
                s->gr[0x06] = (s->gr[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
634
                s->cr[0x17] |= 3; /* no CGA modes */
635
                s->cr[0x13] = s->vbe_line_offset >> 3;
636
                /* width */
637
                s->cr[0x01] = (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
638
                /* height (only meaningful if < 1024) */
639
                h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
640
                s->cr[0x12] = h;
641
                s->cr[0x07] = (s->cr[0x07] & ~0x42) |
642
                    ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
643
                /* line compare to 1023 */
644
                s->cr[0x18] = 0xff;
645
                s->cr[0x07] |= 0x10;
646
                s->cr[0x09] |= 0x40;
647

    
648
                if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
649
                    shift_control = 0;
650
                    s->sr[0x01] &= ~8; /* no double line */
651
                } else {
652
                    shift_control = 2;
653
                    s->sr[4] |= 0x08; /* set chain 4 mode */
654
                    s->sr[2] |= 0x0f; /* activate all planes */
655
                }
656
                s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5);
657
                s->cr[0x09] &= ~0x9f; /* no double scan */
658
            } else {
659
                /* XXX: the bios should do that */
660
                s->bank_offset = 0;
661
            }
662
            s->dac_8bit = (val & VBE_DISPI_8BIT_DAC) > 0;
663
            s->vbe_regs[s->vbe_index] = val;
664
            break;
665
        case VBE_DISPI_INDEX_VIRT_WIDTH:
666
            {
667
                int w, h, line_offset;
668

    
669
                if (val < s->vbe_regs[VBE_DISPI_INDEX_XRES])
670
                    return;
671
                w = val;
672
                if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
673
                    line_offset = w >> 1;
674
                else
675
                    line_offset = w * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
676
                h = s->vram_size / line_offset;
677
                /* XXX: support weird bochs semantics ? */
678
                if (h < s->vbe_regs[VBE_DISPI_INDEX_YRES])
679
                    return;
680
                s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = w;
681
                s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h;
682
                s->vbe_line_offset = line_offset;
683
            }
684
            break;
685
        case VBE_DISPI_INDEX_X_OFFSET:
686
        case VBE_DISPI_INDEX_Y_OFFSET:
687
            {
688
                int x;
689
                s->vbe_regs[s->vbe_index] = val;
690
                s->vbe_start_addr = s->vbe_line_offset * s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET];
691
                x = s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET];
692
                if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
693
                    s->vbe_start_addr += x >> 1;
694
                else
695
                    s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
696
                s->vbe_start_addr >>= 2;
697
            }
698
            break;
699
        default:
700
            break;
701
        }
702
    }
703
}
704
#endif
705

    
706
/* called for accesses between 0xa0000 and 0xc0000 */
707
uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr)
708
{
709
    VGAState *s = opaque;
710
    int memory_map_mode, plane;
711
    uint32_t ret;
712

    
713
    /* convert to VGA memory offset */
714
    memory_map_mode = (s->gr[6] >> 2) & 3;
715
    addr &= 0x1ffff;
716
    switch(memory_map_mode) {
717
    case 0:
718
        break;
719
    case 1:
720
        if (addr >= 0x10000)
721
            return 0xff;
722
        addr += s->bank_offset;
723
        break;
724
    case 2:
725
        addr -= 0x10000;
726
        if (addr >= 0x8000)
727
            return 0xff;
728
        break;
729
    default:
730
    case 3:
731
        addr -= 0x18000;
732
        if (addr >= 0x8000)
733
            return 0xff;
734
        break;
735
    }
736

    
737
    if (s->sr[4] & 0x08) {
738
        /* chain 4 mode : simplest access */
739
        ret = s->vram_ptr[addr];
740
    } else if (s->gr[5] & 0x10) {
741
        /* odd/even mode (aka text mode mapping) */
742
        plane = (s->gr[4] & 2) | (addr & 1);
743
        ret = s->vram_ptr[((addr & ~1) << 1) | plane];
744
    } else {
745
        /* standard VGA latched access */
746
        s->latch = ((uint32_t *)s->vram_ptr)[addr];
747

    
748
        if (!(s->gr[5] & 0x08)) {
749
            /* read mode 0 */
750
            plane = s->gr[4];
751
            ret = GET_PLANE(s->latch, plane);
752
        } else {
753
            /* read mode 1 */
754
            ret = (s->latch ^ mask16[s->gr[2]]) & mask16[s->gr[7]];
755
            ret |= ret >> 16;
756
            ret |= ret >> 8;
757
            ret = (~ret) & 0xff;
758
        }
759
    }
760
    return ret;
761
}
762

    
763
static uint32_t vga_mem_readw(void *opaque, target_phys_addr_t addr)
764
{
765
    uint32_t v;
766
#ifdef TARGET_WORDS_BIGENDIAN
767
    v = vga_mem_readb(opaque, addr) << 8;
768
    v |= vga_mem_readb(opaque, addr + 1);
769
#else
770
    v = vga_mem_readb(opaque, addr);
771
    v |= vga_mem_readb(opaque, addr + 1) << 8;
772
#endif
773
    return v;
774
}
775

    
776
static uint32_t vga_mem_readl(void *opaque, target_phys_addr_t addr)
777
{
778
    uint32_t v;
779
#ifdef TARGET_WORDS_BIGENDIAN
780
    v = vga_mem_readb(opaque, addr) << 24;
781
    v |= vga_mem_readb(opaque, addr + 1) << 16;
782
    v |= vga_mem_readb(opaque, addr + 2) << 8;
783
    v |= vga_mem_readb(opaque, addr + 3);
784
#else
785
    v = vga_mem_readb(opaque, addr);
786
    v |= vga_mem_readb(opaque, addr + 1) << 8;
787
    v |= vga_mem_readb(opaque, addr + 2) << 16;
788
    v |= vga_mem_readb(opaque, addr + 3) << 24;
789
#endif
790
    return v;
791
}
792

    
793
/* called for accesses between 0xa0000 and 0xc0000 */
794
void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
795
{
796
    VGAState *s = opaque;
797
    int memory_map_mode, plane, write_mode, b, func_select, mask;
798
    uint32_t write_mask, bit_mask, set_mask;
799

    
800
#ifdef DEBUG_VGA_MEM
801
    printf("vga: [0x%x] = 0x%02x\n", addr, val);
802
#endif
803
    /* convert to VGA memory offset */
804
    memory_map_mode = (s->gr[6] >> 2) & 3;
805
    addr &= 0x1ffff;
806
    switch(memory_map_mode) {
807
    case 0:
808
        break;
809
    case 1:
810
        if (addr >= 0x10000)
811
            return;
812
        addr += s->bank_offset;
813
        break;
814
    case 2:
815
        addr -= 0x10000;
816
        if (addr >= 0x8000)
817
            return;
818
        break;
819
    default:
820
    case 3:
821
        addr -= 0x18000;
822
        if (addr >= 0x8000)
823
            return;
824
        break;
825
    }
826

    
827
    if (s->sr[4] & 0x08) {
828
        /* chain 4 mode : simplest access */
829
        plane = addr & 3;
830
        mask = (1 << plane);
831
        if (s->sr[2] & mask) {
832
            s->vram_ptr[addr] = val;
833
#ifdef DEBUG_VGA_MEM
834
            printf("vga: chain4: [0x%x]\n", addr);
835
#endif
836
            s->plane_updated |= mask; /* only used to detect font change */
837
            cpu_physical_memory_set_dirty(s->vram_offset + addr);
838
        }
839
    } else if (s->gr[5] & 0x10) {
840
        /* odd/even mode (aka text mode mapping) */
841
        plane = (s->gr[4] & 2) | (addr & 1);
842
        mask = (1 << plane);
843
        if (s->sr[2] & mask) {
844
            addr = ((addr & ~1) << 1) | plane;
845
            s->vram_ptr[addr] = val;
846
#ifdef DEBUG_VGA_MEM
847
            printf("vga: odd/even: [0x%x]\n", addr);
848
#endif
849
            s->plane_updated |= mask; /* only used to detect font change */
850
            cpu_physical_memory_set_dirty(s->vram_offset + addr);
851
        }
852
    } else {
853
        /* standard VGA latched access */
854
        write_mode = s->gr[5] & 3;
855
        switch(write_mode) {
856
        default:
857
        case 0:
858
            /* rotate */
859
            b = s->gr[3] & 7;
860
            val = ((val >> b) | (val << (8 - b))) & 0xff;
861
            val |= val << 8;
862
            val |= val << 16;
863

    
864
            /* apply set/reset mask */
865
            set_mask = mask16[s->gr[1]];
866
            val = (val & ~set_mask) | (mask16[s->gr[0]] & set_mask);
867
            bit_mask = s->gr[8];
868
            break;
869
        case 1:
870
            val = s->latch;
871
            goto do_write;
872
        case 2:
873
            val = mask16[val & 0x0f];
874
            bit_mask = s->gr[8];
875
            break;
876
        case 3:
877
            /* rotate */
878
            b = s->gr[3] & 7;
879
            val = (val >> b) | (val << (8 - b));
880

    
881
            bit_mask = s->gr[8] & val;
882
            val = mask16[s->gr[0]];
883
            break;
884
        }
885

    
886
        /* apply logical operation */
887
        func_select = s->gr[3] >> 3;
888
        switch(func_select) {
889
        case 0:
890
        default:
891
            /* nothing to do */
892
            break;
893
        case 1:
894
            /* and */
895
            val &= s->latch;
896
            break;
897
        case 2:
898
            /* or */
899
            val |= s->latch;
900
            break;
901
        case 3:
902
            /* xor */
903
            val ^= s->latch;
904
            break;
905
        }
906

    
907
        /* apply bit mask */
908
        bit_mask |= bit_mask << 8;
909
        bit_mask |= bit_mask << 16;
910
        val = (val & bit_mask) | (s->latch & ~bit_mask);
911

    
912
    do_write:
913
        /* mask data according to sr[2] */
914
        mask = s->sr[2];
915
        s->plane_updated |= mask; /* only used to detect font change */
916
        write_mask = mask16[mask];
917
        ((uint32_t *)s->vram_ptr)[addr] =
918
            (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
919
            (val & write_mask);
920
#ifdef DEBUG_VGA_MEM
921
            printf("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n",
922
                   addr * 4, write_mask, val);
923
#endif
924
            cpu_physical_memory_set_dirty(s->vram_offset + (addr << 2));
925
    }
926
}
927

    
928
static void vga_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
929
{
930
#ifdef TARGET_WORDS_BIGENDIAN
931
    vga_mem_writeb(opaque, addr, (val >> 8) & 0xff);
932
    vga_mem_writeb(opaque, addr + 1, val & 0xff);
933
#else
934
    vga_mem_writeb(opaque, addr, val & 0xff);
935
    vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
936
#endif
937
}
938

    
939
static void vga_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
940
{
941
#ifdef TARGET_WORDS_BIGENDIAN
942
    vga_mem_writeb(opaque, addr, (val >> 24) & 0xff);
943
    vga_mem_writeb(opaque, addr + 1, (val >> 16) & 0xff);
944
    vga_mem_writeb(opaque, addr + 2, (val >> 8) & 0xff);
945
    vga_mem_writeb(opaque, addr + 3, val & 0xff);
946
#else
947
    vga_mem_writeb(opaque, addr, val & 0xff);
948
    vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
949
    vga_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff);
950
    vga_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff);
951
#endif
952
}
953

    
954
typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
955
                             const uint8_t *font_ptr, int h,
956
                             uint32_t fgcol, uint32_t bgcol);
957
typedef void vga_draw_glyph9_func(uint8_t *d, int linesize,
958
                                  const uint8_t *font_ptr, int h,
959
                                  uint32_t fgcol, uint32_t bgcol, int dup9);
960
typedef void vga_draw_line_func(VGAState *s1, uint8_t *d,
961
                                const uint8_t *s, int width);
962

    
963
#define DEPTH 8
964
#include "vga_template.h"
965

    
966
#define DEPTH 15
967
#include "vga_template.h"
968

    
969
#define BGR_FORMAT
970
#define DEPTH 15
971
#include "vga_template.h"
972

    
973
#define DEPTH 16
974
#include "vga_template.h"
975

    
976
#define BGR_FORMAT
977
#define DEPTH 16
978
#include "vga_template.h"
979

    
980
#define DEPTH 32
981
#include "vga_template.h"
982

    
983
#define BGR_FORMAT
984
#define DEPTH 32
985
#include "vga_template.h"
986

    
987
static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
988
{
989
    unsigned int col;
990
    col = rgb_to_pixel8(r, g, b);
991
    col |= col << 8;
992
    col |= col << 16;
993
    return col;
994
}
995

    
996
static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b)
997
{
998
    unsigned int col;
999
    col = rgb_to_pixel15(r, g, b);
1000
    col |= col << 16;
1001
    return col;
1002
}
1003

    
1004
static unsigned int rgb_to_pixel15bgr_dup(unsigned int r, unsigned int g,
1005
                                          unsigned int b)
1006
{
1007
    unsigned int col;
1008
    col = rgb_to_pixel15bgr(r, g, b);
1009
    col |= col << 16;
1010
    return col;
1011
}
1012

    
1013
static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
1014
{
1015
    unsigned int col;
1016
    col = rgb_to_pixel16(r, g, b);
1017
    col |= col << 16;
1018
    return col;
1019
}
1020

    
1021
static unsigned int rgb_to_pixel16bgr_dup(unsigned int r, unsigned int g,
1022
                                          unsigned int b)
1023
{
1024
    unsigned int col;
1025
    col = rgb_to_pixel16bgr(r, g, b);
1026
    col |= col << 16;
1027
    return col;
1028
}
1029

    
1030
static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
1031
{
1032
    unsigned int col;
1033
    col = rgb_to_pixel32(r, g, b);
1034
    return col;
1035
}
1036

    
1037
static unsigned int rgb_to_pixel32bgr_dup(unsigned int r, unsigned int g, unsigned b)
1038
{
1039
    unsigned int col;
1040
    col = rgb_to_pixel32bgr(r, g, b);
1041
    return col;
1042
}
1043

    
1044
/* return true if the palette was modified */
1045
static int update_palette16(VGAState *s)
1046
{
1047
    int full_update, i;
1048
    uint32_t v, col, *palette;
1049

    
1050
    full_update = 0;
1051
    palette = s->last_palette;
1052
    for(i = 0; i < 16; i++) {
1053
        v = s->ar[i];
1054
        if (s->ar[0x10] & 0x80)
1055
            v = ((s->ar[0x14] & 0xf) << 4) | (v & 0xf);
1056
        else
1057
            v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f);
1058
        v = v * 3;
1059
        col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
1060
                              c6_to_8(s->palette[v + 1]),
1061
                              c6_to_8(s->palette[v + 2]));
1062
        if (col != palette[i]) {
1063
            full_update = 1;
1064
            palette[i] = col;
1065
        }
1066
    }
1067
    return full_update;
1068
}
1069

    
1070
/* return true if the palette was modified */
1071
static int update_palette256(VGAState *s)
1072
{
1073
    int full_update, i;
1074
    uint32_t v, col, *palette;
1075

    
1076
    full_update = 0;
1077
    palette = s->last_palette;
1078
    v = 0;
1079
    for(i = 0; i < 256; i++) {
1080
        if (s->dac_8bit) {
1081
          col = s->rgb_to_pixel(s->palette[v],
1082
                                s->palette[v + 1],
1083
                                s->palette[v + 2]);
1084
        } else {
1085
          col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
1086
                                c6_to_8(s->palette[v + 1]),
1087
                                c6_to_8(s->palette[v + 2]));
1088
        }
1089
        if (col != palette[i]) {
1090
            full_update = 1;
1091
            palette[i] = col;
1092
        }
1093
        v += 3;
1094
    }
1095
    return full_update;
1096
}
1097

    
1098
static void vga_get_offsets(VGAState *s,
1099
                            uint32_t *pline_offset,
1100
                            uint32_t *pstart_addr,
1101
                            uint32_t *pline_compare)
1102
{
1103
    uint32_t start_addr, line_offset, line_compare;
1104
#ifdef CONFIG_BOCHS_VBE
1105
    if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1106
        line_offset = s->vbe_line_offset;
1107
        start_addr = s->vbe_start_addr;
1108
        line_compare = 65535;
1109
    } else
1110
#endif
1111
    {
1112
        /* compute line_offset in bytes */
1113
        line_offset = s->cr[0x13];
1114
        line_offset <<= 3;
1115

    
1116
        /* starting address */
1117
        start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8);
1118

    
1119
        /* line compare */
1120
        line_compare = s->cr[0x18] |
1121
            ((s->cr[0x07] & 0x10) << 4) |
1122
            ((s->cr[0x09] & 0x40) << 3);
1123
    }
1124
    *pline_offset = line_offset;
1125
    *pstart_addr = start_addr;
1126
    *pline_compare = line_compare;
1127
}
1128

    
1129
/* update start_addr and line_offset. Return TRUE if modified */
1130
static int update_basic_params(VGAState *s)
1131
{
1132
    int full_update;
1133
    uint32_t start_addr, line_offset, line_compare;
1134

    
1135
    full_update = 0;
1136

    
1137
    s->get_offsets(s, &line_offset, &start_addr, &line_compare);
1138

    
1139
    if (line_offset != s->line_offset ||
1140
        start_addr != s->start_addr ||
1141
        line_compare != s->line_compare) {
1142
        s->line_offset = line_offset;
1143
        s->start_addr = start_addr;
1144
        s->line_compare = line_compare;
1145
        full_update = 1;
1146
    }
1147
    return full_update;
1148
}
1149

    
1150
#define NB_DEPTHS 7
1151

    
1152
static inline int get_depth_index(DisplayState *s)
1153
{
1154
    switch(s->depth) {
1155
    default:
1156
    case 8:
1157
        return 0;
1158
    case 15:
1159
        if (s->bgr)
1160
            return 5;
1161
        else
1162
            return 1;
1163
    case 16:
1164
        if (s->bgr)
1165
            return 6;
1166
        else
1167
            return 2;
1168
    case 32:
1169
        if (s->bgr)
1170
            return 4;
1171
        else
1172
            return 3;
1173
    }
1174
}
1175

    
1176
static vga_draw_glyph8_func *vga_draw_glyph8_table[NB_DEPTHS] = {
1177
    vga_draw_glyph8_8,
1178
    vga_draw_glyph8_16,
1179
    vga_draw_glyph8_16,
1180
    vga_draw_glyph8_32,
1181
    vga_draw_glyph8_32,
1182
    vga_draw_glyph8_16,
1183
    vga_draw_glyph8_16,
1184
};
1185

    
1186
static vga_draw_glyph8_func *vga_draw_glyph16_table[NB_DEPTHS] = {
1187
    vga_draw_glyph16_8,
1188
    vga_draw_glyph16_16,
1189
    vga_draw_glyph16_16,
1190
    vga_draw_glyph16_32,
1191
    vga_draw_glyph16_32,
1192
    vga_draw_glyph16_16,
1193
    vga_draw_glyph16_16,
1194
};
1195

    
1196
static vga_draw_glyph9_func *vga_draw_glyph9_table[NB_DEPTHS] = {
1197
    vga_draw_glyph9_8,
1198
    vga_draw_glyph9_16,
1199
    vga_draw_glyph9_16,
1200
    vga_draw_glyph9_32,
1201
    vga_draw_glyph9_32,
1202
    vga_draw_glyph9_16,
1203
    vga_draw_glyph9_16,
1204
};
1205

    
1206
static const uint8_t cursor_glyph[32 * 4] = {
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,
1222
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1223
};
1224

    
1225
/*
1226
 * Text mode update
1227
 * Missing:
1228
 * - double scan
1229
 * - double width
1230
 * - underline
1231
 * - flashing
1232
 */
1233
static void vga_draw_text(VGAState *s, int full_update)
1234
{
1235
    int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
1236
    int cx_min, cx_max, linesize, x_incr;
1237
    uint32_t offset, fgcol, bgcol, v, cursor_offset;
1238
    uint8_t *d1, *d, *src, *s1, *dest, *cursor_ptr;
1239
    const uint8_t *font_ptr, *font_base[2];
1240
    int dup9, line_offset, depth_index;
1241
    uint32_t *palette;
1242
    uint32_t *ch_attr_ptr;
1243
    vga_draw_glyph8_func *vga_draw_glyph8;
1244
    vga_draw_glyph9_func *vga_draw_glyph9;
1245

    
1246
    full_update |= update_palette16(s);
1247
    palette = s->last_palette;
1248

    
1249
    /* compute font data address (in plane 2) */
1250
    v = s->sr[3];
1251
    offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
1252
    if (offset != s->font_offsets[0]) {
1253
        s->font_offsets[0] = offset;
1254
        full_update = 1;
1255
    }
1256
    font_base[0] = s->vram_ptr + offset;
1257

    
1258
    offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
1259
    font_base[1] = s->vram_ptr + offset;
1260
    if (offset != s->font_offsets[1]) {
1261
        s->font_offsets[1] = offset;
1262
        full_update = 1;
1263
    }
1264
    if (s->plane_updated & (1 << 2)) {
1265
        /* if the plane 2 was modified since the last display, it
1266
           indicates the font may have been modified */
1267
        s->plane_updated = 0;
1268
        full_update = 1;
1269
    }
1270
    full_update |= update_basic_params(s);
1271

    
1272
    line_offset = s->line_offset;
1273
    s1 = s->vram_ptr + (s->start_addr * 4);
1274

    
1275
    /* total width & height */
1276
    cheight = (s->cr[9] & 0x1f) + 1;
1277
    cw = 8;
1278
    if (!(s->sr[1] & 0x01))
1279
        cw = 9;
1280
    if (s->sr[1] & 0x08)
1281
        cw = 16; /* NOTE: no 18 pixel wide */
1282
    x_incr = cw * ((s->ds->depth + 7) >> 3);
1283
    width = (s->cr[0x01] + 1);
1284
    if (s->cr[0x06] == 100) {
1285
        /* ugly hack for CGA 160x100x16 - explain me the logic */
1286
        height = 100;
1287
    } else {
1288
        height = s->cr[0x12] |
1289
            ((s->cr[0x07] & 0x02) << 7) |
1290
            ((s->cr[0x07] & 0x40) << 3);
1291
        height = (height + 1) / cheight;
1292
    }
1293
    if ((height * width) > CH_ATTR_SIZE) {
1294
        /* better than nothing: exit if transient size is too big */
1295
        return;
1296
    }
1297

    
1298
    if (width != s->last_width || height != s->last_height ||
1299
        cw != s->last_cw || cheight != s->last_ch) {
1300
        s->last_scr_width = width * cw;
1301
        s->last_scr_height = height * cheight;
1302
        qemu_console_resize(s->console, s->last_scr_width, s->last_scr_height);
1303
        s->last_width = width;
1304
        s->last_height = height;
1305
        s->last_ch = cheight;
1306
        s->last_cw = cw;
1307
        full_update = 1;
1308
    }
1309
    cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
1310
    if (cursor_offset != s->cursor_offset ||
1311
        s->cr[0xa] != s->cursor_start ||
1312
        s->cr[0xb] != s->cursor_end) {
1313
      /* if the cursor position changed, we update the old and new
1314
         chars */
1315
        if (s->cursor_offset < CH_ATTR_SIZE)
1316
            s->last_ch_attr[s->cursor_offset] = -1;
1317
        if (cursor_offset < CH_ATTR_SIZE)
1318
            s->last_ch_attr[cursor_offset] = -1;
1319
        s->cursor_offset = cursor_offset;
1320
        s->cursor_start = s->cr[0xa];
1321
        s->cursor_end = s->cr[0xb];
1322
    }
1323
    cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
1324

    
1325
    depth_index = get_depth_index(s->ds);
1326
    if (cw == 16)
1327
        vga_draw_glyph8 = vga_draw_glyph16_table[depth_index];
1328
    else
1329
        vga_draw_glyph8 = vga_draw_glyph8_table[depth_index];
1330
    vga_draw_glyph9 = vga_draw_glyph9_table[depth_index];
1331

    
1332
    dest = s->ds->data;
1333
    linesize = s->ds->linesize;
1334
    ch_attr_ptr = s->last_ch_attr;
1335
    for(cy = 0; cy < height; cy++) {
1336
        d1 = dest;
1337
        src = s1;
1338
        cx_min = width;
1339
        cx_max = -1;
1340
        for(cx = 0; cx < width; cx++) {
1341
            ch_attr = *(uint16_t *)src;
1342
            if (full_update || ch_attr != *ch_attr_ptr) {
1343
                if (cx < cx_min)
1344
                    cx_min = cx;
1345
                if (cx > cx_max)
1346
                    cx_max = cx;
1347
                *ch_attr_ptr = ch_attr;
1348
#ifdef WORDS_BIGENDIAN
1349
                ch = ch_attr >> 8;
1350
                cattr = ch_attr & 0xff;
1351
#else
1352
                ch = ch_attr & 0xff;
1353
                cattr = ch_attr >> 8;
1354
#endif
1355
                font_ptr = font_base[(cattr >> 3) & 1];
1356
                font_ptr += 32 * 4 * ch;
1357
                bgcol = palette[cattr >> 4];
1358
                fgcol = palette[cattr & 0x0f];
1359
                if (cw != 9) {
1360
                    vga_draw_glyph8(d1, linesize,
1361
                                    font_ptr, cheight, fgcol, bgcol);
1362
                } else {
1363
                    dup9 = 0;
1364
                    if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))
1365
                        dup9 = 1;
1366
                    vga_draw_glyph9(d1, linesize,
1367
                                    font_ptr, cheight, fgcol, bgcol, dup9);
1368
                }
1369
                if (src == cursor_ptr &&
1370
                    !(s->cr[0x0a] & 0x20)) {
1371
                    int line_start, line_last, h;
1372
                    /* draw the cursor */
1373
                    line_start = s->cr[0x0a] & 0x1f;
1374
                    line_last = s->cr[0x0b] & 0x1f;
1375
                    /* XXX: check that */
1376
                    if (line_last > cheight - 1)
1377
                        line_last = cheight - 1;
1378
                    if (line_last >= line_start && line_start < cheight) {
1379
                        h = line_last - line_start + 1;
1380
                        d = d1 + linesize * line_start;
1381
                        if (cw != 9) {
1382
                            vga_draw_glyph8(d, linesize,
1383
                                            cursor_glyph, h, fgcol, bgcol);
1384
                        } else {
1385
                            vga_draw_glyph9(d, linesize,
1386
                                            cursor_glyph, h, fgcol, bgcol, 1);
1387
                        }
1388
                    }
1389
                }
1390
            }
1391
            d1 += x_incr;
1392
            src += 4;
1393
            ch_attr_ptr++;
1394
        }
1395
        if (cx_max != -1) {
1396
            dpy_update(s->ds, cx_min * cw, cy * cheight,
1397
                       (cx_max - cx_min + 1) * cw, cheight);
1398
        }
1399
        dest += linesize * cheight;
1400
        s1 += line_offset;
1401
    }
1402
}
1403

    
1404
enum {
1405
    VGA_DRAW_LINE2,
1406
    VGA_DRAW_LINE2D2,
1407
    VGA_DRAW_LINE4,
1408
    VGA_DRAW_LINE4D2,
1409
    VGA_DRAW_LINE8D2,
1410
    VGA_DRAW_LINE8,
1411
    VGA_DRAW_LINE15,
1412
    VGA_DRAW_LINE16,
1413
    VGA_DRAW_LINE24,
1414
    VGA_DRAW_LINE32,
1415
    VGA_DRAW_LINE_NB,
1416
};
1417

    
1418
static vga_draw_line_func *vga_draw_line_table[NB_DEPTHS * VGA_DRAW_LINE_NB] = {
1419
    vga_draw_line2_8,
1420
    vga_draw_line2_16,
1421
    vga_draw_line2_16,
1422
    vga_draw_line2_32,
1423
    vga_draw_line2_32,
1424
    vga_draw_line2_16,
1425
    vga_draw_line2_16,
1426

    
1427
    vga_draw_line2d2_8,
1428
    vga_draw_line2d2_16,
1429
    vga_draw_line2d2_16,
1430
    vga_draw_line2d2_32,
1431
    vga_draw_line2d2_32,
1432
    vga_draw_line2d2_16,
1433
    vga_draw_line2d2_16,
1434

    
1435
    vga_draw_line4_8,
1436
    vga_draw_line4_16,
1437
    vga_draw_line4_16,
1438
    vga_draw_line4_32,
1439
    vga_draw_line4_32,
1440
    vga_draw_line4_16,
1441
    vga_draw_line4_16,
1442

    
1443
    vga_draw_line4d2_8,
1444
    vga_draw_line4d2_16,
1445
    vga_draw_line4d2_16,
1446
    vga_draw_line4d2_32,
1447
    vga_draw_line4d2_32,
1448
    vga_draw_line4d2_16,
1449
    vga_draw_line4d2_16,
1450

    
1451
    vga_draw_line8d2_8,
1452
    vga_draw_line8d2_16,
1453
    vga_draw_line8d2_16,
1454
    vga_draw_line8d2_32,
1455
    vga_draw_line8d2_32,
1456
    vga_draw_line8d2_16,
1457
    vga_draw_line8d2_16,
1458

    
1459
    vga_draw_line8_8,
1460
    vga_draw_line8_16,
1461
    vga_draw_line8_16,
1462
    vga_draw_line8_32,
1463
    vga_draw_line8_32,
1464
    vga_draw_line8_16,
1465
    vga_draw_line8_16,
1466

    
1467
    vga_draw_line15_8,
1468
    vga_draw_line15_15,
1469
    vga_draw_line15_16,
1470
    vga_draw_line15_32,
1471
    vga_draw_line15_32bgr,
1472
    vga_draw_line15_15bgr,
1473
    vga_draw_line15_16bgr,
1474

    
1475
    vga_draw_line16_8,
1476
    vga_draw_line16_15,
1477
    vga_draw_line16_16,
1478
    vga_draw_line16_32,
1479
    vga_draw_line16_32bgr,
1480
    vga_draw_line16_15bgr,
1481
    vga_draw_line16_16bgr,
1482

    
1483
    vga_draw_line24_8,
1484
    vga_draw_line24_15,
1485
    vga_draw_line24_16,
1486
    vga_draw_line24_32,
1487
    vga_draw_line24_32bgr,
1488
    vga_draw_line24_15bgr,
1489
    vga_draw_line24_16bgr,
1490

    
1491
    vga_draw_line32_8,
1492
    vga_draw_line32_15,
1493
    vga_draw_line32_16,
1494
    vga_draw_line32_32,
1495
    vga_draw_line32_32bgr,
1496
    vga_draw_line32_15bgr,
1497
    vga_draw_line32_16bgr,
1498
};
1499

    
1500
typedef unsigned int rgb_to_pixel_dup_func(unsigned int r, unsigned int g, unsigned b);
1501

    
1502
static rgb_to_pixel_dup_func *rgb_to_pixel_dup_table[NB_DEPTHS] = {
1503
    rgb_to_pixel8_dup,
1504
    rgb_to_pixel15_dup,
1505
    rgb_to_pixel16_dup,
1506
    rgb_to_pixel32_dup,
1507
    rgb_to_pixel32bgr_dup,
1508
    rgb_to_pixel15bgr_dup,
1509
    rgb_to_pixel16bgr_dup,
1510
};
1511

    
1512
static int vga_get_bpp(VGAState *s)
1513
{
1514
    int ret;
1515
#ifdef CONFIG_BOCHS_VBE
1516
    if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1517
        ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
1518
    } else
1519
#endif
1520
    {
1521
        ret = 0;
1522
    }
1523
    return ret;
1524
}
1525

    
1526
static void vga_get_resolution(VGAState *s, int *pwidth, int *pheight)
1527
{
1528
    int width, height;
1529

    
1530
#ifdef CONFIG_BOCHS_VBE
1531
    if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1532
        width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
1533
        height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
1534
    } else
1535
#endif
1536
    {
1537
        width = (s->cr[0x01] + 1) * 8;
1538
        height = s->cr[0x12] |
1539
            ((s->cr[0x07] & 0x02) << 7) |
1540
            ((s->cr[0x07] & 0x40) << 3);
1541
        height = (height + 1);
1542
    }
1543
    *pwidth = width;
1544
    *pheight = height;
1545
}
1546

    
1547
void vga_invalidate_scanlines(VGAState *s, int y1, int y2)
1548
{
1549
    int y;
1550
    if (y1 >= VGA_MAX_HEIGHT)
1551
        return;
1552
    if (y2 >= VGA_MAX_HEIGHT)
1553
        y2 = VGA_MAX_HEIGHT;
1554
    for(y = y1; y < y2; y++) {
1555
        s->invalidated_y_table[y >> 5] |= 1 << (y & 0x1f);
1556
    }
1557
}
1558

    
1559
/*
1560
 * graphic modes
1561
 */
1562
static void vga_draw_graphic(VGAState *s, int full_update)
1563
{
1564
    int y1, y, update, page_min, page_max, linesize, y_start, double_scan, mask;
1565
    int width, height, shift_control, line_offset, page0, page1, bwidth, bits;
1566
    int disp_width, multi_scan, multi_run;
1567
    uint8_t *d;
1568
    uint32_t v, addr1, addr;
1569
    vga_draw_line_func *vga_draw_line;
1570

    
1571
    full_update |= update_basic_params(s);
1572

    
1573
    s->get_resolution(s, &width, &height);
1574
    disp_width = width;
1575

    
1576
    shift_control = (s->gr[0x05] >> 5) & 3;
1577
    double_scan = (s->cr[0x09] >> 7);
1578
    if (shift_control != 1) {
1579
        multi_scan = (((s->cr[0x09] & 0x1f) + 1) << double_scan) - 1;
1580
    } else {
1581
        /* in CGA modes, multi_scan is ignored */
1582
        /* XXX: is it correct ? */
1583
        multi_scan = double_scan;
1584
    }
1585
    multi_run = multi_scan;
1586
    if (shift_control != s->shift_control ||
1587
        double_scan != s->double_scan) {
1588
        full_update = 1;
1589
        s->shift_control = shift_control;
1590
        s->double_scan = double_scan;
1591
    }
1592

    
1593
    if (shift_control == 0) {
1594
        full_update |= update_palette16(s);
1595
        if (s->sr[0x01] & 8) {
1596
            v = VGA_DRAW_LINE4D2;
1597
            disp_width <<= 1;
1598
        } else {
1599
            v = VGA_DRAW_LINE4;
1600
        }
1601
        bits = 4;
1602
    } else if (shift_control == 1) {
1603
        full_update |= update_palette16(s);
1604
        if (s->sr[0x01] & 8) {
1605
            v = VGA_DRAW_LINE2D2;
1606
            disp_width <<= 1;
1607
        } else {
1608
            v = VGA_DRAW_LINE2;
1609
        }
1610
        bits = 4;
1611
    } else {
1612
        switch(s->get_bpp(s)) {
1613
        default:
1614
        case 0:
1615
            full_update |= update_palette256(s);
1616
            v = VGA_DRAW_LINE8D2;
1617
            bits = 4;
1618
            break;
1619
        case 8:
1620
            full_update |= update_palette256(s);
1621
            v = VGA_DRAW_LINE8;
1622
            bits = 8;
1623
            break;
1624
        case 15:
1625
            v = VGA_DRAW_LINE15;
1626
            bits = 16;
1627
            break;
1628
        case 16:
1629
            v = VGA_DRAW_LINE16;
1630
            bits = 16;
1631
            break;
1632
        case 24:
1633
            v = VGA_DRAW_LINE24;
1634
            bits = 24;
1635
            break;
1636
        case 32:
1637
            v = VGA_DRAW_LINE32;
1638
            bits = 32;
1639
            break;
1640
        }
1641
    }
1642
    vga_draw_line = vga_draw_line_table[v * NB_DEPTHS + get_depth_index(s->ds)];
1643

    
1644
    if (disp_width != s->last_width ||
1645
        height != s->last_height) {
1646
        qemu_console_resize(s->console, disp_width, height);
1647
        s->last_scr_width = disp_width;
1648
        s->last_scr_height = height;
1649
        s->last_width = disp_width;
1650
        s->last_height = height;
1651
        full_update = 1;
1652
    }
1653
    if (s->cursor_invalidate)
1654
        s->cursor_invalidate(s);
1655

    
1656
    line_offset = s->line_offset;
1657
#if 0
1658
    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",
1659
           width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]);
1660
#endif
1661
    addr1 = (s->start_addr * 4);
1662
    bwidth = (width * bits + 7) / 8;
1663
    y_start = -1;
1664
    page_min = 0x7fffffff;
1665
    page_max = -1;
1666
    d = s->ds->data;
1667
    linesize = s->ds->linesize;
1668
    y1 = 0;
1669
    for(y = 0; y < height; y++) {
1670
        addr = addr1;
1671
        if (!(s->cr[0x17] & 1)) {
1672
            int shift;
1673
            /* CGA compatibility handling */
1674
            shift = 14 + ((s->cr[0x17] >> 6) & 1);
1675
            addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
1676
        }
1677
        if (!(s->cr[0x17] & 2)) {
1678
            addr = (addr & ~0x8000) | ((y1 & 2) << 14);
1679
        }
1680
        page0 = s->vram_offset + (addr & TARGET_PAGE_MASK);
1681
        page1 = s->vram_offset + ((addr + bwidth - 1) & TARGET_PAGE_MASK);
1682
        update = full_update |
1683
            cpu_physical_memory_get_dirty(page0, VGA_DIRTY_FLAG) |
1684
            cpu_physical_memory_get_dirty(page1, VGA_DIRTY_FLAG);
1685
        if ((page1 - page0) > TARGET_PAGE_SIZE) {
1686
            /* if wide line, can use another page */
1687
            update |= cpu_physical_memory_get_dirty(page0 + TARGET_PAGE_SIZE,
1688
                                                    VGA_DIRTY_FLAG);
1689
        }
1690
        /* explicit invalidation for the hardware cursor */
1691
        update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
1692
        if (update) {
1693
            if (y_start < 0)
1694
                y_start = y;
1695
            if (page0 < page_min)
1696
                page_min = page0;
1697
            if (page1 > page_max)
1698
                page_max = page1;
1699
            vga_draw_line(s, d, s->vram_ptr + addr, width);
1700
            if (s->cursor_draw_line)
1701
                s->cursor_draw_line(s, d, y);
1702
        } else {
1703
            if (y_start >= 0) {
1704
                /* flush to display */
1705
                dpy_update(s->ds, 0, y_start,
1706
                           disp_width, y - y_start);
1707
                y_start = -1;
1708
            }
1709
        }
1710
        if (!multi_run) {
1711
            mask = (s->cr[0x17] & 3) ^ 3;
1712
            if ((y1 & mask) == mask)
1713
                addr1 += line_offset;
1714
            y1++;
1715
            multi_run = multi_scan;
1716
        } else {
1717
            multi_run--;
1718
        }
1719
        /* line compare acts on the displayed lines */
1720
        if (y == s->line_compare)
1721
            addr1 = 0;
1722
        d += linesize;
1723
    }
1724
    if (y_start >= 0) {
1725
        /* flush to display */
1726
        dpy_update(s->ds, 0, y_start,
1727
                   disp_width, y - y_start);
1728
    }
1729
    /* reset modified pages */
1730
    if (page_max != -1) {
1731
        cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
1732
                                        VGA_DIRTY_FLAG);
1733
    }
1734
    memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
1735
}
1736

    
1737
static void vga_draw_blank(VGAState *s, int full_update)
1738
{
1739
    int i, w, val;
1740
    uint8_t *d;
1741

    
1742
    if (!full_update)
1743
        return;
1744
    if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
1745
        return;
1746
    if (s->ds->depth == 8)
1747
        val = s->rgb_to_pixel(0, 0, 0);
1748
    else
1749
        val = 0;
1750
    w = s->last_scr_width * ((s->ds->depth + 7) >> 3);
1751
    d = s->ds->data;
1752
    for(i = 0; i < s->last_scr_height; i++) {
1753
        memset(d, val, w);
1754
        d += s->ds->linesize;
1755
    }
1756
    dpy_update(s->ds, 0, 0,
1757
               s->last_scr_width, s->last_scr_height);
1758
}
1759

    
1760
#define GMODE_TEXT     0
1761
#define GMODE_GRAPH    1
1762
#define GMODE_BLANK 2
1763

    
1764
static void vga_update_display(void *opaque)
1765
{
1766
    VGAState *s = (VGAState *)opaque;
1767
    int full_update, graphic_mode;
1768

    
1769
    if (s->ds->depth == 0) {
1770
        /* nothing to do */
1771
    } else {
1772
        s->rgb_to_pixel =
1773
            rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1774

    
1775
        full_update = 0;
1776
        if (!(s->ar_index & 0x20)) {
1777
            graphic_mode = GMODE_BLANK;
1778
        } else {
1779
            graphic_mode = s->gr[6] & 1;
1780
        }
1781
        if (graphic_mode != s->graphic_mode) {
1782
            s->graphic_mode = graphic_mode;
1783
            full_update = 1;
1784
        }
1785
        switch(graphic_mode) {
1786
        case GMODE_TEXT:
1787
            vga_draw_text(s, full_update);
1788
            break;
1789
        case GMODE_GRAPH:
1790
            vga_draw_graphic(s, full_update);
1791
            break;
1792
        case GMODE_BLANK:
1793
        default:
1794
            vga_draw_blank(s, full_update);
1795
            break;
1796
        }
1797
    }
1798
}
1799

    
1800
/* force a full display refresh */
1801
static void vga_invalidate_display(void *opaque)
1802
{
1803
    VGAState *s = (VGAState *)opaque;
1804

    
1805
    s->last_width = -1;
1806
    s->last_height = -1;
1807
}
1808

    
1809
static void vga_reset(VGAState *s)
1810
{
1811
    memset(s, 0, sizeof(VGAState));
1812
    s->graphic_mode = -1; /* force full update */
1813
}
1814

    
1815
#define TEXTMODE_X(x)        ((x) % width)
1816
#define TEXTMODE_Y(x)        ((x) / width)
1817
#define VMEM2CHTYPE(v)        ((v & 0xff0007ff) | \
1818
        ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1))
1819
/* relay text rendering to the display driver
1820
 * instead of doing a full vga_update_display() */
1821
static void vga_update_text(void *opaque, console_ch_t *chardata)
1822
{
1823
    VGAState *s = (VGAState *) opaque;
1824
    int graphic_mode, i, cursor_offset, cursor_visible;
1825
    int cw, cheight, width, height, size, c_min, c_max;
1826
    uint32_t *src;
1827
    console_ch_t *dst, val;
1828
    char msg_buffer[80];
1829
    int full_update = 0;
1830

    
1831
    if (!(s->ar_index & 0x20)) {
1832
        graphic_mode = GMODE_BLANK;
1833
    } else {
1834
        graphic_mode = s->gr[6] & 1;
1835
    }
1836
    if (graphic_mode != s->graphic_mode) {
1837
        s->graphic_mode = graphic_mode;
1838
        full_update = 1;
1839
    }
1840
    if (s->last_width == -1) {
1841
        s->last_width = 0;
1842
        full_update = 1;
1843
    }
1844

    
1845
    switch (graphic_mode) {
1846
    case GMODE_TEXT:
1847
        /* TODO: update palette */
1848
        full_update |= update_basic_params(s);
1849

    
1850
        /* total width & height */
1851
        cheight = (s->cr[9] & 0x1f) + 1;
1852
        cw = 8;
1853
        if (!(s->sr[1] & 0x01))
1854
            cw = 9;
1855
        if (s->sr[1] & 0x08)
1856
            cw = 16; /* NOTE: no 18 pixel wide */
1857
        width = (s->cr[0x01] + 1);
1858
        if (s->cr[0x06] == 100) {
1859
            /* ugly hack for CGA 160x100x16 - explain me the logic */
1860
            height = 100;
1861
        } else {
1862
            height = s->cr[0x12] | 
1863
                ((s->cr[0x07] & 0x02) << 7) | 
1864
                ((s->cr[0x07] & 0x40) << 3);
1865
            height = (height + 1) / cheight;
1866
        }
1867

    
1868
        size = (height * width);
1869
        if (size > CH_ATTR_SIZE) {
1870
            if (!full_update)
1871
                return;
1872

    
1873
            snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Text mode",
1874
                     width, height);
1875
            break;
1876
        }
1877

    
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;
1882
            qemu_console_resize(s->console, width, height);
1883
            s->last_width = width;
1884
            s->last_height = height;
1885
            s->last_ch = cheight;
1886
            s->last_cw = cw;
1887
            full_update = 1;
1888
        }
1889

    
1890
        /* Update "hardware" cursor */
1891
        cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
1892
        if (cursor_offset != s->cursor_offset ||
1893
            s->cr[0xa] != s->cursor_start ||
1894
            s->cr[0xb] != s->cursor_end || full_update) {
1895
            cursor_visible = !(s->cr[0xa] & 0x20);
1896
            if (cursor_visible && cursor_offset < size && cursor_offset >= 0)
1897
                dpy_cursor(s->ds,
1898
                           TEXTMODE_X(cursor_offset),
1899
                           TEXTMODE_Y(cursor_offset));
1900
            else
1901
                dpy_cursor(s->ds, -1, -1);
1902
            s->cursor_offset = cursor_offset;
1903
            s->cursor_start = s->cr[0xa];
1904
            s->cursor_end = s->cr[0xb];
1905
        }
1906

    
1907
        src = (uint32_t *) s->vram_ptr + s->start_addr;
1908
        dst = chardata;
1909

    
1910
        if (full_update) {
1911
            for (i = 0; i < size; src ++, dst ++, i ++)
1912
                console_write_ch(dst, VMEM2CHTYPE(*src));
1913

    
1914
            dpy_update(s->ds, 0, 0, width, height);
1915
        } else {
1916
            c_max = 0;
1917

    
1918
            for (i = 0; i < size; src ++, dst ++, i ++) {
1919
                console_write_ch(&val, VMEM2CHTYPE(*src));
1920
                if (*dst != val) {
1921
                    *dst = val;
1922
                    c_max = i;
1923
                    break;
1924
                }
1925
            }
1926
            c_min = i;
1927
            for (; i < size; src ++, dst ++, i ++) {
1928
                console_write_ch(&val, VMEM2CHTYPE(*src));
1929
                if (*dst != val) {
1930
                    *dst = val;
1931
                    c_max = i;
1932
                }
1933
            }
1934

    
1935
            if (c_min <= c_max) {
1936
                i = TEXTMODE_Y(c_min);
1937
                dpy_update(s->ds, 0, i, width, TEXTMODE_Y(c_max) - i + 1);
1938
            }
1939
        }
1940

    
1941
        return;
1942
    case GMODE_GRAPH:
1943
        if (!full_update)
1944
            return;
1945

    
1946
        s->get_resolution(s, &width, &height);
1947
        snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Graphic mode",
1948
                 width, height);
1949
        break;
1950
    case GMODE_BLANK:
1951
    default:
1952
        if (!full_update)
1953
            return;
1954

    
1955
        snprintf(msg_buffer, sizeof(msg_buffer), "VGA Blank mode");
1956
        break;
1957
    }
1958

    
1959
    /* Display a message */
1960
    s->last_width = 60;
1961
    s->last_height = height = 3;
1962
    dpy_cursor(s->ds, -1, -1);
1963
    qemu_console_resize(s->console, s->last_width, height);
1964

    
1965
    for (dst = chardata, i = 0; i < s->last_width * height; i ++)
1966
        console_write_ch(dst ++, ' ');
1967

    
1968
    size = strlen(msg_buffer);
1969
    width = (s->last_width - size) / 2;
1970
    dst = chardata + s->last_width + width;
1971
    for (i = 0; i < size; i ++)
1972
        console_write_ch(dst ++, 0x00200100 | msg_buffer[i]);
1973

    
1974
    dpy_update(s->ds, 0, 0, s->last_width, height);
1975
}
1976

    
1977
static CPUReadMemoryFunc *vga_mem_read[3] = {
1978
    vga_mem_readb,
1979
    vga_mem_readw,
1980
    vga_mem_readl,
1981
};
1982

    
1983
static CPUWriteMemoryFunc *vga_mem_write[3] = {
1984
    vga_mem_writeb,
1985
    vga_mem_writew,
1986
    vga_mem_writel,
1987
};
1988

    
1989
static void vga_save(QEMUFile *f, void *opaque)
1990
{
1991
    VGAState *s = opaque;
1992
    int i;
1993

    
1994
    if (s->pci_dev)
1995
        pci_device_save(s->pci_dev, f);
1996

    
1997
    qemu_put_be32s(f, &s->latch);
1998
    qemu_put_8s(f, &s->sr_index);
1999
    qemu_put_buffer(f, s->sr, 8);
2000
    qemu_put_8s(f, &s->gr_index);
2001
    qemu_put_buffer(f, s->gr, 16);
2002
    qemu_put_8s(f, &s->ar_index);
2003
    qemu_put_buffer(f, s->ar, 21);
2004
    qemu_put_be32(f, s->ar_flip_flop);
2005
    qemu_put_8s(f, &s->cr_index);
2006
    qemu_put_buffer(f, s->cr, 256);
2007
    qemu_put_8s(f, &s->msr);
2008
    qemu_put_8s(f, &s->fcr);
2009
    qemu_put_byte(f, s->st00);
2010
    qemu_put_8s(f, &s->st01);
2011

    
2012
    qemu_put_8s(f, &s->dac_state);
2013
    qemu_put_8s(f, &s->dac_sub_index);
2014
    qemu_put_8s(f, &s->dac_read_index);
2015
    qemu_put_8s(f, &s->dac_write_index);
2016
    qemu_put_buffer(f, s->dac_cache, 3);
2017
    qemu_put_buffer(f, s->palette, 768);
2018

    
2019
    qemu_put_be32(f, s->bank_offset);
2020
#ifdef CONFIG_BOCHS_VBE
2021
    qemu_put_byte(f, 1);
2022
    qemu_put_be16s(f, &s->vbe_index);
2023
    for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
2024
        qemu_put_be16s(f, &s->vbe_regs[i]);
2025
    qemu_put_be32s(f, &s->vbe_start_addr);
2026
    qemu_put_be32s(f, &s->vbe_line_offset);
2027
    qemu_put_be32s(f, &s->vbe_bank_mask);
2028
#else
2029
    qemu_put_byte(f, 0);
2030
#endif
2031
}
2032

    
2033
static int vga_load(QEMUFile *f, void *opaque, int version_id)
2034
{
2035
    VGAState *s = opaque;
2036
    int is_vbe, i, ret;
2037

    
2038
    if (version_id > 2)
2039
        return -EINVAL;
2040

    
2041
    if (s->pci_dev && version_id >= 2) {
2042
        ret = pci_device_load(s->pci_dev, f);
2043
        if (ret < 0)
2044
            return ret;
2045
    }
2046

    
2047
    qemu_get_be32s(f, &s->latch);
2048
    qemu_get_8s(f, &s->sr_index);
2049
    qemu_get_buffer(f, s->sr, 8);
2050
    qemu_get_8s(f, &s->gr_index);
2051
    qemu_get_buffer(f, s->gr, 16);
2052
    qemu_get_8s(f, &s->ar_index);
2053
    qemu_get_buffer(f, s->ar, 21);
2054
    s->ar_flip_flop=qemu_get_be32(f);
2055
    qemu_get_8s(f, &s->cr_index);
2056
    qemu_get_buffer(f, s->cr, 256);
2057
    qemu_get_8s(f, &s->msr);
2058
    qemu_get_8s(f, &s->fcr);
2059
    qemu_get_8s(f, &s->st00);
2060
    qemu_get_8s(f, &s->st01);
2061

    
2062
    qemu_get_8s(f, &s->dac_state);
2063
    qemu_get_8s(f, &s->dac_sub_index);
2064
    qemu_get_8s(f, &s->dac_read_index);
2065
    qemu_get_8s(f, &s->dac_write_index);
2066
    qemu_get_buffer(f, s->dac_cache, 3);
2067
    qemu_get_buffer(f, s->palette, 768);
2068

    
2069
    s->bank_offset=qemu_get_be32(f);
2070
    is_vbe = qemu_get_byte(f);
2071
#ifdef CONFIG_BOCHS_VBE
2072
    if (!is_vbe)
2073
        return -EINVAL;
2074
    qemu_get_be16s(f, &s->vbe_index);
2075
    for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
2076
        qemu_get_be16s(f, &s->vbe_regs[i]);
2077
    qemu_get_be32s(f, &s->vbe_start_addr);
2078
    qemu_get_be32s(f, &s->vbe_line_offset);
2079
    qemu_get_be32s(f, &s->vbe_bank_mask);
2080
#else
2081
    if (is_vbe)
2082
        return -EINVAL;
2083
#endif
2084

    
2085
    /* force refresh */
2086
    s->graphic_mode = -1;
2087
    return 0;
2088
}
2089

    
2090
typedef struct PCIVGAState {
2091
    PCIDevice dev;
2092
    VGAState vga_state;
2093
} PCIVGAState;
2094

    
2095
static void vga_map(PCIDevice *pci_dev, int region_num,
2096
                    uint32_t addr, uint32_t size, int type)
2097
{
2098
    PCIVGAState *d = (PCIVGAState *)pci_dev;
2099
    VGAState *s = &d->vga_state;
2100
    if (region_num == PCI_ROM_SLOT) {
2101
        cpu_register_physical_memory(addr, s->bios_size, s->bios_offset);
2102
    } else {
2103
        cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
2104
    }
2105
}
2106

    
2107
void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base,
2108
                     unsigned long vga_ram_offset, int vga_ram_size)
2109
{
2110
    int i, j, v, b;
2111

    
2112
    for(i = 0;i < 256; i++) {
2113
        v = 0;
2114
        for(j = 0; j < 8; j++) {
2115
            v |= ((i >> j) & 1) << (j * 4);
2116
        }
2117
        expand4[i] = v;
2118

    
2119
        v = 0;
2120
        for(j = 0; j < 4; j++) {
2121
            v |= ((i >> (2 * j)) & 3) << (j * 4);
2122
        }
2123
        expand2[i] = v;
2124
    }
2125
    for(i = 0; i < 16; i++) {
2126
        v = 0;
2127
        for(j = 0; j < 4; j++) {
2128
            b = ((i >> j) & 1);
2129
            v |= b << (2 * j);
2130
            v |= b << (2 * j + 1);
2131
        }
2132
        expand4to8[i] = v;
2133
    }
2134

    
2135
    vga_reset(s);
2136

    
2137
    s->vram_ptr = vga_ram_base;
2138
    s->vram_offset = vga_ram_offset;
2139
    s->vram_size = vga_ram_size;
2140
    s->ds = ds;
2141
    s->get_bpp = vga_get_bpp;
2142
    s->get_offsets = vga_get_offsets;
2143
    s->get_resolution = vga_get_resolution;
2144
    s->update = vga_update_display;
2145
    s->invalidate = vga_invalidate_display;
2146
    s->screen_dump = vga_screen_dump;
2147
    s->text_update = vga_update_text;
2148
    switch (vga_retrace_method) {
2149
    case VGA_RETRACE_DUMB:
2150
        s->retrace = vga_dumb_retrace;
2151
        s->update_retrace_info = vga_dumb_update_retrace_info;
2152
        break;
2153

    
2154
    case VGA_RETRACE_PRECISE:
2155
        s->retrace = vga_precise_retrace;
2156
        s->update_retrace_info = vga_precise_update_retrace_info;
2157
        memset(&s->retrace_info, 0, sizeof (s->retrace_info));
2158
        break;
2159
    }
2160
}
2161

    
2162
/* used by both ISA and PCI */
2163
void vga_init(VGAState *s)
2164
{
2165
    int vga_io_memory;
2166

    
2167
    register_savevm("vga", 0, 2, vga_save, vga_load, s);
2168

    
2169
    register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
2170

    
2171
    register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
2172
    register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);
2173
    register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);
2174
    register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);
2175

    
2176
    register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
2177

    
2178
    register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);
2179
    register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);
2180
    register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
2181
    register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
2182
    s->bank_offset = 0;
2183

    
2184
#ifdef CONFIG_BOCHS_VBE
2185
    s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0;
2186
    s->vbe_bank_mask = ((s->vram_size >> 16) - 1);
2187
#if defined (TARGET_I386)
2188
    register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
2189
    register_ioport_read(0x1cf, 1, 2, vbe_ioport_read_data, s);
2190

    
2191
    register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
2192
    register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data, s);
2193

    
2194
    /* old Bochs IO ports */
2195
    register_ioport_read(0xff80, 1, 2, vbe_ioport_read_index, s);
2196
    register_ioport_read(0xff81, 1, 2, vbe_ioport_read_data, s);
2197

    
2198
    register_ioport_write(0xff80, 1, 2, vbe_ioport_write_index, s);
2199
    register_ioport_write(0xff81, 1, 2, vbe_ioport_write_data, s);
2200
#else
2201
    register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
2202
    register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data, s);
2203

    
2204
    register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
2205
    register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data, s);
2206
#endif
2207
#endif /* CONFIG_BOCHS_VBE */
2208

    
2209
    vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s);
2210
    cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
2211
                                 vga_io_memory);
2212
}
2213

    
2214
/* Memory mapped interface */
2215
static uint32_t vga_mm_readb (void *opaque, target_phys_addr_t addr)
2216
{
2217
    VGAState *s = opaque;
2218

    
2219
    return vga_ioport_read(s, (addr - s->base_ctrl) >> s->it_shift) & 0xff;
2220
}
2221

    
2222
static void vga_mm_writeb (void *opaque,
2223
                           target_phys_addr_t addr, uint32_t value)
2224
{
2225
    VGAState *s = opaque;
2226

    
2227
    vga_ioport_write(s, (addr - s->base_ctrl) >> s->it_shift, value & 0xff);
2228
}
2229

    
2230
static uint32_t vga_mm_readw (void *opaque, target_phys_addr_t addr)
2231
{
2232
    VGAState *s = opaque;
2233

    
2234
    return vga_ioport_read(s, (addr - s->base_ctrl) >> s->it_shift) & 0xffff;
2235
}
2236

    
2237
static void vga_mm_writew (void *opaque,
2238
                           target_phys_addr_t addr, uint32_t value)
2239
{
2240
    VGAState *s = opaque;
2241

    
2242
    vga_ioport_write(s, (addr - s->base_ctrl) >> s->it_shift, value & 0xffff);
2243
}
2244

    
2245
static uint32_t vga_mm_readl (void *opaque, target_phys_addr_t addr)
2246
{
2247
    VGAState *s = opaque;
2248

    
2249
    return vga_ioport_read(s, (addr - s->base_ctrl) >> s->it_shift);
2250
}
2251

    
2252
static void vga_mm_writel (void *opaque,
2253
                           target_phys_addr_t addr, uint32_t value)
2254
{
2255
    VGAState *s = opaque;
2256

    
2257
    vga_ioport_write(s, (addr - s->base_ctrl) >> s->it_shift, value);
2258
}
2259

    
2260
static CPUReadMemoryFunc *vga_mm_read_ctrl[] = {
2261
    &vga_mm_readb,
2262
    &vga_mm_readw,
2263
    &vga_mm_readl,
2264
};
2265

    
2266
static CPUWriteMemoryFunc *vga_mm_write_ctrl[] = {
2267
    &vga_mm_writeb,
2268
    &vga_mm_writew,
2269
    &vga_mm_writel,
2270
};
2271

    
2272
static void vga_mm_init(VGAState *s, target_phys_addr_t vram_base,
2273
                        target_phys_addr_t ctrl_base, int it_shift)
2274
{
2275
    int s_ioport_ctrl, vga_io_memory;
2276

    
2277
    s->base_ctrl = ctrl_base;
2278
    s->it_shift = it_shift;
2279
    s_ioport_ctrl = cpu_register_io_memory(0, vga_mm_read_ctrl, vga_mm_write_ctrl, s);
2280
    vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s);
2281

    
2282
    register_savevm("vga", 0, 2, vga_save, vga_load, s);
2283

    
2284
    cpu_register_physical_memory(ctrl_base, 0x100000, s_ioport_ctrl);
2285
    s->bank_offset = 0;
2286
    cpu_register_physical_memory(vram_base + 0x000a0000, 0x20000, vga_io_memory);
2287
}
2288

    
2289
int isa_vga_init(DisplayState *ds, uint8_t *vga_ram_base,
2290
                 unsigned long vga_ram_offset, int vga_ram_size)
2291
{
2292
    VGAState *s;
2293

    
2294
    s = qemu_mallocz(sizeof(VGAState));
2295
    if (!s)
2296
        return -1;
2297

    
2298
    vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size);
2299
    vga_init(s);
2300

    
2301
    s->console = graphic_console_init(s->ds, s->update, s->invalidate,
2302
                                      s->screen_dump, s->text_update, s);
2303

    
2304
#ifdef CONFIG_BOCHS_VBE
2305
    /* XXX: use optimized standard vga accesses */
2306
    cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
2307
                                 vga_ram_size, vga_ram_offset);
2308
#endif
2309
    return 0;
2310
}
2311

    
2312
int isa_vga_mm_init(DisplayState *ds, uint8_t *vga_ram_base,
2313
                    unsigned long vga_ram_offset, int vga_ram_size,
2314
                    target_phys_addr_t vram_base, target_phys_addr_t ctrl_base,
2315
                    int it_shift)
2316
{
2317
    VGAState *s;
2318

    
2319
    s = qemu_mallocz(sizeof(VGAState));
2320
    if (!s)
2321
        return -1;
2322

    
2323
    vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size);
2324
    vga_mm_init(s, vram_base, ctrl_base, it_shift);
2325

    
2326
    s->console = graphic_console_init(s->ds, s->update, s->invalidate,
2327
                                      s->screen_dump, s->text_update, s);
2328

    
2329
#ifdef CONFIG_BOCHS_VBE
2330
    /* XXX: use optimized standard vga accesses */
2331
    cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
2332
                                 vga_ram_size, vga_ram_offset);
2333
#endif
2334
    return 0;
2335
}
2336

    
2337
int pci_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base,
2338
                 unsigned long vga_ram_offset, int vga_ram_size,
2339
                 unsigned long vga_bios_offset, int vga_bios_size)
2340
{
2341
    PCIVGAState *d;
2342
    VGAState *s;
2343
    uint8_t *pci_conf;
2344

    
2345
    d = (PCIVGAState *)pci_register_device(bus, "VGA",
2346
                                           sizeof(PCIVGAState),
2347
                                           -1, NULL, NULL);
2348
    if (!d)
2349
        return -1;
2350
    s = &d->vga_state;
2351

    
2352
    vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size);
2353
    vga_init(s);
2354

    
2355
    s->console = graphic_console_init(s->ds, s->update, s->invalidate,
2356
                                      s->screen_dump, s->text_update, s);
2357

    
2358
    s->pci_dev = &d->dev;
2359

    
2360
    pci_conf = d->dev.config;
2361
    pci_conf[0x00] = 0x34; // dummy VGA (same as Bochs ID)
2362
    pci_conf[0x01] = 0x12;
2363
    pci_conf[0x02] = 0x11;
2364
    pci_conf[0x03] = 0x11;
2365
    pci_conf[0x0a] = 0x00; // VGA controller
2366
    pci_conf[0x0b] = 0x03;
2367
    pci_conf[0x0e] = 0x00; // header_type
2368

    
2369
    /* XXX: vga_ram_size must be a power of two */
2370
    pci_register_io_region(&d->dev, 0, vga_ram_size,
2371
                           PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
2372
    if (vga_bios_size != 0) {
2373
        unsigned int bios_total_size;
2374
        s->bios_offset = vga_bios_offset;
2375
        s->bios_size = vga_bios_size;
2376
        /* must be a power of two */
2377
        bios_total_size = 1;
2378
        while (bios_total_size < vga_bios_size)
2379
            bios_total_size <<= 1;
2380
        pci_register_io_region(&d->dev, PCI_ROM_SLOT, bios_total_size,
2381
                               PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
2382
    }
2383
    return 0;
2384
}
2385

    
2386
/********************************************************/
2387
/* vga screen dump */
2388

    
2389
static int vga_save_w, vga_save_h;
2390

    
2391
static void vga_save_dpy_update(DisplayState *s,
2392
                                int x, int y, int w, int h)
2393
{
2394
}
2395

    
2396
static void vga_save_dpy_resize(DisplayState *s, int w, int h)
2397
{
2398
    s->linesize = w * 4;
2399
    s->data = qemu_mallocz(h * s->linesize);
2400
    vga_save_w = w;
2401
    vga_save_h = h;
2402
}
2403

    
2404
static void vga_save_dpy_refresh(DisplayState *s)
2405
{
2406
}
2407

    
2408
int ppm_save(const char *filename, uint8_t *data,
2409
             int w, int h, int linesize)
2410
{
2411
    FILE *f;
2412
    uint8_t *d, *d1;
2413
    unsigned int v;
2414
    int y, x;
2415

    
2416
    f = fopen(filename, "wb");
2417
    if (!f)
2418
        return -1;
2419
    fprintf(f, "P6\n%d %d\n%d\n",
2420
            w, h, 255);
2421
    d1 = data;
2422
    for(y = 0; y < h; y++) {
2423
        d = d1;
2424
        for(x = 0; x < w; x++) {
2425
            v = *(uint32_t *)d;
2426
            fputc((v >> 16) & 0xff, f);
2427
            fputc((v >> 8) & 0xff, f);
2428
            fputc((v) & 0xff, f);
2429
            d += 4;
2430
        }
2431
        d1 += linesize;
2432
    }
2433
    fclose(f);
2434
    return 0;
2435
}
2436

    
2437
/* save the vga display in a PPM image even if no display is
2438
   available */
2439
static void vga_screen_dump(void *opaque, const char *filename)
2440
{
2441
    VGAState *s = (VGAState *)opaque;
2442
    DisplayState *saved_ds, ds1, *ds = &ds1;
2443

    
2444
    /* XXX: this is a little hackish */
2445
    vga_invalidate_display(s);
2446
    saved_ds = s->ds;
2447

    
2448
    memset(ds, 0, sizeof(DisplayState));
2449
    ds->dpy_update = vga_save_dpy_update;
2450
    ds->dpy_resize = vga_save_dpy_resize;
2451
    ds->dpy_refresh = vga_save_dpy_refresh;
2452
    ds->depth = 32;
2453

    
2454
    s->ds = ds;
2455
    s->graphic_mode = -1;
2456
    vga_update_display(s);
2457

    
2458
    if (ds->data) {
2459
        ppm_save(filename, ds->data, vga_save_w, vga_save_h,
2460
                 s->ds->linesize);
2461
        qemu_free(ds->data);
2462
    }
2463
    s->ds = saved_ds;
2464
}