spelling fixes
[qemu] / hw / vga.c
index 452de61..2a0a9c3 100644 (file)
--- a/hw/vga.c
+++ b/hw/vga.c
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <string.h>
-#include <getopt.h>
-#include <inttypes.h>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <time.h>
-#include <sys/time.h>
-#include <malloc.h>
-#include <termios.h>
-#include <sys/poll.h>
-#include <errno.h>
-#include <sys/wait.h>
-#include <netinet/in.h>
-
-#include "cpu.h"
-#include "exec-all.h"
-
 #include "vl.h"
+#include "vga_int.h"
 
 //#define DEBUG_VGA
 //#define DEBUG_VGA_MEM
 //#define DEBUG_S3
 //#define DEBUG_BOCHS_VBE
 
-#define CONFIG_S3VGA
-
-#define MSR_COLOR_EMULATION 0x01
-#define MSR_PAGE_SELECT     0x20
-
-#define ST01_V_RETRACE      0x08
-#define ST01_DISP_ENABLE    0x01
-
-/* bochs VBE support */
-#define CONFIG_BOCHS_VBE
-
-#define VBE_DISPI_MAX_XRES              1024
-#define VBE_DISPI_MAX_YRES              768
-
-#define VBE_DISPI_INDEX_ID              0x0
-#define VBE_DISPI_INDEX_XRES            0x1
-#define VBE_DISPI_INDEX_YRES            0x2
-#define VBE_DISPI_INDEX_BPP             0x3
-#define VBE_DISPI_INDEX_ENABLE          0x4
-#define VBE_DISPI_INDEX_BANK            0x5
-#define VBE_DISPI_INDEX_VIRT_WIDTH      0x6
-#define VBE_DISPI_INDEX_VIRT_HEIGHT     0x7
-#define VBE_DISPI_INDEX_X_OFFSET        0x8
-#define VBE_DISPI_INDEX_Y_OFFSET        0x9
-#define VBE_DISPI_INDEX_NB              0xa
-      
-#define VBE_DISPI_ID0                   0xB0C0
-#define VBE_DISPI_ID1                   0xB0C1
-#define VBE_DISPI_ID2                   0xB0C2
-  
-#define VBE_DISPI_DISABLED              0x00
-#define VBE_DISPI_ENABLED               0x01
-#define VBE_DISPI_LFB_ENABLED           0x40
-#define VBE_DISPI_NOCLEARMEM            0x80
-  
-#define VBE_DISPI_LFB_PHYSICAL_ADDRESS  0xE0000000
-
-typedef struct VGAState {
-    uint8_t *vram_ptr;
-    unsigned long vram_offset;
-    unsigned int vram_size;
-    uint32_t latch;
-    uint8_t sr_index;
-    uint8_t sr[8];
-    uint8_t gr_index;
-    uint8_t gr[16];
-    uint8_t ar_index;
-    uint8_t ar[21];
-    int ar_flip_flop;
-    uint8_t cr_index;
-    uint8_t cr[256]; /* CRT registers */
-    uint8_t msr; /* Misc Output Register */
-    uint8_t fcr; /* Feature Control Register */
-    uint8_t st00; /* status 0 */
-    uint8_t st01; /* status 1 */
-    uint8_t dac_state;
-    uint8_t dac_sub_index;
-    uint8_t dac_read_index;
-    uint8_t dac_write_index;
-    uint8_t dac_cache[3]; /* used when writing */
-    uint8_t palette[768];
-    uint32_t bank_offset;
-#ifdef CONFIG_BOCHS_VBE
-    uint16_t vbe_index;
-    uint16_t vbe_regs[VBE_DISPI_INDEX_NB];
-    uint32_t vbe_start_addr;
-    uint32_t vbe_line_offset;
-    uint32_t vbe_bank_mask;
-#endif
-    /* display refresh support */
-    DisplayState *ds;
-    uint32_t font_offsets[2];
-    int graphic_mode;
-    uint8_t shift_control;
-    uint8_t double_scan;
-    uint32_t line_offset;
-    uint32_t line_compare;
-    uint32_t start_addr;
-    uint8_t last_cw, last_ch;
-    uint32_t last_width, last_height;
-    uint8_t cursor_start, cursor_end;
-    uint32_t cursor_offset;
-    unsigned int (*rgb_to_pixel)(unsigned int r, unsigned int g, unsigned b);
-    /* tell for each page if it has been updated since the last time */
-    uint32_t last_palette[256];
-#define CH_ATTR_SIZE (160 * 100)
-    uint32_t last_ch_attr[CH_ATTR_SIZE]; /* XXX: make it dynamic */
-} VGAState;
+/* S3 VGA is deprecated - another graphic card will be emulated */
+//#define CONFIG_S3VGA
 
 /* force some bits to zero */
