source: trunk/packages/xen-3.1/xen-3.1/tools/ioemu/hw/vga.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 18 years ago

Add xen and xen-common

File size: 61.8 KB
Line 
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 "vl.h"
25#include "vga_int.h"
26
27//#define DEBUG_VGA
28//#define DEBUG_VGA_MEM
29//#define DEBUG_VGA_REG
30
31//#define DEBUG_BOCHS_VBE
32
33/* force some bits to zero */
34const uint8_t sr_mask[8] = {
35    (uint8_t)~0xfc,
36    (uint8_t)~0xc2,
37    (uint8_t)~0xf0,
38    (uint8_t)~0xc0,
39    (uint8_t)~0xf1,
40    (uint8_t)~0xff,
41    (uint8_t)~0xff,
42    (uint8_t)~0x00,
43};
44
45const uint8_t gr_mask[16] = {
46    (uint8_t)~0xf0, /* 0x00 */
47    (uint8_t)~0xf0, /* 0x01 */
48    (uint8_t)~0xf0, /* 0x02 */
49    (uint8_t)~0xe0, /* 0x03 */
50    (uint8_t)~0xfc, /* 0x04 */
51    (uint8_t)~0x84, /* 0x05 */
52    (uint8_t)~0xf0, /* 0x06 */
53    (uint8_t)~0xf0, /* 0x07 */
54    (uint8_t)~0x00, /* 0x08 */
55    (uint8_t)~0xff, /* 0x09 */
56    (uint8_t)~0xff, /* 0x0a */
57    (uint8_t)~0xff, /* 0x0b */
58    (uint8_t)~0xff, /* 0x0c */
59    (uint8_t)~0xff, /* 0x0d */
60    (uint8_t)~0xff, /* 0x0e */
61    (uint8_t)~0xff, /* 0x0f */
62};
63
64#define cbswap_32(__x) \
65((uint32_t)( \
66                (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
67                (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) <<  8) | \
68                (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >>  8) | \
69                (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
70
71#ifdef WORDS_BIGENDIAN
72#define PAT(x) cbswap_32(x)
73#else
74#define PAT(x) (x)
75#endif
76
77#ifdef WORDS_BIGENDIAN
78#define BIG 1
79#else
80#define BIG 0
81#endif
82
83#ifdef WORDS_BIGENDIAN
84#define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
85#else
86#define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
87#endif
88
89static const uint32_t mask16[16] = {
90    PAT(0x00000000),
91    PAT(0x000000ff),
92    PAT(0x0000ff00),
93    PAT(0x0000ffff),
94    PAT(0x00ff0000),
95    PAT(0x00ff00ff),
96    PAT(0x00ffff00),
97    PAT(0x00ffffff),
98    PAT(0xff000000),
99    PAT(0xff0000ff),
100    PAT(0xff00ff00),
101    PAT(0xff00ffff),
102    PAT(0xffff0000),
103    PAT(0xffff00ff),
104    PAT(0xffffff00),
105    PAT(0xffffffff),
106};
107
108#undef PAT
109
110#ifdef WORDS_BIGENDIAN
111#define PAT(x) (x)
112#else
113#define PAT(x) cbswap_32(x)
114#endif
115
116static const uint32_t dmask16[16] = {
117    PAT(0x00000000),
118    PAT(0x000000ff),
119    PAT(0x0000ff00),
120    PAT(0x0000ffff),
121    PAT(0x00ff0000),
122    PAT(0x00ff00ff),
123    PAT(0x00ffff00),
124    PAT(0x00ffffff),
125    PAT(0xff000000),
126    PAT(0xff0000ff),
127    PAT(0xff00ff00),
128    PAT(0xff00ffff),
129    PAT(0xffff0000),
130    PAT(0xffff00ff),
131    PAT(0xffffff00),
132    PAT(0xffffffff),
133};
134
135static const uint32_t dmask4[4] = {
136    PAT(0x00000000),
137    PAT(0x0000ffff),
138    PAT(0xffff0000),
139    PAT(0xffffffff),
140};
141
142static uint32_t expand4[256];
143static uint16_t expand2[256];
144static uint8_t expand4to8[16];
145
146VGAState *vga_state;
147int vga_io_memory;
148
149static void vga_screen_dump(void *opaque, const char *filename);
150
151static uint32_t vga_ioport_read(void *opaque, uint32_t addr)
152{
153    VGAState *s = opaque;
154    int val, index;
155
156    /* check port range access depending on color/monochrome mode */
157    if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
158        (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION))) {
159        val = 0xff;
160    } else {
161        switch(addr) {
162        case 0x3c0:
163            if (s->ar_flip_flop == 0) {
164                val = s->ar_index;
165            } else {
166                val = 0;
167            }
168            break;
169        case 0x3c1:
170            index = s->ar_index & 0x1f;
171            if (index < 21) 
172                val = s->ar[index];
173            else
174                val = 0;
175            break;
176        case 0x3c2:
177            val = s->st00;
178            break;
179        case 0x3c4:
180            val = s->sr_index;
181            break;
182        case 0x3c5:
183            val = s->sr[s->sr_index];
184#ifdef DEBUG_VGA_REG
185            printf("vga: read SR%x = 0x%02x\n", s->sr_index, val);
186#endif
187            break;
188        case 0x3c7:
189            val = s->dac_state;
190            break;
191        case 0x3c8:
192            val = s->dac_write_index;
193            break;
194        case 0x3c9:
195            val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
196            if (++s->dac_sub_index == 3) {
197                s->dac_sub_index = 0;
198                s->dac_read_index++;
199            }
200            break;
201        case 0x3ca:
202            val = s->fcr;
203            break;
204        case 0x3cc:
205            val = s->msr;
206            break;
207        case 0x3ce:
208            val = s->gr_index;
209            break;
210        case 0x3cf:
211            val = s->gr[s->gr_index];
212#ifdef DEBUG_VGA_REG
213            printf("vga: read GR%x = 0x%02x\n", s->gr_index, val);
214#endif
215            break;
216        case 0x3b4:
217        case 0x3d4:
218            val = s->cr_index;
219            break;
220        case 0x3b5:
221        case 0x3d5:
222            val = s->cr[s->cr_index];
223#ifdef DEBUG_VGA_REG
224            printf("vga: read CR%x = 0x%02x\n", s->cr_index, val);
225#endif
226            break;
227        case 0x3ba:
228        case 0x3da:
229            /* just toggle to fool polling */
230            s->st01 ^= ST01_V_RETRACE | ST01_DISP_ENABLE;
231            val = s->st01;
232            s->ar_flip_flop = 0;
233            break;
234        default:
235            val = 0x00;
236            break;
237        }
238    }
239#if defined(DEBUG_VGA)
240    printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
241#endif
242    return val;
243}
244
245static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
246{
247    VGAState *s = opaque;
248    int index;
249
250    /* check port range access depending on color/monochrome mode */
251    if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
252        (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION)))
253        return;
254
255#ifdef DEBUG_VGA
256    printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
257#endif
258
259    switch(addr) {
260    case 0x3c0:
261        if (s->ar_flip_flop == 0) {
262            val &= 0x3f;
263            s->ar_index = val;
264        } else {
265            index = s->ar_index & 0x1f;
266            switch(index) {
267            case 0x00 ... 0x0f:
268                s->ar[index] = val & 0x3f;
269                break;
270            case 0x10:
271                s->ar[index] = val & ~0x10;
272                break;
273            case 0x11:
274                s->ar[index] = val;
275                break;
276            case 0x12:
277                s->ar[index] = val & ~0xc0;
278                break;
279            case 0x13:
280                s->ar[index] = val & ~0xf0;
281                break;
282            case 0x14:
283                s->ar[index] = val & ~0xf0;
284                break;
285            default:
286                break;
287            }
288        }
289        s->ar_flip_flop ^= 1;
290        break;
291    case 0x3c2:
292        s->msr = val & ~0x10;
293        break;
294    case 0x3c4:
295        s->sr_index = val & 7;
296        break;
297    case 0x3c5:
298#ifdef DEBUG_VGA_REG
299        printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
300#endif
301        s->sr[s->sr_index] = val & sr_mask[s->sr_index];
302        break;
303    case 0x3c7:
304        s->dac_read_index = val;
305        s->dac_sub_index = 0;
306        s->dac_state = 3;
307        break;
308    case 0x3c8:
309        s->dac_write_index = val;
310        s->dac_sub_index = 0;
311        s->dac_state = 0;
312        break;
313    case 0x3c9:
314        s->dac_cache[s->dac_sub_index] = val;
315        if (++s->dac_sub_index == 3) {
316            memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
317            s->dac_sub_index = 0;
318            s->dac_write_index++;
319        }
320        break;
321    case 0x3ce:
322        s->gr_index = val & 0x0f;
323        break;
324    case 0x3cf:
325#ifdef DEBUG_VGA_REG
326        printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
327#endif
328        s->gr[s->gr_index] = val & gr_mask[s->gr_index];
329        break;
330    case 0x3b4:
331    case 0x3d4:
332        s->cr_index = val;
333        break;
334    case 0x3b5:
335    case 0x3d5:
336#ifdef DEBUG_VGA_REG
337        printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
338#endif
339        /* handle CR0-7 protection */
340        if ((s->cr[0x11] & 0x80) && s->cr_index <= 7) {
341            /* can always write bit 4 of CR7 */
342            if (s->cr_index == 7)
343                s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
344            return;
345        }
346        switch(s->cr_index) {
347        case 0x01: /* horizontal display end */
348        case 0x07:
349        case 0x09:
350        case 0x0c:
351        case 0x0d:
352        case 0x12: /* veritcal display end */
353            s->cr[s->cr_index] = val;
354            break;
355        default:
356            s->cr[s->cr_index] = val;
357            break;
358        }
359        break;
360    case 0x3ba:
361    case 0x3da:
362        s->fcr = val & 0x10;
363        break;
364    }
365}
366
367#ifdef CONFIG_BOCHS_VBE
368static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
369{
370    VGAState *s = opaque;
371    uint32_t val;
372    val = s->vbe_index;
373    return val;
374}
375
376static uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr)
377{
378    VGAState *s = opaque;
379    uint32_t val;
380
381    if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
382        if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_GETCAPS) {
383            switch(s->vbe_index) {
384                /* XXX: do not hardcode ? */
385            case VBE_DISPI_INDEX_XRES:
386                val = VBE_DISPI_MAX_XRES;
387                break;
388            case VBE_DISPI_INDEX_YRES:
389                val = VBE_DISPI_MAX_YRES;
390                break;
391            case VBE_DISPI_INDEX_BPP:
392                val = VBE_DISPI_MAX_BPP;
393                break;
394            default:
395                val = s->vbe_regs[s->vbe_index]; 
396                break;
397            }
398        } else {
399            val = s->vbe_regs[s->vbe_index]; 
400        }
401    } else {
402        val = 0;
403    }
404#ifdef DEBUG_BOCHS_VBE
405    printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val);
406#endif
407    return val;
408}
409
410static void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val)
411{
412    VGAState *s = opaque;
413    s->vbe_index = val;
414}
415
416static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
417{
418    VGAState *s = opaque;
419
420    if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
421#ifdef DEBUG_BOCHS_VBE
422        printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val);
423#endif
424        switch(s->vbe_index) {
425        case VBE_DISPI_INDEX_ID:
426            if (val == VBE_DISPI_ID0 ||
427                val == VBE_DISPI_ID1 ||
428                val == VBE_DISPI_ID2) {
429                s->vbe_regs[s->vbe_index] = val;
430            }
431            break;
432        case VBE_DISPI_INDEX_XRES:
433            if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) {
434                s->vbe_regs[s->vbe_index] = val;
435            }
436            break;
437        case VBE_DISPI_INDEX_YRES:
438            if (val <= VBE_DISPI_MAX_YRES) {
439                s->vbe_regs[s->vbe_index] = val;
440            }
441            break;
442        case VBE_DISPI_INDEX_BPP:
443            if (val == 0)
444                val = 8;
445            if (val == 4 || val == 8 || val == 15 || 
446                val == 16 || val == 24 || val == 32) {
447                s->vbe_regs[s->vbe_index] = val;
448            }
449            break;
450        case VBE_DISPI_INDEX_BANK:
451            val &= s->vbe_bank_mask;
452            s->vbe_regs[s->vbe_index] = val;
453            s->bank_offset = (val << 16);
454            break;
455        case VBE_DISPI_INDEX_ENABLE:
456            if ((val & VBE_DISPI_ENABLED) &&
457                !(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
458                int h, shift_control;
459
460                s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = 
461                    s->vbe_regs[VBE_DISPI_INDEX_XRES];
462                s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = 
463                    s->vbe_regs[VBE_DISPI_INDEX_YRES];
464                s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
465                s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
466               
467                if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
468                    s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1;
469                else
470                    s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] * 
471                        ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
472                s->vbe_start_addr = 0;
473
474                /* clear the screen (should be done in BIOS) */
475                if (!(val & VBE_DISPI_NOCLEARMEM)) {
476                    memset(s->vram_ptr, 0, 
477                           s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
478                }
479               
480                /* we initialize the VGA graphic mode (should be done
481                   in BIOS) */
482                s->gr[0x06] = (s->gr[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
483                s->cr[0x17] |= 3; /* no CGA modes */
484                s->cr[0x13] = s->vbe_line_offset >> 3;
485                /* width */
486                s->cr[0x01] = (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
487                /* height (only meaningful if < 1024) */
488                h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
489                s->cr[0x12] = h;
490                s->cr[0x07] = (s->cr[0x07] & ~0x42) | 
491                    ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
492                /* line compare to 1023 */
493                s->cr[0x18] = 0xff;
494                s->cr[0x07] |= 0x10;
495                s->cr[0x09] |= 0x40;
496               
497                if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
498                    shift_control = 0;
499                    s->sr[0x01] &= ~8; /* no double line */
500                } else {
501                    shift_control = 2;
502                    s->sr[4] |= 0x08; /* set chain 4 mode */
503                    s->sr[2] |= 0x0f; /* activate all planes */
504                }
505                s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5);
506                s->cr[0x09] &= ~0x9f; /* no double scan */
507            } else {
508                /* XXX: the bios should do that */
509                s->bank_offset = 0;
510            }
511            s->vbe_regs[s->vbe_index] = val;
512            break;
513        case VBE_DISPI_INDEX_VIRT_WIDTH:
514            {
515                int w, h, line_offset;
516
517                if (val < s->vbe_regs[VBE_DISPI_INDEX_XRES])
518                    return;
519                w = val;
520                if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
521                    line_offset = w >> 1;
522                else
523                    line_offset = w * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
524                h = s->vram_size / line_offset;
525                /* XXX: support weird bochs semantics ? */
526                if (h < s->vbe_regs[VBE_DISPI_INDEX_YRES])
527                    return;
528                s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = w;
529                s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h;
530                s->vbe_line_offset = line_offset;
531            }
532            break;
533        case VBE_DISPI_INDEX_X_OFFSET:
534        case VBE_DISPI_INDEX_Y_OFFSET:
535            {
536                int x;
537                s->vbe_regs[s->vbe_index] = val;
538                s->vbe_start_addr = s->vbe_line_offset * s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET];
539                x = s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET];
540                if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
541                    s->vbe_start_addr += x >> 1;
542                else
543                    s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
544                s->vbe_start_addr >>= 2;
545            }
546            break;
547        default:
548            break;
549        }
550    }
551}
552#endif
553
554/* called for accesses between 0xa0000 and 0xc0000 */
555uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr)
556{
557    VGAState *s = opaque;
558    int memory_map_mode, plane;
559    uint32_t ret;
560   
561    /* convert to VGA memory offset */
562    memory_map_mode = (s->gr[6] >> 2) & 3;
563    addr &= 0x1ffff;
564    switch(memory_map_mode) {
565    case 0:
566        break;
567    case 1:
568        if (addr >= 0x10000)
569            return 0xff;
570        addr += s->bank_offset;
571        break;
572    case 2:
573        addr -= 0x10000;
574        if (addr >= 0x8000)
575            return 0xff;
576        break;
577    default:
578    case 3:
579        addr -= 0x18000;
580        if (addr >= 0x8000)
581            return 0xff;
582        break;
583    }
584   
585    if (s->sr[4] & 0x08) {
586        /* chain 4 mode : simplest access */
587        ret = s->vram_ptr[addr];
588    } else if (s->gr[5] & 0x10) {
589        /* odd/even mode (aka text mode mapping) */
590        plane = (s->gr[4] & 2) | (addr & 1);
591        ret = s->vram_ptr[((addr & ~1) << 1) | plane];
592    } else {
593        /* standard VGA latched access */
594        s->latch = ((uint32_t *)s->vram_ptr)[addr];
595
596        if (!(s->gr[5] & 0x08)) {
597            /* read mode 0 */
598            plane = s->gr[4];
599            ret = GET_PLANE(s->latch, plane);
600        } else {
601            /* read mode 1 */
602            ret = (s->latch ^ mask16[s->gr[2]]) & mask16[s->gr[7]];
603            ret |= ret >> 16;
604            ret |= ret >> 8;
605            ret = (~ret) & 0xff;
606        }
607    }
608    return ret;
609}
610
611static uint32_t vga_mem_readw(void *opaque, target_phys_addr_t addr)
612{
613    uint32_t v;
614#ifdef TARGET_WORDS_BIGENDIAN
615    v = vga_mem_readb(opaque, addr) << 8;
616    v |= vga_mem_readb(opaque, addr + 1);
617#else
618    v = vga_mem_readb(opaque, addr);
619    v |= vga_mem_readb(opaque, addr + 1) << 8;
620#endif
621    return v;
622}
623
624static uint32_t vga_mem_readl(void *opaque, target_phys_addr_t addr)
625{
626    uint32_t v;
627#ifdef TARGET_WORDS_BIGENDIAN
628    v = vga_mem_readb(opaque, addr) << 24;
629    v |= vga_mem_readb(opaque, addr + 1) << 16;
630    v |= vga_mem_readb(opaque, addr + 2) << 8;
631    v |= vga_mem_readb(opaque, addr + 3);
632#else
633    v = vga_mem_readb(opaque, addr);
634    v |= vga_mem_readb(opaque, addr + 1) << 8;
635    v |= vga_mem_readb(opaque, addr + 2) << 16;
636    v |= vga_mem_readb(opaque, addr + 3) << 24;
637#endif
638    return v;
639}
640
641/* called for accesses between 0xa0000 and 0xc0000 */
642void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
643{
644    VGAState *s = opaque;
645    int memory_map_mode, plane, write_mode, b, func_select, mask;
646    uint32_t write_mask, bit_mask, set_mask;
647
648#ifdef DEBUG_VGA_MEM
649    printf("vga: [0x%x] = 0x%02x\n", addr, val);
650#endif
651    /* convert to VGA memory offset */
652    memory_map_mode = (s->gr[6] >> 2) & 3;
653    addr &= 0x1ffff;
654    switch(memory_map_mode) {
655    case 0:
656        break;
657    case 1:
658        if (addr >= 0x10000)
659            return;
660        addr += s->bank_offset;
661        break;
662    case 2:
663        addr -= 0x10000;
664        if (addr >= 0x8000)
665            return;
666        break;
667    default:
668    case 3:
669        addr -= 0x18000;
670        if (addr >= 0x8000)
671            return;
672        break;
673    }
674   
675    if (s->sr[4] & 0x08) {
676        /* chain 4 mode : simplest access */
677        plane = addr & 3;
678        mask = (1 << plane);
679        if (s->sr[2] & mask) {
680            s->vram_ptr[addr] = val;
681#ifdef DEBUG_VGA_MEM
682            printf("vga: chain4: [0x%x]\n", addr);
683#endif
684            s->plane_updated |= mask; /* only used to detect font change */
685            cpu_physical_memory_set_dirty(s->vram_offset + addr);
686        }
687    } else if (s->gr[5] & 0x10) {
688        /* odd/even mode (aka text mode mapping) */
689        plane = (s->gr[4] & 2) | (addr & 1);
690        mask = (1 << plane);
691        if (s->sr[2] & mask) {
692            addr = ((addr & ~1) << 1) | plane;
693            s->vram_ptr[addr] = val;
694#ifdef DEBUG_VGA_MEM
695            printf("vga: odd/even: [0x%x]\n", addr);
696#endif
697            s->plane_updated |= mask; /* only used to detect font change */
698            cpu_physical_memory_set_dirty(s->vram_offset + addr);
699        }
700    } else {
701        /* standard VGA latched access */
702        write_mode = s->gr[5] & 3;
703        switch(write_mode) {
704        default:
705        case 0:
706            /* rotate */
707            b = s->gr[3] & 7;
708            val = ((val >> b) | (val << (8 - b))) & 0xff;
709            val |= val << 8;
710            val |= val << 16;
711
712            /* apply set/reset mask */
713            set_mask = mask16[s->gr[1]];
714            val = (val & ~set_mask) | (mask16[s->gr[0]] & set_mask);
715            bit_mask = s->gr[8];
716            break;
717        case 1:
718            val = s->latch;
719            goto do_write;
720        case 2:
721            val = mask16[val & 0x0f];
722            bit_mask = s->gr[8];
723            break;
724        case 3:
725            /* rotate */
726            b = s->gr[3] & 7;
727            val = (val >> b) | (val << (8 - b));
728
729            bit_mask = s->gr[8] & val;
730            val = mask16[s->gr[0]];
731            break;
732        }
733
734        /* apply logical operation */
735        func_select = s->gr[3] >> 3;
736        switch(func_select) {
737        case 0:
738        default:
739            /* nothing to do */
740            break;
741        case 1:
742            /* and */
743            val &= s->latch;
744            break;
745        case 2:
746            /* or */
747            val |= s->latch;
748            break;
749        case 3:
750            /* xor */
751            val ^= s->latch;
752            break;
753        }
754
755        /* apply bit mask */
756        bit_mask |= bit_mask << 8;
757        bit_mask |= bit_mask << 16;
758        val = (val & bit_mask) | (s->latch & ~bit_mask);
759
760    do_write:
761        /* mask data according to sr[2] */
762        mask = s->sr[2];
763        s->plane_updated |= mask; /* only used to detect font change */
764        write_mask = mask16[mask];
765        ((uint32_t *)s->vram_ptr)[addr] = 
766            (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) | 
767            (val & write_mask);
768#ifdef DEBUG_VGA_MEM
769            printf("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n", 
770                   addr * 4, write_mask, val);
771#endif
772            cpu_physical_memory_set_dirty(s->vram_offset + (addr << 2));
773    }
774}
775
776static void vga_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
777{
778#ifdef TARGET_WORDS_BIGENDIAN
779    vga_mem_writeb(opaque, addr, (val >> 8) & 0xff);
780    vga_mem_writeb(opaque, addr + 1, val & 0xff);
781#else
782    vga_mem_writeb(opaque, addr, val & 0xff);
783    vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
784#endif
785}
786
787static void vga_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
788{
789#ifdef TARGET_WORDS_BIGENDIAN
790    vga_mem_writeb(opaque, addr, (val >> 24) & 0xff);
791    vga_mem_writeb(opaque, addr + 1, (val >> 16) & 0xff);
792    vga_mem_writeb(opaque, addr + 2, (val >> 8) & 0xff);
793    vga_mem_writeb(opaque, addr + 3, val & 0xff);
794#else
795    vga_mem_writeb(opaque, addr, val & 0xff);
796    vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
797    vga_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff);
798    vga_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff);
799#endif
800}
801
802typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
803                             const uint8_t *font_ptr, int h,
804                             uint32_t fgcol, uint32_t bgcol);
805typedef void vga_draw_glyph9_func(uint8_t *d, int linesize,
806                                  const uint8_t *font_ptr, int h, 
807                                  uint32_t fgcol, uint32_t bgcol, int dup9);
808typedef void vga_draw_line_func(VGAState *s1, uint8_t *d, 
809                                const uint8_t *s, int width);
810
811static inline unsigned int rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b)
812{
813    return ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6);
814}
815
816static inline unsigned int rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b)
817{
818    return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
819}
820
821static inline unsigned int rgb_to_pixel16(unsigned int r, unsigned int g, unsigned b)
822{
823    return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
824}
825
826static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b)
827{
828    return (r << 16) | (g << 8) | b;
829}
830
831static inline unsigned int rgb_to_pixel32bgr(unsigned int r, unsigned int g, unsigned b)
832{
833    return (b << 16) | (g << 8) | r;
834}
835
836#define DEPTH 8
837#include "vga_template.h"
838
839#define DEPTH 15
840#include "vga_template.h"
841
842#define DEPTH 16
843#include "vga_template.h"
844
845#define DEPTH 32
846#include "vga_template.h"
847
848#define BGR_FORMAT
849#define DEPTH 32
850#include "vga_template.h"
851
852static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
853{
854    unsigned int col;
855    col = rgb_to_pixel8(r, g, b);
856    col |= col << 8;
857    col |= col << 16;
858    return col;
859}
860
861static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b)
862{
863    unsigned int col;
864    col = rgb_to_pixel15(r, g, b);
865    col |= col << 16;
866    return col;
867}
868
869static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
870{
871    unsigned int col;
872    col = rgb_to_pixel16(r, g, b);
873    col |= col << 16;
874    return col;
875}
876
877static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
878{
879    unsigned int col;
880    col = rgb_to_pixel32(r, g, b);
881    return col;
882}
883
884static unsigned int rgb_to_pixel32bgr_dup(unsigned int r, unsigned int g, unsigned b)
885{
886    unsigned int col;
887    col = rgb_to_pixel32bgr(r, g, b);
888    return col;
889}
890
891/* return true if the palette was modified */
892static int update_palette16(VGAState *s)
893{
894    int full_update, i;
895    uint32_t v, col, *palette;
896
897    full_update = 0;
898    palette = s->last_palette;
899    for(i = 0; i < 16; i++) {
900        v = s->ar[i];
901        if (s->ar[0x10] & 0x80)
902            v = ((s->ar[0x14] & 0xf) << 4) | (v & 0xf);
903        else
904            v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f);
905        v = v * 3;
906        col = s->rgb_to_pixel(c6_to_8(s->palette[v]), 
907                              c6_to_8(s->palette[v + 1]), 
908                              c6_to_8(s->palette[v + 2]));
909        if (col != palette[i]) {
910            full_update = 1;
911            palette[i] = col;
912        }
913    }
914    return full_update;
915}
916
917/* return true if the palette was modified */
918static int update_palette256(VGAState *s)
919{
920    int full_update, i;
921    uint32_t v, col, *palette;
922
923    full_update = 0;
924    palette = s->last_palette;
925    v = 0;
926    for(i = 0; i < 256; i++) {
927        col = s->rgb_to_pixel(c6_to_8(s->palette[v]), 
928                              c6_to_8(s->palette[v + 1]), 
929                              c6_to_8(s->palette[v + 2]));
930        if (col != palette[i]) {
931            full_update = 1;
932            palette[i] = col;
933        }
934        v += 3;
935    }
936    return full_update;
937}
938
939static void vga_get_offsets(VGAState *s, 
940                            uint32_t *pline_offset, 
941                            uint32_t *pstart_addr)
942{
943    uint32_t start_addr, line_offset;
944#ifdef CONFIG_BOCHS_VBE
945    if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
946        line_offset = s->vbe_line_offset;
947        start_addr = s->vbe_start_addr;
948    } else
949#endif
950    { 
951        /* compute line_offset in bytes */
952        line_offset = s->cr[0x13];
953        line_offset <<= 3;
954
955        /* starting address */
956        start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8);
957    }
958    *pline_offset = line_offset;
959    *pstart_addr = start_addr;
960}
961
962/* update start_addr and line_offset. Return TRUE if modified */
963static int update_basic_params(VGAState *s)
964{
965    int full_update;
966    uint32_t start_addr, line_offset, line_compare;
967   
968    full_update = 0;
969
970    s->get_offsets(s, &line_offset, &start_addr);
971    /* line compare */
972    line_compare = s->cr[0x18] | 
973        ((s->cr[0x07] & 0x10) << 4) |
974        ((s->cr[0x09] & 0x40) << 3);
975
976    if (line_offset != s->line_offset ||
977        start_addr != s->start_addr ||
978        line_compare != s->line_compare) {
979        s->line_offset = line_offset;
980        s->start_addr = start_addr;
981        s->line_compare = line_compare;
982        full_update = 1;
983    }
984    return full_update;
985}
986
987#define NB_DEPTHS 5
988
989static inline int get_depth_index(DisplayState *s)
990{
991    switch(s->depth) {
992    default:
993    case 8:
994        return 0;
995    case 15:
996        return 1;
997    case 16:
998        return 2;
999    case 32:
1000        if (s->bgr)
1001            return 4;
1002        else
1003            return 3;
1004    }
1005}
1006
1007static vga_draw_glyph8_func *vga_draw_glyph8_table[NB_DEPTHS] = {
1008    vga_draw_glyph8_8,
1009    vga_draw_glyph8_16,
1010    vga_draw_glyph8_16,
1011    vga_draw_glyph8_32,
1012    vga_draw_glyph8_32,
1013};
1014
1015static vga_draw_glyph8_func *vga_draw_glyph16_table[NB_DEPTHS] = {
1016    vga_draw_glyph16_8,
1017    vga_draw_glyph16_16,
1018    vga_draw_glyph16_16,
1019    vga_draw_glyph16_32,
1020    vga_draw_glyph16_32,
1021};
1022
1023static vga_draw_glyph9_func *vga_draw_glyph9_table[NB_DEPTHS] = {
1024    vga_draw_glyph9_8,
1025    vga_draw_glyph9_16,
1026    vga_draw_glyph9_16,
1027    vga_draw_glyph9_32,
1028    vga_draw_glyph9_32,
1029};
1030   
1031static const uint8_t cursor_glyph[32 * 4] = {
1032    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1033    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1034    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1035    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1036    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1037    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1038    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1039    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1040    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1041    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1042    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1043    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1044    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1045    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1046    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1047    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1048};   
1049
1050/*
1051 * Text mode update
1052 * Missing:
1053 * - double scan
1054 * - double width
1055 * - underline
1056 * - flashing
1057 */
1058static void vga_draw_text(VGAState *s, int full_update)
1059{
1060    int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
1061    int cx_min, cx_max, linesize, x_incr;
1062    uint32_t offset, fgcol, bgcol, v, cursor_offset;
1063    uint8_t *d1, *d, *src, *s1, *dest, *cursor_ptr;
1064    const uint8_t *font_ptr, *font_base[2];
1065    int dup9, line_offset, depth_index;
1066    uint32_t *palette;
1067    uint32_t *ch_attr_ptr;
1068    vga_draw_glyph8_func *vga_draw_glyph8;
1069    vga_draw_glyph9_func *vga_draw_glyph9;
1070
1071    full_update |= update_palette16(s);
1072    palette = s->last_palette;
1073   
1074    /* compute font data address (in plane 2) */
1075    v = s->sr[3];
1076    offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
1077    if (offset != s->font_offsets[0]) {
1078        s->font_offsets[0] = offset;
1079        full_update = 1;
1080    }
1081    font_base[0] = s->vram_ptr + offset;
1082
1083    offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
1084    font_base[1] = s->vram_ptr + offset;
1085    if (offset != s->font_offsets[1]) {
1086        s->font_offsets[1] = offset;
1087        full_update = 1;
1088    }
1089    if (s->plane_updated & (1 << 2)) {
1090        /* if the plane 2 was modified since the last display, it
1091           indicates the font may have been modified */
1092        s->plane_updated = 0;
1093        full_update = 1;
1094    }
1095    full_update |= update_basic_params(s);
1096
1097    line_offset = s->line_offset;
1098    s1 = s->vram_ptr + (s->start_addr * 4);
1099
1100    /* total width & height */
1101    cheight = (s->cr[9] & 0x1f) + 1;
1102    cw = 8;
1103    if (!(s->sr[1] & 0x01))
1104        cw = 9;
1105    if (s->sr[1] & 0x08)
1106        cw = 16; /* NOTE: no 18 pixel wide */
1107    x_incr = cw * ((s->ds->depth + 7) >> 3);
1108    width = (s->cr[0x01] + 1);
1109    if (s->cr[0x06] == 100) {
1110        /* ugly hack for CGA 160x100x16 - explain me the logic */
1111        height = 100;
1112    } else {
1113        height = s->cr[0x12] | 
1114            ((s->cr[0x07] & 0x02) << 7) | 
1115            ((s->cr[0x07] & 0x40) << 3);
1116        height = (height + 1) / cheight;
1117    }
1118    if ((height * width) > CH_ATTR_SIZE) {
1119        /* better than nothing: exit if transient size is too big */
1120        return;
1121    }
1122
1123    if (width != s->last_width || height != s->last_height ||
1124        cw != s->last_cw || cheight != s->last_ch) {
1125        s->last_scr_width = width * cw;
1126        s->last_scr_height = height * cheight;
1127        dpy_resize(s->ds, s->last_scr_width, s->last_scr_height);
1128        s->last_width = width;
1129        s->last_height = height;
1130        s->last_ch = cheight;
1131        s->last_cw = cw;
1132        full_update = 1;
1133    }
1134    cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
1135    if (cursor_offset != s->cursor_offset ||
1136        s->cr[0xa] != s->cursor_start ||
1137        s->cr[0xb] != s->cursor_end) {
1138      /* if the cursor position changed, we update the old and new
1139         chars */
1140        if (s->cursor_offset < CH_ATTR_SIZE)
1141            s->last_ch_attr[s->cursor_offset] = -1;
1142        if (cursor_offset < CH_ATTR_SIZE)
1143            s->last_ch_attr[cursor_offset] = -1;
1144        s->cursor_offset = cursor_offset;
1145        s->cursor_start = s->cr[0xa];
1146        s->cursor_end = s->cr[0xb];
1147    }
1148    cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
1149   
1150    depth_index = get_depth_index(s->ds);
1151    if (cw == 16)
1152        vga_draw_glyph8 = vga_draw_glyph16_table[depth_index];
1153    else
1154        vga_draw_glyph8 = vga_draw_glyph8_table[depth_index];
1155    vga_draw_glyph9 = vga_draw_glyph9_table[depth_index];
1156   
1157    dest = s->ds->data;
1158    linesize = s->ds->linesize;
1159    ch_attr_ptr = s->last_ch_attr;
1160    for(cy = 0; cy < height; cy++) {
1161        d1 = dest;
1162        src = s1;
1163        cx_min = width;
1164        cx_max = -1;
1165        for(cx = 0; cx < width; cx++) {
1166            ch_attr = *(uint16_t *)src;
1167            if (full_update || ch_attr != *ch_attr_ptr) {
1168                if (cx < cx_min)
1169                    cx_min = cx;
1170                if (cx > cx_max)
1171                    cx_max = cx;
1172                *ch_attr_ptr = ch_attr;
1173#ifdef WORDS_BIGENDIAN
1174                ch = ch_attr >> 8;
1175                cattr = ch_attr & 0xff;
1176#else
1177                ch = ch_attr & 0xff;
1178                cattr = ch_attr >> 8;
1179#endif
1180                font_ptr = font_base[(cattr >> 3) & 1];
1181                font_ptr += 32 * 4 * ch;
1182                bgcol = palette[cattr >> 4];
1183                fgcol = palette[cattr & 0x0f];
1184                if (cw != 9) {
1185                    vga_draw_glyph8(d1, linesize, 
1186                                    font_ptr, cheight, fgcol, bgcol);
1187                } else {
1188                    dup9 = 0;
1189                    if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))
1190                        dup9 = 1;
1191                    vga_draw_glyph9(d1, linesize, 
1192                                    font_ptr, cheight, fgcol, bgcol, dup9);
1193                }
1194                if (src == cursor_ptr &&
1195                    !(s->cr[0x0a] & 0x20)) {
1196                    int line_start, line_last, h;
1197                    /* draw the cursor */
1198                    line_start = s->cr[0x0a] & 0x1f;
1199                    line_last = s->cr[0x0b] & 0x1f;
1200                    /* XXX: check that */
1201                    if (line_last > cheight - 1)
1202                        line_last = cheight - 1;
1203                    if (line_last >= line_start && line_start < cheight) {
1204                        h = line_last - line_start + 1;
1205                        d = d1 + linesize * line_start;
1206                        if (cw != 9) {
1207                            vga_draw_glyph8(d, linesize, 
1208                                            cursor_glyph, h, fgcol, bgcol);
1209                        } else {
1210                            vga_draw_glyph9(d, linesize, 
1211                                            cursor_glyph, h, fgcol, bgcol, 1);
1212                        }
1213                    }
1214                }
1215            }
1216            d1 += x_incr;
1217            src += 4;
1218            ch_attr_ptr++;
1219        }
1220        if (cx_max != -1) {
1221            dpy_update(s->ds, cx_min * cw, cy * cheight, 
1222                       (cx_max - cx_min + 1) * cw, cheight);
1223        }
1224        dest += linesize * cheight;
1225        s1 += line_offset;
1226    }
1227}
1228
1229enum {
1230    VGA_DRAW_LINE2,
1231    VGA_DRAW_LINE2D2,
1232    VGA_DRAW_LINE4,
1233    VGA_DRAW_LINE4D2,
1234    VGA_DRAW_LINE8D2,
1235    VGA_DRAW_LINE8,
1236    VGA_DRAW_LINE15,
1237    VGA_DRAW_LINE16,
1238    VGA_DRAW_LINE24,
1239    VGA_DRAW_LINE32,
1240    VGA_DRAW_LINE_NB,
1241};
1242
1243static vga_draw_line_func *vga_draw_line_table[NB_DEPTHS * VGA_DRAW_LINE_NB] = {
1244    vga_draw_line2_8,
1245    vga_draw_line2_16,
1246    vga_draw_line2_16,
1247    vga_draw_line2_32,
1248    vga_draw_line2_32,
1249
1250    vga_draw_line2d2_8,
1251    vga_draw_line2d2_16,
1252    vga_draw_line2d2_16,
1253    vga_draw_line2d2_32,
1254    vga_draw_line2d2_32,
1255
1256    vga_draw_line4_8,
1257    vga_draw_line4_16,
1258    vga_draw_line4_16,
1259    vga_draw_line4_32,
1260    vga_draw_line4_32,
1261
1262    vga_draw_line4d2_8,
1263    vga_draw_line4d2_16,
1264    vga_draw_line4d2_16,
1265    vga_draw_line4d2_32,
1266    vga_draw_line4d2_32,
1267
1268    vga_draw_line8d2_8,
1269    vga_draw_line8d2_16,
1270    vga_draw_line8d2_16,
1271    vga_draw_line8d2_32,
1272    vga_draw_line8d2_32,
1273
1274    vga_draw_line8_8,
1275    vga_draw_line8_16,
1276    vga_draw_line8_16,
1277    vga_draw_line8_32,
1278    vga_draw_line8_32,
1279
1280    vga_draw_line15_8,
1281    vga_draw_line15_15,
1282    vga_draw_line15_16,
1283    vga_draw_line15_32,
1284    vga_draw_line15_32bgr,
1285
1286    vga_draw_line16_8,
1287    vga_draw_line16_15,
1288    vga_draw_line16_16,
1289    vga_draw_line16_32,
1290    vga_draw_line16_32bgr,
1291
1292    vga_draw_line24_8,
1293    vga_draw_line24_15,
1294    vga_draw_line24_16,
1295    vga_draw_line24_32,
1296    vga_draw_line24_32bgr,
1297
1298    vga_draw_line32_8,
1299    vga_draw_line32_15,
1300    vga_draw_line32_16,
1301    vga_draw_line32_32,
1302    vga_draw_line32_32bgr,
1303};
1304
1305typedef unsigned int rgb_to_pixel_dup_func(unsigned int r, unsigned int g, unsigned b);
1306
1307static rgb_to_pixel_dup_func *rgb_to_pixel_dup_table[NB_DEPTHS] = {
1308    rgb_to_pixel8_dup,
1309    rgb_to_pixel15_dup,
1310    rgb_to_pixel16_dup,
1311    rgb_to_pixel32_dup,
1312    rgb_to_pixel32bgr_dup,
1313};
1314
1315static int vga_get_bpp(VGAState *s)
1316{
1317    int ret;
1318#ifdef CONFIG_BOCHS_VBE
1319    if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1320        ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
1321    } else 
1322#endif
1323    {
1324        ret = 0;
1325    }
1326    return ret;
1327}
1328
1329static void vga_get_resolution(VGAState *s, int *pwidth, int *pheight)
1330{
1331    int width, height;
1332   
1333#ifdef CONFIG_BOCHS_VBE
1334    if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1335        width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
1336        height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
1337    } else 
1338#endif
1339    {
1340        width = (s->cr[0x01] + 1) * 8;
1341        height = s->cr[0x12] | 
1342            ((s->cr[0x07] & 0x02) << 7) | 
1343            ((s->cr[0x07] & 0x40) << 3);
1344        height = (height + 1);
1345    }
1346    *pwidth = width;
1347    *pheight = height;
1348}
1349
1350void vga_invalidate_scanlines(VGAState *s, int y1, int y2)
1351{
1352    int y;
1353    if (y1 >= VGA_MAX_HEIGHT)
1354        return;
1355    if (y2 >= VGA_MAX_HEIGHT)
1356        y2 = VGA_MAX_HEIGHT;
1357    for(y = y1; y < y2; y++) {
1358        s->invalidated_y_table[y >> 5] |= 1 << (y & 0x1f);
1359    }
1360}
1361
1362static inline int cmp_vram(VGAState *s, int offset, int n)
1363{
1364    long *vp, *sp;
1365
1366    if (s->vram_shadow == NULL)
1367        return 1;
1368    vp = (long *)(s->vram_ptr + offset);
1369    sp = (long *)(s->vram_shadow + offset);
1370    while ((n -= sizeof(*vp)) >= 0) {
1371        if (*vp++ != *sp++) {
1372            memcpy(sp - 1, vp - 1, n + sizeof(*vp));
1373            return 1;
1374        }
1375    }
1376    return 0;
1377}
1378
1379#ifdef USE_SSE2
1380
1381#include <signal.h>
1382#include <setjmp.h>
1383#include <emmintrin.h>
1384
1385int sse2_ok = 1;
1386
1387static inline unsigned int cpuid_edx(unsigned int op)
1388{
1389    unsigned int eax, edx;
1390
1391#ifdef __x86_64__
1392#define __bx "rbx"
1393#else
1394#define __bx "ebx"
1395#endif
1396    __asm__("push %%"__bx"; cpuid; pop %%"__bx
1397            : "=a" (eax), "=d" (edx)
1398            : "0" (op)
1399            : "cx");
1400#undef __bx
1401
1402    return edx;
1403}
1404
1405jmp_buf sse_jbuf;
1406
1407void intr(int sig)
1408{
1409    sse2_ok = 0;
1410    longjmp(sse_jbuf, 1);
1411}
1412
1413void check_sse2(void)
1414{
1415    /* Check 1: What does CPUID say? */
1416    if ((cpuid_edx(1) & 0x4000000) == 0) {
1417        sse2_ok = 0;
1418        return;
1419    }
1420
1421    /* Check 2: Can we use SSE2 in anger? */
1422    signal(SIGILL, intr);
1423    if (setjmp(sse_jbuf) == 0)
1424        __asm__("xorps %xmm0,%xmm0\n");
1425}
1426
1427int vram_dirty(VGAState *s, int offset, int n)
1428{
1429    __m128i *sp, *vp;
1430
1431    if (s->vram_shadow == NULL)
1432        return 1;
1433    if (sse2_ok == 0)
1434        return cmp_vram(s, offset, n);
1435    vp = (__m128i *)(s->vram_ptr + offset);
1436    sp = (__m128i *)(s->vram_shadow + offset);
1437    while ((n -= sizeof(*vp)) >= 0) {
1438        if (_mm_movemask_epi8(_mm_cmpeq_epi8(*sp, *vp)) != 0xffff) {
1439            while (n >= 0) {
1440                _mm_store_si128(sp++, _mm_load_si128(vp++));
1441                n -= sizeof(*vp);
1442            }
1443            return 1;
1444        }
1445        sp++;
1446        vp++;
1447    }
1448    return 0;
1449}
1450#else /* !USE_SSE2 */
1451int vram_dirty(VGAState *s, int offset, int n)
1452{
1453    return cmp_vram(s, offset, n);
1454}
1455
1456void check_sse2(void)
1457{
1458}
1459#endif /* !USE_SSE2 */
1460
1461/*
1462 * graphic modes
1463 */
1464static void vga_draw_graphic(VGAState *s, int full_update)
1465{
1466    int y1, y, update, linesize, y_start, double_scan, mask;
1467    int width, height, shift_control, line_offset, bwidth;
1468    ram_addr_t page0, page1;
1469    int disp_width, multi_scan, multi_run;
1470    uint8_t *d;
1471    uint32_t v, addr1, addr;
1472    vga_draw_line_func *vga_draw_line;
1473    ram_addr_t page_min, page_max;
1474
1475    full_update |= update_basic_params(s);
1476
1477    s->get_resolution(s, &width, &height);
1478    disp_width = width;
1479
1480    shift_control = (s->gr[0x05] >> 5) & 3;
1481    double_scan = (s->cr[0x09] >> 7);
1482    if (shift_control != 1) {
1483        multi_scan = (((s->cr[0x09] & 0x1f) + 1) << double_scan) - 1;
1484    } else {
1485        /* in CGA modes, multi_scan is ignored */
1486        /* XXX: is it correct ? */
1487        multi_scan = double_scan;
1488    }
1489    multi_run = multi_scan;
1490    if (shift_control != s->shift_control ||
1491        double_scan != s->double_scan) {
1492        full_update = 1;
1493        s->shift_control = shift_control;
1494        s->double_scan = double_scan;
1495    }
1496   
1497    if (shift_control == 0) {
1498        full_update |= update_palette16(s);
1499        if (s->sr[0x01] & 8) {
1500            v = VGA_DRAW_LINE4D2;
1501            disp_width <<= 1;
1502        } else {
1503            v = VGA_DRAW_LINE4;
1504        }
1505    } else if (shift_control == 1) {
1506        full_update |= update_palette16(s);
1507        if (s->sr[0x01] & 8) {
1508            v = VGA_DRAW_LINE2D2;
1509            disp_width <<= 1;
1510        } else {
1511            v = VGA_DRAW_LINE2;
1512        }
1513    } else {
1514        switch(s->get_bpp(s)) {
1515        default:
1516        case 0:
1517            full_update |= update_palette256(s);
1518            v = VGA_DRAW_LINE8D2;
1519            break;
1520        case 8:
1521            full_update |= update_palette256(s);
1522            v = VGA_DRAW_LINE8;
1523            break;
1524        case 15:
1525            v = VGA_DRAW_LINE15;
1526            break;
1527        case 16:
1528            v = VGA_DRAW_LINE16;
1529            break;
1530        case 24:
1531            v = VGA_DRAW_LINE24;
1532            break;
1533        case 32:
1534            v = VGA_DRAW_LINE32;
1535            break;
1536        }
1537    }
1538    vga_draw_line = vga_draw_line_table[v * NB_DEPTHS + get_depth_index(s->ds)];
1539
1540    if (disp_width != s->last_width ||
1541        height != s->last_height) {
1542        dpy_resize(s->ds, disp_width, height);
1543        s->last_scr_width = disp_width;
1544        s->last_scr_height = height;
1545        s->last_width = disp_width;
1546        s->last_height = height;
1547        full_update = 1;
1548    }
1549    if (s->cursor_invalidate)
1550        s->cursor_invalidate(s);
1551   
1552    line_offset = s->line_offset;
1553#if 0
1554    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",
1555           width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]);
1556#endif
1557
1558    for (y = 0; y < s->vram_size; y += TARGET_PAGE_SIZE)
1559        if (vram_dirty(s, y, TARGET_PAGE_SIZE))
1560            cpu_physical_memory_set_dirty(s->vram_offset + y);
1561
1562    addr1 = (s->start_addr * 4);
1563    bwidth = width * 4;
1564    y_start = -1;
1565    page_min = 0;
1566    page_max = 0;
1567    d = s->ds->data;
1568    linesize = s->ds->linesize;
1569    y1 = 0;
1570    for(y = 0; y < height; y++) {
1571        addr = addr1;
1572        if (!(s->cr[0x17] & 1)) {
1573            int shift;
1574            /* CGA compatibility handling */
1575            shift = 14 + ((s->cr[0x17] >> 6) & 1);
1576            addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
1577        }
1578        if (!(s->cr[0x17] & 2)) {
1579            addr = (addr & ~0x8000) | ((y1 & 2) << 14);
1580        }
1581        page0 = s->vram_offset + (addr & TARGET_PAGE_MASK);
1582        page1 = s->vram_offset + ((addr + bwidth - 1) & TARGET_PAGE_MASK);
1583        update = full_update | 
1584            cpu_physical_memory_get_dirty(page0, VGA_DIRTY_FLAG) |
1585            cpu_physical_memory_get_dirty(page1, VGA_DIRTY_FLAG);
1586        if ((page1 - page0) > TARGET_PAGE_SIZE) {
1587            /* if wide line, can use another page */
1588            update |= cpu_physical_memory_get_dirty(page0 + TARGET_PAGE_SIZE, 
1589                                                    VGA_DIRTY_FLAG);
1590        }
1591        /* explicit invalidation for the hardware cursor */
1592        update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
1593        if (update) {
1594            if (y_start < 0)
1595                y_start = y;
1596            if (page_min == 0 || page0 < page_min)
1597                page_min = page0;
1598            if (page_max == 0 || page1 > page_max)
1599                page_max = page1;
1600            vga_draw_line(s, d, s->vram_ptr + addr, width);
1601            if (s->cursor_draw_line)
1602                s->cursor_draw_line(s, d, y);
1603        } else {
1604            if (y_start >= 0) {
1605                /* flush to display */
1606                dpy_update(s->ds, 0, y_start, 
1607                           disp_width, y - y_start);
1608                y_start = -1;
1609            }
1610        }
1611        if (!multi_run) {
1612            mask = (s->cr[0x17] & 3) ^ 3;
1613            if ((y1 & mask) == mask)
1614                addr1 += line_offset;
1615            y1++;
1616            multi_run = multi_scan;
1617        } else {
1618            multi_run--;
1619        }
1620        /* line compare acts on the displayed lines */
1621        if (y == s->line_compare)
1622            addr1 = 0;
1623        d += linesize;
1624    }
1625    if (y_start >= 0) {
1626        /* flush to display */
1627        dpy_update(s->ds, 0, y_start, 
1628                   disp_width, y - y_start);
1629    }
1630    /* reset modified pages */
1631    if (page_max != -1) {
1632        cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
1633                                        VGA_DIRTY_FLAG);
1634    }
1635    memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
1636}
1637
1638static void vga_draw_blank(VGAState *s, int full_update)
1639{
1640    int i, w, val;
1641    uint8_t *d;
1642
1643    if (!full_update)
1644        return;
1645    if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
1646        return;
1647    if (s->ds->depth == 8) 
1648        val = s->rgb_to_pixel(0, 0, 0);
1649    else
1650        val = 0;
1651    w = s->last_scr_width * ((s->ds->depth + 7) >> 3);
1652    d = s->ds->data;
1653    for(i = 0; i < s->last_scr_height; i++) {
1654        memset(d, val, w);
1655        d += s->ds->linesize;
1656    }
1657    dpy_update(s->ds, 0, 0, 
1658               s->last_scr_width, s->last_scr_height);
1659}
1660
1661#define GMODE_TEXT     0
1662#define GMODE_GRAPH    1
1663#define GMODE_BLANK 2
1664
1665static void vga_update_display(void *opaque)
1666{
1667    VGAState *s = (VGAState *)opaque;
1668    int full_update, graphic_mode;
1669
1670    if (s->ds->depth == 0) {
1671        /* nothing to do */
1672    } else {
1673        s->rgb_to_pixel = 
1674            rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1675       
1676        full_update = 0;
1677        if (!(s->ar_index & 0x20)) {
1678            graphic_mode = GMODE_BLANK;
1679        } else {
1680            graphic_mode = s->gr[6] & 1;
1681        }
1682        if (graphic_mode != s->graphic_mode) {
1683            s->graphic_mode = graphic_mode;
1684            full_update = 1;
1685        }
1686        switch(graphic_mode) {
1687        case GMODE_TEXT:
1688            vga_draw_text(s, full_update);
1689            break;
1690        case GMODE_GRAPH:
1691            vga_draw_graphic(s, full_update);
1692            break;
1693        case GMODE_BLANK:
1694        default:
1695            vga_draw_blank(s, full_update);
1696            break;
1697        }
1698    }
1699}
1700
1701/* force a full display refresh */
1702static void vga_invalidate_display(void *opaque)
1703{
1704    VGAState *s = (VGAState *)opaque;
1705   
1706    s->last_width = -1;
1707    s->last_height = -1;
1708}
1709
1710static void vga_reset(VGAState *s)
1711{
1712    memset(s, 0, sizeof(VGAState));
1713    s->graphic_mode = -1; /* force full update */
1714}
1715
1716static CPUReadMemoryFunc *vga_mem_read[3] = {
1717    vga_mem_readb,
1718    vga_mem_readw,
1719    vga_mem_readl,
1720};
1721
1722static CPUWriteMemoryFunc *vga_mem_write[3] = {
1723    vga_mem_writeb,
1724    vga_mem_writew,
1725    vga_mem_writel,
1726};
1727
1728static void vga_save(QEMUFile *f, void *opaque)
1729{
1730    VGAState *s = opaque;
1731#ifdef CONFIG_BOCHS_VBE
1732    int i;
1733#endif
1734
1735    qemu_put_be32s(f, &s->latch);
1736    qemu_put_8s(f, &s->sr_index);
1737    qemu_put_buffer(f, s->sr, 8);
1738    qemu_put_8s(f, &s->gr_index);
1739    qemu_put_buffer(f, s->gr, 16);
1740    qemu_put_8s(f, &s->ar_index);
1741    qemu_put_buffer(f, s->ar, 21);
1742    qemu_put_be32s(f, &s->ar_flip_flop);
1743    qemu_put_8s(f, &s->cr_index);
1744    qemu_put_buffer(f, s->cr, 256);
1745    qemu_put_8s(f, &s->msr);
1746    qemu_put_8s(f, &s->fcr);
1747    qemu_put_8s(f, &s->st00);
1748    qemu_put_8s(f, &s->st01);
1749
1750    qemu_put_8s(f, &s->dac_state);
1751    qemu_put_8s(f, &s->dac_sub_index);
1752    qemu_put_8s(f, &s->dac_read_index);
1753    qemu_put_8s(f, &s->dac_write_index);
1754    qemu_put_buffer(f, s->dac_cache, 3);
1755    qemu_put_buffer(f, s->palette, 768);
1756
1757    qemu_put_be32s(f, &s->bank_offset);
1758#ifdef CONFIG_BOCHS_VBE
1759    qemu_put_byte(f, 1);
1760    qemu_put_be16s(f, &s->vbe_index);
1761    for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
1762        qemu_put_be16s(f, &s->vbe_regs[i]);
1763    qemu_put_be32s(f, &s->vbe_start_addr);
1764    qemu_put_be32s(f, &s->vbe_line_offset);
1765    qemu_put_be32s(f, &s->vbe_bank_mask);
1766#else
1767    qemu_put_byte(f, 0);
1768#endif
1769}
1770
1771static int vga_load(QEMUFile *f, void *opaque, int version_id)
1772{
1773    VGAState *s = opaque;
1774    int is_vbe;
1775#ifdef CONFIG_BOCHS_VBE
1776    int i;
1777#endif
1778
1779    if (version_id != 1)
1780        return -EINVAL;
1781
1782    qemu_get_be32s(f, &s->latch);
1783    qemu_get_8s(f, &s->sr_index);
1784    qemu_get_buffer(f, s->sr, 8);
1785    qemu_get_8s(f, &s->gr_index);
1786    qemu_get_buffer(f, s->gr, 16);
1787    qemu_get_8s(f, &s->ar_index);
1788    qemu_get_buffer(f, s->ar, 21);
1789    qemu_get_be32s(f, &s->ar_flip_flop);
1790    qemu_get_8s(f, &s->cr_index);
1791    qemu_get_buffer(f, s->cr, 256);
1792    qemu_get_8s(f, &s->msr);
1793    qemu_get_8s(f, &s->fcr);
1794    qemu_get_8s(f, &s->st00);
1795    qemu_get_8s(f, &s->st01);
1796
1797    qemu_get_8s(f, &s->dac_state);
1798    qemu_get_8s(f, &s->dac_sub_index);
1799    qemu_get_8s(f, &s->dac_read_index);
1800    qemu_get_8s(f, &s->dac_write_index);
1801    qemu_get_buffer(f, s->dac_cache, 3);
1802    qemu_get_buffer(f, s->palette, 768);
1803
1804    qemu_get_be32s(f, &s->bank_offset);
1805    is_vbe = qemu_get_byte(f);
1806#ifdef CONFIG_BOCHS_VBE
1807    if (!is_vbe)
1808        return -EINVAL;
1809    qemu_get_be16s(f, &s->vbe_index);
1810    for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
1811        qemu_get_be16s(f, &s->vbe_regs[i]);
1812    qemu_get_be32s(f, &s->vbe_start_addr);
1813    qemu_get_be32s(f, &s->vbe_line_offset);
1814    qemu_get_be32s(f, &s->vbe_bank_mask);
1815#else
1816    if (is_vbe)
1817        return -EINVAL;
1818#endif
1819
1820    /* force refresh */
1821    s->graphic_mode = -1;
1822    return 0;
1823}
1824
1825static void vga_map(PCIDevice *pci_dev, int region_num, 
1826                    uint32_t addr, uint32_t size, int type)
1827{
1828    VGAState *s = vga_state;
1829    if (region_num == PCI_ROM_SLOT) {
1830        cpu_register_physical_memory(addr, s->bios_size, s->bios_offset);
1831    } else {
1832        cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
1833    }
1834}
1835
1836/* do the same job as vgabios before vgabios get ready - yeah */
1837void vga_bios_init(VGAState *s)
1838{
1839    uint8_t palette_model[192] = {
1840        0,   0,   0,   0,   0, 170,   0, 170,
1841        0,   0, 170, 170, 170,   0,   0, 170,
1842        0, 170, 170,  85,   0, 170, 170, 170,
1843       85,  85,  85,  85,  85, 255,  85, 255,
1844       85,  85, 255, 255, 255,  85,  85, 255, 
1845       85, 255, 255, 255,  85, 255, 255, 255,
1846        0,  21,   0,   0,  21,  42,   0,  63,
1847        0,   0,  63,  42,  42,  21,   0,  42,
1848       21,  42,  42,  63,   0,  42,  63,  42,
1849        0,  21,  21,   0,  21,  63,   0,  63, 
1850       21,   0,  63,  63,  42,  21,  21,  42,
1851       21,  63,  42,  63,  21,  42,  63,  63,
1852       21,   0,   0,  21,   0,  42,  21,  42,
1853        0,  21,  42,  42,  63,   0,   0,  63,
1854        0,  42,  63,  42,   0,  63,  42,  42,
1855       21,   0,  21,  21,   0,  63,  21,  42,
1856       21,  21,  42,  63,  63,   0,  21,  63,
1857        0,  63,  63,  42,  21,  63,  42,  63,
1858       21,  21,   0,  21,  21,  42,  21,  63,
1859        0,  21,  63,  42,  63,  21,   0,  63,
1860       21,  42,  63,  63,   0,  63,  63,  42,
1861       21,  21,  21,  21,  21,  63,  21,  63,
1862       21,  21,  63,  63,  63,  21,  21,  63,
1863       21,  63,  63,  63,  21,  63,  63,  63
1864    };
1865
1866    s->latch = 0; 
1867
1868    s->sr_index = 3; 
1869    s->sr[0] = 3;
1870    s->sr[1] = 0;
1871    s->sr[2] = 3;
1872    s->sr[3] = 0;
1873    s->sr[4] = 2;
1874    s->sr[5] = 0;
1875    s->sr[6] = 0;
1876    s->sr[7] = 0;
1877
1878    s->gr_index = 5; 
1879    s->gr[0] = 0;
1880    s->gr[1] = 0;
1881    s->gr[2] = 0;
1882    s->gr[3] = 0;
1883    s->gr[4] = 0;
1884    s->gr[5] = 16;
1885    s->gr[6] = 14;
1886    s->gr[7] = 15;
1887    s->gr[8] = 255;
1888
1889    /* changed by out 0x03c0 */
1890    s->ar_index = 32;
1891    s->ar[0] = 0;
1892    s->ar[1] = 1;
1893    s->ar[2] = 2;
1894    s->ar[3] = 3;
1895    s->ar[4] = 4;
1896    s->ar[5] = 5;
1897    s->ar[6] = 6;
1898    s->ar[7] = 7;
1899    s->ar[8] = 8;
1900    s->ar[9] = 9;
1901    s->ar[10] = 10;
1902    s->ar[11] = 11;
1903    s->ar[12] = 12;
1904    s->ar[13] = 13;
1905    s->ar[14] = 14;
1906    s->ar[15] = 15;
1907    s->ar[16] = 12;
1908    s->ar[17] = 0;
1909    s->ar[18] = 15;
1910    s->ar[19] = 8;
1911    s->ar[20] = 0;
1912
1913    s->ar_flip_flop = 1; 
1914
1915    s->cr_index = 15; 
1916    s->cr[0] = 95;
1917    s->cr[1] = 79;
1918    s->cr[2] = 80;
1919    s->cr[3] = 130;
1920    s->cr[4] = 85;
1921    s->cr[5] = 129;
1922    s->cr[6] = 191;
1923    s->cr[7] = 31;
1924    s->cr[8] = 0;
1925    s->cr[9] = 79;
1926    s->cr[10] = 14;
1927    s->cr[11] = 15;
1928    s->cr[12] = 0;
1929    s->cr[13] = 0;
1930    s->cr[14] = 5;
1931    s->cr[15] = 160;
1932    s->cr[16] = 156;
1933    s->cr[17] = 142;
1934    s->cr[18] = 143;
1935    s->cr[19] = 40;
1936    s->cr[20] = 31;
1937    s->cr[21] = 150;
1938    s->cr[22] = 185;
1939    s->cr[23] = 163;
1940    s->cr[24] = 255;
1941
1942    s->msr = 103; 
1943    s->fcr = 0; 
1944    s->st00 = 0; 
1945    s->st01 = 0; 
1946
1947    /* dac_* & palette will be initialized by os through out 0x03c8 &
1948     * out 0c03c9(1:3) */
1949    s->dac_state = 0; 
1950    s->dac_sub_index = 0; 
1951    s->dac_read_index = 0; 
1952    s->dac_write_index = 16; 
1953    s->dac_cache[0] = 255;
1954    s->dac_cache[1] = 255;
1955    s->dac_cache[2] = 255;
1956
1957    /* palette */
1958    memcpy(s->palette, palette_model, 192);
1959
1960    s->bank_offset = 0;
1961    s->graphic_mode = -1;
1962
1963    /* TODO: add vbe support if enabled */
1964}
1965
1966/* when used on xen environment, the vga_ram_base is not used */
1967void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base, 
1968                     unsigned long vga_ram_offset, int vga_ram_size)
1969{
1970    int i, j, v, b;
1971
1972    for(i = 0;i < 256; i++) {
1973        v = 0;
1974        for(j = 0; j < 8; j++) {
1975            v |= ((i >> j) & 1) << (j * 4);
1976        }
1977        expand4[i] = v;
1978
1979        v = 0;
1980        for(j = 0; j < 4; j++) {
1981            v |= ((i >> (2 * j)) & 3) << (j * 4);
1982        }
1983        expand2[i] = v;
1984    }
1985    for(i = 0; i < 16; i++) {
1986        v = 0;
1987        for(j = 0; j < 4; j++) {
1988            b = ((i >> j) & 1);
1989            v |= b << (2 * j);
1990            v |= b << (2 * j + 1);
1991        }
1992        expand4to8[i] = v;
1993    }
1994
1995    vga_reset(s);
1996
1997    check_sse2();
1998    s->vram_shadow = qemu_malloc(vga_ram_size+TARGET_PAGE_SIZE+1);
1999    if (s->vram_shadow == NULL)
2000        fprintf(stderr, "Cannot allocate %d bytes for VRAM shadow, "
2001                "mouse will be slow\n", vga_ram_size);
2002    s->vram_shadow = (uint8_t *)((long)(s->vram_shadow + TARGET_PAGE_SIZE - 1)
2003                                 & ~(TARGET_PAGE_SIZE - 1));
2004
2005    /* Video RAM must be 128-bit aligned for SSE optimizations later */
2006    s->vram_alloc = qemu_malloc(vga_ram_size + 15);
2007    s->vram_ptr = (uint8_t *)((long)(s->vram_alloc + 15) & ~15L);
2008
2009    s->vram_offset = vga_ram_offset;
2010    s->vram_size = vga_ram_size;
2011    s->ds = ds;
2012    s->get_bpp = vga_get_bpp;
2013    s->get_offsets = vga_get_offsets;
2014    s->get_resolution = vga_get_resolution;
2015    graphic_console_init(s->ds, vga_update_display, vga_invalidate_display,
2016                         vga_screen_dump, s);
2017    /* XXX: currently needed for display */
2018    vga_state = s;
2019
2020    vga_bios_init(s);
2021}
2022
2023
2024int vga_initialize(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, 
2025                   unsigned long vga_ram_offset, int vga_ram_size,
2026                   unsigned long vga_bios_offset, int vga_bios_size)
2027{
2028    VGAState *s;
2029
2030    s = qemu_mallocz(sizeof(VGAState));
2031    if (!s)
2032        return -1;
2033
2034    vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size);
2035
2036    register_savevm("vga", 0, 1, vga_save, vga_load, s);
2037
2038    register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
2039
2040    register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
2041    register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);
2042    register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);
2043    register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);
2044
2045    register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
2046
2047    register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);
2048    register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);
2049    register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
2050    register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
2051    s->bank_offset = 0;
2052
2053#ifdef CONFIG_BOCHS_VBE
2054    s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0;
2055    s->vbe_bank_mask = ((s->vram_size >> 16) - 1);
2056#if defined (TARGET_I386)
2057    register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
2058    register_ioport_read(0x1cf, 1, 2, vbe_ioport_read_data, s);
2059
2060    register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
2061    register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data, s);
2062
2063    /* old Bochs IO ports */
2064    register_ioport_read(0xff80, 1, 2, vbe_ioport_read_index, s);
2065    register_ioport_read(0xff81, 1, 2, vbe_ioport_read_data, s);
2066
2067    register_ioport_write(0xff80, 1, 2, vbe_ioport_write_index, s);
2068    register_ioport_write(0xff81, 1, 2, vbe_ioport_write_data, s); 
2069#else
2070    register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
2071    register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data, s);
2072
2073    register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
2074    register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data, s);
2075#endif
2076#endif /* CONFIG_BOCHS_VBE */
2077
2078    vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s);
2079    cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000, 
2080                                 vga_io_memory);
2081
2082    if (bus) {
2083        PCIDevice *d;
2084        uint8_t *pci_conf;
2085
2086        d = pci_register_device(bus, "VGA", 
2087                                sizeof(PCIDevice),
2088                                -1, NULL, NULL);
2089        pci_conf = d->config;
2090        pci_conf[0x00] = 0x34; // dummy VGA (same as Bochs ID)
2091        pci_conf[0x01] = 0x12;
2092        pci_conf[0x02] = 0x11;
2093        pci_conf[0x03] = 0x11;
2094        pci_conf[0x0a] = 0x00; // VGA controller
2095        pci_conf[0x0b] = 0x03;
2096        pci_conf[0x0e] = 0x00; // header_type
2097
2098        /* XXX: vga_ram_size must be a power of two */
2099        pci_register_io_region(d, 0, vga_ram_size, 
2100                               PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
2101        if (vga_bios_size != 0) {
2102            unsigned int bios_total_size;
2103            s->bios_offset = vga_bios_offset;
2104            s->bios_size = vga_bios_size;
2105            /* must be a power of two */
2106            bios_total_size = 1;
2107            while (bios_total_size < vga_bios_size)
2108                bios_total_size <<= 1;
2109            pci_register_io_region(d, PCI_ROM_SLOT, bios_total_size, 
2110                                   PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
2111        }
2112    } else {
2113#ifdef CONFIG_BOCHS_VBE
2114        /* XXX: use optimized standard vga accesses */
2115        cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS, 
2116                                     vga_ram_size, vga_ram_offset);
2117#endif
2118    }
2119    return 0;
2120}
2121
2122void *vga_update_vram(VGAState *s, void *vga_ram_base, int vga_ram_size)
2123{
2124    uint8_t *old_pointer;
2125
2126    if (s->vram_size != vga_ram_size) {
2127        fprintf(stderr, "No support to change vga_ram_size\n");
2128        return NULL;
2129    }
2130
2131    if (!vga_ram_base) {
2132        vga_ram_base = qemu_malloc(vga_ram_size + TARGET_PAGE_SIZE + 1);
2133        if (!vga_ram_base) {
2134            fprintf(stderr, "reallocate error\n");
2135            return NULL;
2136        }
2137    }
2138
2139    /* XXX lock needed? */
2140    old_pointer = s->vram_alloc;
2141    s->vram_alloc = vga_ram_base;
2142    vga_ram_base = (uint8_t *)((long)(vga_ram_base + 15) & ~15L);
2143    memcpy(vga_ram_base, s->vram_ptr, vga_ram_size);
2144    s->vram_ptr = vga_ram_base;
2145
2146    return old_pointer;
2147}
2148
2149/********************************************************/
2150/* vga screen dump */
2151
2152static int vga_save_w, vga_save_h;
2153
2154static void vga_save_dpy_update(DisplayState *s, 
2155                                int x, int y, int w, int h)
2156{
2157}
2158
2159static void vga_save_dpy_resize(DisplayState *s, int w, int h)
2160{
2161    s->linesize = w * 4;
2162    s->data = qemu_malloc(h * s->linesize);
2163    vga_save_w = w;
2164    vga_save_h = h;
2165}
2166
2167static void vga_save_dpy_refresh(DisplayState *s)
2168{
2169}
2170
2171static int ppm_save(const char *filename, uint8_t *data, 
2172                    int w, int h, int linesize)
2173{
2174    FILE *f;
2175    uint8_t *d, *d1;
2176    unsigned int v;
2177    int y, x;
2178
2179    f = fopen(filename, "wb");
2180    if (!f)
2181        return -1;
2182    fprintf(f, "P6\n%d %d\n%d\n",
2183            w, h, 255);
2184    d1 = data;
2185    for(y = 0; y < h; y++) {
2186        d = d1;
2187        for(x = 0; x < w; x++) {
2188            v = *(uint32_t *)d;
2189            fputc((v >> 16) & 0xff, f);
2190            fputc((v >> 8) & 0xff, f);
2191            fputc((v) & 0xff, f);
2192            d += 4;
2193        }
2194        d1 += linesize;
2195    }
2196    fclose(f);
2197    return 0;
2198}
2199
2200/* save the vga display in a PPM image even if no display is
2201   available */
2202static void vga_screen_dump(void *opaque, const char *filename)
2203{
2204    VGAState *s = (VGAState *)opaque;
2205    DisplayState *saved_ds, ds1, *ds = &ds1;
2206   
2207    /* XXX: this is a little hackish */
2208    vga_invalidate_display(s);
2209    saved_ds = s->ds;
2210
2211    memset(ds, 0, sizeof(DisplayState));
2212    ds->dpy_update = vga_save_dpy_update;
2213    ds->dpy_resize = vga_save_dpy_resize;
2214    ds->dpy_refresh = vga_save_dpy_refresh;
2215    ds->depth = 32;
2216
2217    s->ds = ds;
2218    s->graphic_mode = -1;
2219    vga_update_display(s);
2220   
2221    if (ds->data) {
2222        ppm_save(filename, ds->data, vga_save_w, vga_save_h, 
2223                 s->ds->linesize);
2224        qemu_free(ds->data);
2225    }
2226    s->ds = saved_ds;
2227}
Note: See TracBrowser for help on using the repository browser.