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