-static const uint8_t sr_mask[8] = {
+const uint8_t sr_mask[8] = {
     (uint8_t)~0xfc,
     (uint8_t)~0xc2,
     (uint8_t)~0xf0,
@@ -153,7 +46,7 @@ static const uint8_t sr_mask[8] = {
     (uint8_t)~0x00,
 };
 
-static const uint8_t gr_mask[16] = {
+const uint8_t gr_mask[16] = {
     (uint8_t)~0xf0, /* 0x00 */
     (uint8_t)~0xf0, /* 0x01 */
     (uint8_t)~0xf0, /* 0x02 */
@@ -254,7 +147,7 @@ static uint32_t expand4[256];
 static uint16_t expand2[256];
 static uint8_t expand4to8[16];
 
-VGAState vga_state;
+VGAState *vga_state;
 int vga_io_memory;
 
 static uint32_t vga_ioport_read(void *opaque, uint32_t addr)
@@ -297,6 +190,9 @@ static uint32_t vga_ioport_read(void *opaque, uint32_t addr)
         case 0x3c7:
             val = s->dac_state;
             break;
+       case 0x3c8:
+           val = s->dac_write_index;
+           break;
         case 0x3c9:
             val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
             if (++s->dac_sub_index == 3) {
@@ -356,7 +252,7 @@ static uint32_t vga_ioport_read(void *opaque, uint32_t addr)
 static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
 {
     VGAState *s = opaque;
-    int index, v;
+    int index;
 
     /* check port range access depending on color/monochrome mode */
     if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
@@ -474,15 +370,21 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
             break;
         case 0x31:
             /* update start address */
-            s->cr[s->cr_index] = val;
-            v = (val >> 4) & 3;
-            s->cr[0x69] = (s->cr[69] & ~0x03) | v;
+            {
+                int v;
+                s->cr[s->cr_index] = val;
+                v = (val >> 4) & 3;
+                s->cr[0x69] = (s->cr[69] & ~0x03) | v;
+            }
             break;
         case 0x51:
             /* update start address */
-            s->cr[s->cr_index] = val;
-            v = val & 3;
-            s->cr[0x69] = (s->cr[69] & ~0x0c) | (v << 2);
+            {
+                int v;
+                s->cr[s->cr_index] = val;
+                v = val & 3;
+                s->cr[0x69] = (s->cr[69] & ~0x0c) | (v << 2);
+            }
             break;
 #endif
         default:
@@ -503,34 +405,40 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
 }
 
 #ifdef CONFIG_BOCHS_VBE
-static uint32_t vbe_ioport_read(void *opaque, uint32_t addr)
+static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
 {
     VGAState *s = opaque;
     uint32_t val;
+    val = s->vbe_index;
+    return val;
+}
 
-    addr &= 1;
-    if (addr == 0) {
-        val = s->vbe_index;
-    } else {
-        if (s->vbe_index <= VBE_DISPI_INDEX_NB)
-            val = s->vbe_regs[s->vbe_index];
-        else
-            val = 0;
+static uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr)
+{
+    VGAState *s = opaque;
+    uint32_t val;
+
+    if (s->vbe_index <= VBE_DISPI_INDEX_NB)
+        val = s->vbe_regs[s->vbe_index];
+    else
+        val = 0;
 #ifdef DEBUG_BOCHS_VBE
-        printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val);
+    printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val);
 #endif
-    }
     return val;
 }
 
-static void vbe_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+static void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val)
+{
+    VGAState *s = opaque;
+    s->vbe_index = val;
+}
+
+static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
 {
     VGAState *s = opaque;
 
-    addr &= 1;
-    if (addr == 0) {
-        s->vbe_index = val;
-    } else if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
+    if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
 #ifdef DEBUG_BOCHS_VBE
         printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val);
 #endif
@@ -563,7 +471,7 @@ static void vbe_ioport_write(void *opaque, uint32_t addr, uint32_t val)
         case VBE_DISPI_INDEX_BANK:
             val &= s->vbe_bank_mask;
             s->vbe_regs[s->vbe_index] = val;
-            s->bank_offset = (val << 16) - 0xa0000;
+            s->bank_offset = (val << 16);
             break;
         case VBE_DISPI_INDEX_ENABLE:
             if (val & VBE_DISPI_ENABLED) {
@@ -611,14 +519,16 @@ static void vbe_ioport_write(void *opaque, uint32_t addr, uint32_t val)
                     s->sr[0x01] &= ~8; /* no double line */
                 } else {
                     shift_control = 2;
+                    s->sr[4] |= 0x08; /* set chain 4 mode */
+                    s->sr[2] |= 0x0f; /* activate all planes */
                 }
                 s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5);
                 s->cr[0x09] &= ~0x9f; /* no double scan */
-                s->vbe_regs[s->vbe_index] = val;
             } else {
                 /* XXX: the bios should do that */
-                s->bank_offset = -0xa0000;
+                s->bank_offset = 0;
             }
