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