+            s->vbe_regs[s->vbe_index] = val;
             break;
         case VBE_DISPI_INDEX_VIRT_WIDTH:
             {
@@ -662,31 +572,31 @@ static void vbe_ioport_write(void *opaque, uint32_t addr, uint32_t val)
 #endif
 
 /* called for accesses between 0xa0000 and 0xc0000 */
-static uint32_t vga_mem_readb(uint32_t addr)
+uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr)
 {
-    VGAState *s = &vga_state;
+    VGAState *s = opaque;
     int memory_map_mode, plane;
     uint32_t ret;
     
     /* convert to VGA memory offset */
     memory_map_mode = (s->gr[6] >> 2) & 3;
+    addr &= 0x1ffff;
     switch(memory_map_mode) {
     case 0:
-        addr -= 0xa0000;
         break;
     case 1:
-        if (addr >= 0xb0000)
+        if (addr >= 0x10000)
             return 0xff;
         addr += s->bank_offset;
         break;
     case 2:
-        addr -= 0xb0000;
+        addr -= 0x10000;
         if (addr >= 0x8000)
             return 0xff;
         break;
     default:
     case 3:
-        addr -= 0xb8000;
+        addr -= 0x18000;
         if (addr >= 0x8000)
             return 0xff;
         break;
@@ -718,28 +628,40 @@ static uint32_t vga_mem_readb(uint32_t addr)
     return ret;
 }
 
-static uint32_t vga_mem_readw(uint32_t addr)
+static uint32_t vga_mem_readw(void *opaque, target_phys_addr_t addr)
 {
     uint32_t v;
-    v = vga_mem_readb(addr);
-    v |= vga_mem_readb(addr + 1) << 8;
+#ifdef TARGET_WORDS_BIGENDIAN
+    v = vga_mem_readb(opaque, addr) << 8;
+    v |= vga_mem_readb(opaque, addr + 1);
+#else
+    v = vga_mem_readb(opaque, addr);
+    v |= vga_mem_readb(opaque, addr + 1) << 8;
+#endif
     return v;
 }
 
-static uint32_t vga_mem_readl(uint32_t addr)
+static uint32_t vga_mem_readl(void *opaque, target_phys_addr_t addr)
 {
     uint32_t v;
-    v = vga_mem_readb(addr);
-    v |= vga_mem_readb(addr + 1) << 8;
-    v |= vga_mem_readb(addr + 2) << 16;
-    v |= vga_mem_readb(addr + 3) << 24;
+#ifdef TARGET_WORDS_BIGENDIAN
+    v = vga_mem_readb(opaque, addr) << 24;
+    v |= vga_mem_readb(opaque, addr + 1) << 16;
+    v |= vga_mem_readb(opaque, addr + 2) << 8;
+    v |= vga_mem_readb(opaque, addr + 3);
+#else
+    v = vga_mem_readb(opaque, addr);
+    v |= vga_mem_readb(opaque, addr + 1) << 8;
+    v |= vga_mem_readb(opaque, addr + 2) << 16;
+    v |= vga_mem_readb(opaque, addr + 3) << 24;
+#endif
     return v;
 }
 
 /* called for accesses between 0xa0000 and 0xc0000 */
-void vga_mem_writeb(uint32_t addr, uint32_t val, uint32_t vaddr)
+void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
 {
-    VGAState *s = &vga_state;
+    VGAState *s = opaque;
     int memory_map_mode, plane, write_mode, b, func_select;
     uint32_t write_mask, bit_mask, set_mask;
 
@@ -748,23 +670,23 @@ void vga_mem_writeb(uint32_t addr, uint32_t val, uint32_t vaddr)
 #endif
     /* convert to VGA memory offset */
     memory_map_mode = (s->gr[6] >> 2) & 3;
+    addr &= 0x1ffff;
     switch(memory_map_mode) {
     case 0:
-        addr -= 0xa0000;
         break;
     case 1:
-        if (addr >= 0xb0000)
+        if (addr >= 0x10000)
             return;
         addr += s->bank_offset;
         break;
     case 2:
-        addr -= 0xb0000;
+        addr -= 0x10000;
         if (addr >= 0x8000)
             return;
         break;
     default:
     case 3:
-        addr -= 0xb8000;
+        addr -= 0x18000;
         if (addr >= 0x8000)
             return;
         break;
@@ -865,18 +787,30 @@ void vga_mem_writeb(uint32_t addr, uint32_t val, uint32_t vaddr)
     }
 }
 
-void vga_mem_writew(uint32_t addr, uint32_t val, uint32_t vaddr)
+static void vga_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
 {
-    vga_mem_writeb(addr, val & 0xff, vaddr);
-    vga_mem_writeb(addr + 1, (val >> 8) & 0xff, vaddr);
+#ifdef TARGET_WORDS_BIGENDIAN
+    vga_mem_writeb(opaque, addr, (val >> 8) & 0xff);
+    vga_mem_writeb(opaque, addr + 1, val & 0xff);
+#else
+    vga_mem_writeb(opaque, addr, val & 0xff);
+    vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
+#endif
 }
 
-void vga_mem_writel(uint32_t addr, uint32_t val, uint32_t vaddr)
+static void vga_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
 {
-    vga_mem_writeb(addr, val & 0xff, vaddr);
-    vga_mem_writeb(addr + 1, (val >> 8) & 0xff, vaddr);
-    vga_mem_writeb(addr + 2, (val >> 16) & 0xff, vaddr);
-    vga_mem_writeb(addr + 3, (val >> 24) & 0xff, vaddr);
+#ifdef TARGET_WORDS_BIGENDIAN
+    vga_mem_writeb(opaque, addr, (val >> 24) & 0xff);
+    vga_mem_writeb(opaque, addr + 1, (val >> 16) & 0xff);
+    vga_mem_writeb(opaque, addr + 2, (val >> 8) & 0xff);
+    vga_mem_writeb(opaque, addr + 3, val & 0xff);
+#else
+    vga_mem_writeb(opaque, addr, val & 0xff);
+    vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
+    vga_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff);
+    vga_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff);
+#endif
 }
 
 typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
@@ -921,14 +855,6 @@ static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g, unsign
 #define DEPTH 32
 #include "vga_template.h"
 
-static inline int c6_to_8(int v)
-{
-    int b;
-    v &= 0x3f;
-    b = v & 1;
-    return (v << 2) | (b << 1) | b;
-}
-
 static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
 {
     unsigned int col;
@@ -1009,14 +935,11 @@ static int update_palette256(VGAState *s)
     return full_update;
 }
 
-/* update start_addr and line_offset. Return TRUE if modified */
-static int update_basic_params(VGAState *s)
+static void vga_get_offsets(VGAState *s, 
+                            uint32_t *pline_offset, 
+                            uint32_t *pstart_addr)
 {
-    int full_update;
-    uint32_t start_addr, line_offset, line_compare, v;
-    
-    full_update = 0;
-
+    uint32_t start_addr, line_offset;
 #ifdef CONFIG_BOCHS_VBE
     if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
         line_offset = s->vbe_line_offset;
@@ -1027,10 +950,13 @@ static int update_basic_params(VGAState *s)
         /* compute line_offset in bytes */
         line_offset = s->cr[0x13];
 #ifdef CONFIG_S3VGA
-        v = (s->cr[0x51] >> 4) & 3; /* S3 extension */
-        if (v == 0)
-            v = (s->cr[0x43] >> 2) & 1; /* S3 extension */
-        line_offset |= (v << 8);
+        {
+            uinr32_t v;
+            v = (s->cr[0x51] >> 4) & 3; /* S3 extension */
+            if (v == 0)
+                v = (s->cr[0x43] >> 2) & 1; /* S3 extension */
+            line_offset |= (v << 8);
+        }
 #endif
         line_offset <<= 3;
         
@@ -1040,7 +966,19 @@ static int update_basic_params(VGAState *s)
         start_addr |= (s->cr[0x69] & 0x1f) << 16; /* S3 extension */
 #endif
     }
+    *pline_offset = line_offset;
+    *pstart_addr = start_addr;
+}
+
+/* update start_addr and line_offset. Return TRUE if modified */
+static int update_basic_params(VGAState *s)
+{
+    int full_update;
+    uint32_t start_addr, line_offset, line_compare;
     
+    full_update = 0;
+
+    s->get_offsets(s, &line_offset, &start_addr);
     /* line compare */
     line_compare = s->cr[0x18] | 
         ((s->cr[0x07] & 0x10) << 4) |
@@ -1138,14 +1076,14 @@ static void vga_draw_text(VGAState *s, int full_update)
     
     /* compute font data address (in plane 2) */
     v = s->sr[3];
-    offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
+    offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
     if (offset != s->font_offsets[0]) {
         s->font_offsets[0] = offset;
         full_update = 1;
     }
     font_base[0] = s->vram_ptr + offset;
 
-    offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
+    offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
     font_base[1] = s->vram_ptr + offset;
     if (offset != s->font_offsets[1]) {
         s->font_offsets[1] = offset;
@@ -1160,7 +1098,7 @@ static void vga_draw_text(VGAState *s, int full_update)
     /* total width & height */
     cheight = (s->cr[9] & 0x1f) + 1;
     cw = 8;
-    if (s->sr[1] & 0x01)
+    if (!(s->sr[1] & 0x01))
         cw = 9;
     if (s->sr[1] & 0x08)
         cw = 16; /* NOTE: no 18 pixel wide */
@@ -1175,9 +1113,16 @@ static void vga_draw_text(VGAState *s, int full_update)
             ((s->cr[0x07] & 0x40) << 3);
         height = (height + 1) / cheight;
     }
+    if ((height * width) > CH_ATTR_SIZE) {
+        /* better than nothing: exit if transient size is too big */
+        return;
+    }
+
     if (width != s->last_width || height != s->last_height ||
-        cw != s->last_cw || cw != s->last_cw) {
-        dpy_resize(s->ds, width * cw, height * cheight);
+        cw != s->last_cw || cheight != s->last_ch) {
+        s->last_scr_width = width * cw;
+        s->last_scr_height = height * cheight;
+        dpy_resize(s->ds, s->last_scr_width, s->last_scr_height);
         s->last_width = width;
         s->last_height = height;
         s->last_ch = cheight;
@@ -1345,11 +1290,47 @@ static vga_draw_line_func *vga_draw_line_table[4 * VGA_DRAW_LINE_NB] = {
     vga_draw_line32_32,
 };
 
+static int vga_get_bpp(VGAState *s)
+{
+    int ret;
+#ifdef CONFIG_BOCHS_VBE
+    if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+        ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
+    } else 
+#endif
+    {
+        ret = 0;
+    }
+    return ret;
+}
+
+static void vga_get_resolution(VGAState *s, int *pwidth, int *pheight)
+{
+    int width, height;
+    
+    width = (s->cr[0x01] + 1) * 8;
+    height = s->cr[0x12] | 
+        ((s->cr[0x07] & 0x02) << 7) | 
+        ((s->cr[0x07] & 0x40) << 3);
+    height = (height + 1);
+    *pwidth = width;
+    *pheight = height;
+}
+
+void vga_invalidate_scanlines(VGAState *s, int y1, int y2)
+{
+    int y;
+    if (y1 >= VGA_MAX_HEIGHT)
+        return;
+    if (y2 >= VGA_MAX_HEIGHT)
+        y2 = VGA_MAX_HEIGHT;
+    for(y = y1; y < y2; y++) {
+        s->invalidated_y_table[y >> 5] |= 1 << (y & 0x1f);
+    }
+}
+
 /* 
  * graphic modes
- * Missing:
- * - double scan
- * - double width 
  */
 static void vga_draw_graphic(VGAState *s, int full_update)
 {
@@ -1362,13 +1343,9 @@ static void vga_draw_graphic(VGAState *s, int full_update)
     
     full_update |= update_basic_params(s);
 
-    width = (s->cr[0x01] + 1) * 8;
-    height = s->cr[0x12] | 
-        ((s->cr[0x07] & 0x02) << 7) | 
-        ((s->cr[0x07] & 0x40) << 3);
-    height = (height + 1);
+    s->get_resolution(s, &width, &height);
     disp_width = width;
-    
+
     shift_control = (s->gr[0x05] >> 5) & 3;
     double_scan = (s->cr[0x09] & 0x80);
     if (shift_control > 1) {
@@ -1401,32 +1378,28 @@ static void vga_draw_graphic(VGAState *s, int full_update)
             v = VGA_DRAW_LINE2;
         }
     } else {
-#ifdef CONFIG_BOCHS_VBE
-        if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
-            switch(s->vbe_regs[VBE_DISPI_INDEX_BPP]) {
-            default:
-            case 8:
-                full_update |= update_palette256(s);
-                v = VGA_DRAW_LINE8;
-                break;
-            case 15:
-                v = VGA_DRAW_LINE15;
-                break;
-            case 16:
-                v = VGA_DRAW_LINE16;
-                break;
-            case 24:
-                v = VGA_DRAW_LINE24;
-                break;
-            case 32:
-                v = VGA_DRAW_LINE32;
-                break;
-            }
-        } else 
-#endif
-        {
+        switch(s->get_bpp(s)) {
+        default:
+        case 0:
             full_update |= update_palette256(s);
             v = VGA_DRAW_LINE8D2;
+            break;
+        case 8:
+            full_update |= update_palette256(s);
+            v = VGA_DRAW_LINE8;
+            break;
+        case 15:
+            v = VGA_DRAW_LINE15;
+            break;
+        case 16:
+            v = VGA_DRAW_LINE16;
+            break;
+        case 24:
+            v = VGA_DRAW_LINE24;
+            break;
+        case 32:
+            v = VGA_DRAW_LINE32;
+            break;
         }
     }
     vga_draw_line = vga_draw_line_table[v * 4 + get_depth_index(s->ds->depth)];
@@ -1434,11 +1407,15 @@ static void vga_draw_graphic(VGAState *s, int full_update)
     if (disp_width != s->last_width ||
         height != s->last_height) {
         dpy_resize(s->ds, disp_width, height);
+        s->last_scr_width = disp_width;
+        s->last_scr_height = height;
         s->last_width = disp_width;
         s->last_height = height;
         full_update = 1;
     }
-
+    if (s->cursor_invalidate)
+        s->cursor_invalidate(s);
+    
     line_offset = s->line_offset;
 #if 0
     printf("w=%d h=%d v=%d line_offset=%d double_scan=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=%02x\n",
@@ -1471,6 +1448,8 @@ static void vga_draw_graphic(VGAState *s, int full_update)
             /* if wide line, can use another page */
             update |= cpu_physical_memory_is_dirty(page0 + TARGET_PAGE_SIZE);
         }
+        /* explicit invalidation for the hardware cursor */
+        update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
         if (update) {
             if (y_start < 0)
                 y_start = y;
@@ -1479,6 +1458,8 @@ static void vga_draw_graphic(VGAState *s, int full_update)
             if (page1 > page_max)
                 page_max = page1;
             vga_draw_line(s, d, s->vram_ptr + addr, width);
+            if (s->cursor_draw_line)
+                s->cursor_draw_line(s, d, y);
         } else {
             if (y_start >= 0) {
                 /* flush to display */
@@ -1514,30 +1495,95 @@ static void vga_draw_graphic(VGAState *s, int full_update)
     if (page_max != -1) {
         cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE);
     }
+    memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
+}
+
+static void vga_draw_blank(VGAState *s, int full_update)
+{
+    int i, w, val;
+    uint8_t *d;
+
+    if (!full_update)
+        return;
+    if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
+        return;
+    if (s->ds->depth == 8) 
+        val = s->rgb_to_pixel(0, 0, 0);
+    else
+        val = 0;
+    w = s->last_scr_width * ((s->ds->depth + 7) >> 3);
+    d = s->ds->data;
+    for(i = 0; i < s->last_scr_height; i++) {
+        memset(d, val, w);
+        d += s->ds->linesize;
+    }
+    dpy_update(s->ds, 0, 0, 
+               s->last_scr_width, s->last_scr_height);
 }
 
+#define GMODE_TEXT     0
+#define GMODE_GRAPH    1
+#define GMODE_BLANK 2 
+
 void vga_update_display(void)
 {
-    VGAState *s = &vga_state;
+    VGAState *s = vga_state;
     int full_update, graphic_mode;
 
     if (s->ds->depth == 0) {
         /* nothing to do */
-   } else {
+    } else {
+        switch(s->ds->depth) {
+        case 8:
+            s->rgb_to_pixel = rgb_to_pixel8_dup;
+            break;
+        case 15:
+            s->rgb_to_pixel = rgb_to_pixel15_dup;
+            break;
+        default:
+        case 16:
+            s->rgb_to_pixel = rgb_to_pixel16_dup;
+            break;
+        case 32:
+            s->rgb_to_pixel = rgb_to_pixel32_dup;
+            break;
+        }
+        
         full_update = 0;
-        graphic_mode = s->gr[6] & 1;
+        if (!(s->ar_index & 0x20)) {
+            graphic_mode = GMODE_BLANK;
+        } else {
+            graphic_mode = s->gr[6] & 1;
+        }
         if (graphic_mode != s->graphic_mode) {
             s->graphic_mode = graphic_mode;
             full_update = 1;
         }
-        if (graphic_mode)
-            vga_draw_graphic(s, full_update);
-        else
+        switch(graphic_mode) {
+        case GMODE_TEXT:
             vga_draw_text(s, full_update);
+            break;
+        case GMODE_GRAPH:
+            vga_draw_graphic(s, full_update);
+            break;
+        case GMODE_BLANK:
+        default:
+            vga_draw_blank(s, full_update);
+            break;
+        }
     }
 }
 
-void vga_reset(VGAState *s)
+/* force a full display refresh */
+void vga_invalidate_display(void)
+{
+    VGAState *s = vga_state;
+    
+    s->last_width = -1;
+    s->last_height = -1;
+}
+
+static void vga_reset(VGAState *s)
 {
     memset(s, 0, sizeof(VGAState));
 #ifdef CONFIG_S3VGA
@@ -1550,22 +1596,121 @@ void vga_reset(VGAState *s)
     s->graphic_mode = -1; /* force full update */
 }
 
-CPUReadMemoryFunc *vga_mem_read[3] = {
+static CPUReadMemoryFunc *vga_mem_read[3] = {
     vga_mem_readb,
     vga_mem_readw,
     vga_mem_readl,
 };
 
-CPUWriteMemoryFunc *vga_mem_write[3] = {
+static CPUWriteMemoryFunc *vga_mem_write[3] = {
     vga_mem_writeb,
     vga_mem_writew,
     vga_mem_writel,
 };
 
-int vga_initialize(DisplayState *ds, uint8_t *vga_ram_base, 
-                   unsigned long vga_ram_offset, int vga_ram_size)
+static void vga_save(QEMUFile *f, void *opaque)
+{
+    VGAState *s = opaque;
+    int i;
+
+    qemu_put_be32s(f, &s->latch);
+    qemu_put_8s(f, &s->sr_index);
+    qemu_put_buffer(f, s->sr, 8);
+    qemu_put_8s(f, &s->gr_index);
+    qemu_put_buffer(f, s->gr, 16);
+    qemu_put_8s(f, &s->ar_index);
+    qemu_put_buffer(f, s->ar, 21);
+    qemu_put_be32s(f, &s->ar_flip_flop);
+    qemu_put_8s(f, &s->cr_index);
+    qemu_put_buffer(f, s->cr, 256);
+    qemu_put_8s(f, &s->msr);
+    qemu_put_8s(f, &s->fcr);
+    qemu_put_8s(f, &s->st00);
+    qemu_put_8s(f, &s->st01);
+
+    qemu_put_8s(f, &s->dac_state);
+    qemu_put_8s(f, &s->dac_sub_index);
+    qemu_put_8s(f, &s->dac_read_index);
+    qemu_put_8s(f, &s->dac_write_index);
+    qemu_put_buffer(f, s->dac_cache, 3);
+    qemu_put_buffer(f, s->palette, 768);
+
+    qemu_put_be32s(f, &s->bank_offset);
+#ifdef CONFIG_BOCHS_VBE
+    qemu_put_byte(f, 1);
+    qemu_put_be16s(f, &s->vbe_index);
+    for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
+        qemu_put_be16s(f, &s->vbe_regs[i]);
+    qemu_put_be32s(f, &s->vbe_start_addr);
+    qemu_put_be32s(f, &s->vbe_line_offset);
+    qemu_put_be32s(f, &s->vbe_bank_mask);
+#else
+    qemu_put_byte(f, 0);
+#endif
+}
+
+static int vga_load(QEMUFile *f, void *opaque, int version_id)
+{
+    VGAState *s = opaque;
+    int is_vbe, i;
+
+    if (version_id != 1)
+        return -EINVAL;
+
+    qemu_get_be32s(f, &s->latch);
+    qemu_get_8s(f, &s->sr_index);
+    qemu_get_buffer(f, s->sr, 8);
+    qemu_get_8s(f, &s->gr_index);
+    qemu_get_buffer(f, s->gr, 16);
+    qemu_get_8s(f, &s->ar_index);
+    qemu_get_buffer(f, s->ar, 21);
+    qemu_get_be32s(f, &s->ar_flip_flop);
+    qemu_get_8s(f, &s->cr_index);
+    qemu_get_buffer(f, s->cr, 256);
+    qemu_get_8s(f, &s->msr);
+    qemu_get_8s(f, &s->fcr);
+    qemu_get_8s(f, &s->st00);
+    qemu_get_8s(f, &s->st01);
+
+    qemu_get_8s(f, &s->dac_state);
+    qemu_get_8s(f, &s->dac_sub_index);
+    qemu_get_8s(f, &s->dac_read_index);
+    qemu_get_8s(f, &s->dac_write_index);
+    qemu_get_buffer(f, s->dac_cache, 3);
+    qemu_get_buffer(f, s->palette, 768);
+
+    qemu_get_be32s(f, &s->bank_offset);
+    is_vbe = qemu_get_byte(f);
+#ifdef CONFIG_BOCHS_VBE
+    if (!is_vbe)
+        return -EINVAL;
+    qemu_get_be16s(f, &s->vbe_index);
+    for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
+        qemu_get_be16s(f, &s->vbe_regs[i]);
+    qemu_get_be32s(f, &s->vbe_start_addr);
+    qemu_get_be32s(f, &s->vbe_line_offset);
+    qemu_get_be32s(f, &s->vbe_bank_mask);
+#else
+    if (is_vbe)
+        return -EINVAL;
+#endif
+
+    /* force refresh */
+    s->graphic_mode = -1;
+    return 0;
+}
+
+static void vga_map(PCIDevice *pci_dev, int region_num, 
+                    uint32_t addr, uint32_t size, int type)
+{
+    VGAState *s = vga_state;
+
+    cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
+}
+
+void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base, 
+                     unsigned long vga_ram_offset, int vga_ram_size)
 {
-    VGAState *s = &vga_state;
     int i, j, v, b;
 
     for(i = 0;i < 256; i++) {
@@ -1593,26 +1738,30 @@ int vga_initialize(DisplayState *ds, uint8_t *vga_ram_base,
 
     vga_reset(s);
 
-    switch(ds->depth) {
-    case 8:
-        s->rgb_to_pixel = rgb_to_pixel8_dup;
-        break;
-    case 15:
-        s->rgb_to_pixel = rgb_to_pixel15_dup;
-        break;
-    default:
-    case 16:
-        s->rgb_to_pixel = rgb_to_pixel16_dup;
-        break;
-    case 32:
-        s->rgb_to_pixel = rgb_to_pixel32_dup;
-        break;
-    }
-
     s->vram_ptr = vga_ram_base;
     s->vram_offset = vga_ram_offset;
     s->vram_size = vga_ram_size;
     s->ds = ds;
+    s->get_bpp = vga_get_bpp;
+    s->get_offsets = vga_get_offsets;
+    s->get_resolution = vga_get_resolution;
+    /* XXX: currently needed for display */
+    vga_state = s;
+}
+
+
+int vga_initialize(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, 
+                   unsigned long vga_ram_offset, int vga_ram_size)
+{
+    VGAState *s;
+
+    s = qemu_mallocz(sizeof(VGAState));
+    if (!s)
+        return -1;
+
+    vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size);
+
+    register_savevm("vga", 0, 1, vga_save, vga_load, s);
 
     register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
 
@@ -1627,28 +1776,142 @@ int vga_initialize(DisplayState *ds, uint8_t *vga_ram_base,
     register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);
     register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
     register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
-    s->bank_offset = -0xa0000;
+    s->bank_offset = 0;
 
 #ifdef CONFIG_BOCHS_VBE
     s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0;
     s->vbe_bank_mask = ((s->vram_size >> 16) - 1);
-    register_ioport_read(0x1ce, 1, 2, vbe_ioport_read, s);
-    register_ioport_read(0x1cf, 1, 2, vbe_ioport_read, s);
+#if defined (TARGET_I386)
+    register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
+    register_ioport_read(0x1cf, 1, 2, vbe_ioport_read_data, s);
 
-    register_ioport_write(0x1ce, 1, 2, vbe_ioport_write, s);
-    register_ioport_write(0x1cf, 1, 2, vbe_ioport_write, s);
-#endif
+    register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
+    register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data, s);
 
-    vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write);
-#if defined (TARGET_I386)
-    cpu_register_physical_memory(0x000a0000, 0x20000, vga_io_memory);
-#ifdef CONFIG_BOCHS_VBE
-    /* XXX: use optimized standard vga accesses */
-    cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS, 
-                                 vga_ram_size, vga_ram_offset);
+    /* old Bochs IO ports */
+    register_ioport_read(0xff80, 1, 2, vbe_ioport_read_index, s);
+    register_ioport_read(0xff81, 1, 2, vbe_ioport_read_data, s);
+
+    register_ioport_write(0xff80, 1, 2, vbe_ioport_write_index, s);
+    register_ioport_write(0xff81, 1, 2, vbe_ioport_write_data, s); 
+#else
+    register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
+    register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data, s);
+
+    register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
+    register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data, s);
 #endif
-#elif defined (TARGET_PPC)
-    cpu_register_physical_memory(0xf00a0000, 0x20000, vga_io_memory);
+#endif /* CONFIG_BOCHS_VBE */
+
+    vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s);
+    cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000, 
+                                 vga_io_memory);
+
+    if (bus) {
+        PCIDevice *d;
+        uint8_t *pci_conf;
+
+        d = pci_register_device(bus, "VGA", 
+                                sizeof(PCIDevice),
+                                -1, NULL, NULL);
+        pci_conf = d->config;
+        pci_conf[0x00] = 0x34; // dummy VGA (same as Bochs ID)
+        pci_conf[0x01] = 0x12;
+        pci_conf[0x02] = 0x11;
+        pci_conf[0x03] = 0x11;
+        pci_conf[0x0a] = 0x00; // VGA controller 
+        pci_conf[0x0b] = 0x03;
+        pci_conf[0x0e] = 0x00; // header_type
+
+        /* XXX: vga_ram_size must be a power of two */
+        pci_register_io_region(d, 0, vga_ram_size, 
+                               PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
+    } else {
+#ifdef CONFIG_BOCHS_VBE
+        /* XXX: use optimized standard vga accesses */
+        cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS, 
+                                     vga_ram_size, vga_ram_offset);
 #endif
+    }
     return 0;
 }
+
+/********************************************************/
+/* vga screen dump */
+
+static int vga_save_w, vga_save_h;
+
+static void vga_save_dpy_update(DisplayState *s, 
+                                int x, int y, int w, int h)
+{
+}
+
+static void vga_save_dpy_resize(DisplayState *s, int w, int h)
+{
+    s->linesize = w * 4;
+    s->data = qemu_malloc(h * s->linesize);
+    vga_save_w = w;
+    vga_save_h = h;
+}
+
+static void vga_save_dpy_refresh(DisplayState *s)
+{
+}
+
+static int ppm_save(const char *filename, uint8_t *data, 
+                    int w, int h, int linesize)
+{
+    FILE *f;
+    uint8_t *d, *d1;
+    unsigned int v;
+    int y, x;
+
+    f = fopen(filename, "wb");
+    if (!f)
+        return -1;
+    fprintf(f, "P6\n%d %d\n%d\n",
+            w, h, 255);
+    d1 = data;
+    for(y = 0; y < h; y++) {
+        d = d1;
+        for(x = 0; x < w; x++) {
+            v = *(uint32_t *)d;
+            fputc((v >> 16) & 0xff, f);
+            fputc((v >> 8) & 0xff, f);
+            fputc((v) & 0xff, f);
+            d += 4;
+        }
+        d1 += linesize;
+    }
+    fclose(f);
+    return 0;
+}
+
+/* save the vga display in a PPM image even if no display is
+   available */
+void vga_screen_dump(const char *filename)
+{
+    VGAState *s = vga_state;
+    DisplayState *saved_ds, ds1, *ds = &ds1;
+    
+    /* XXX: this is a little hackish */
+    vga_invalidate_display();
+    saved_ds = s->ds;
+
+    memset(ds, 0, sizeof(DisplayState));
+    ds->dpy_update = vga_save_dpy_update;
+    ds->dpy_resize = vga_save_dpy_resize;
+    ds->dpy_refresh = vga_save_dpy_refresh;
+    ds->depth = 32;
+
+    s->ds = ds;
+    s->graphic_mode = -1;
+    vga_update_display();
+    
+    if (ds->data) {
+        ppm_save(filename, ds->data, vga_save_w, vga_save_h, 
+                 s->ds->linesize);
+        qemu_free(ds->data);
+    }
+    s->ds = saved_ds;
+}