diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index 54a730d..babb816 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -2516,6 +2516,7 @@ static void map_linear_vram(CirrusVGAState *s)
         cpu_register_physical_memory(isa_mem_base + 0xa0000, 0x20000,
                                      s->vga.vga_io_memory);
         s->vga.vga_mem_mapped = false;
+        s->vga.vga_memory_map_mode = 1;
     }
 }
 
diff --git a/hw/vga.c b/hw/vga.c
index 4208151..6eef149 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -159,7 +159,13 @@ static void vga_sync_dirty_bitmap(VGACommonState *s)
     }
     if (s->vga_mem_mapped) {
         cpu_physical_sync_dirty_bitmap(isa_mem_base + 0xa0000, 0xa8000);
-        cpu_physical_sync_dirty_bitmap(isa_mem_base + 0xa8000, 0xb0000);
+        if (s->vga_memory_map_mode <= 1) {
+            cpu_physical_sync_dirty_bitmap(isa_mem_base + 0xa8000, 0xb0000);
+            if (s->vga_memory_map_mode == 0) {
+                cpu_physical_sync_dirty_bitmap(isa_mem_base + 0xb0000,
+                                               0xc0000);
+            }
+        }
     }
 #ifdef CONFIG_BOCHS_VBE
     if (s->vbe_mapped) {
@@ -170,6 +176,61 @@ static void vga_sync_dirty_bitmap(VGACommonState *s)
 #endif
 }
 
+static void vga_update_memory_access(VGACommonState *s)
+{
+    target_phys_addr_t offset, io_size;
+    uint8_t memory_map_mode;
+
+    if ((s->sr[0x02] & 0xf) == 0xf && s->sr[0x04] & 0x08) {
+        memory_map_mode = (s->gr[6] >> 2) & 3;
+        if (s->vga_mem_mapped && memory_map_mode == s->vga_memory_map_mode &&
+            s->bank_offset == s->vga_bank_offs_mapped) {
+            return;
+        }
+        vga_sync_dirty_bitmap(s);
+        s->vga_mem_mapped = true;
+        s->vga_memory_map_mode = memory_map_mode;
+        s->vga_bank_offs_mapped = s->bank_offset;
+
+        if (memory_map_mode <= 1) {
+            if (memory_map_mode == 0) {
+                offset = 0;
+                cpu_register_physical_memory_log(isa_mem_base + 0xb0000,
+                                                 0x10000,
+                                                 (s->vram_offset + 0x10000) |
+                                                 IO_MEM_RAM, 0, true);
+                io_size = 0;
+            } else {
+                offset = s->bank_offset;
+                io_size = 0x10000;
+            }
+            cpu_register_physical_memory_log(isa_mem_base + 0xa0000, 0x8000,
+                                             (s->vram_offset + offset) |
+                                             IO_MEM_RAM, 0, true);
+            offset += 0x8000;
+            cpu_register_physical_memory_log(isa_mem_base + 0xa8000, 0x8000,
+                                             (s->vram_offset + offset) |
+                                             IO_MEM_RAM, 0, true);
+        } else {
+            offset = (memory_map_mode == 2) ? 0xb0000 : 0xb8000;
+            cpu_register_physical_memory_log(isa_mem_base + 0xa0000, 0x8000,
+                                             (s->vram_offset + offset) |
+                                             IO_MEM_RAM, 0, true);
+            io_size = 0x18000;
+        }
+        if (io_size > 0) {
+            cpu_register_physical_memory(isa_mem_base + 0xc0000 - io_size,
+                                         io_size, s->vga_io_memory);
+        }
+    } else if (s->vga_mem_mapped) {
+        vga_sync_dirty_bitmap(s);
+        s->vga_mem_mapped = false;
+        s->plane_updated = 0xf;
+        cpu_register_physical_memory(isa_mem_base + 0xa0000, 0x20000,
+                                     s->vga_io_memory);
+    }
+}
+
 static void vga_dumb_update_retrace_info(VGACommonState *s)
 {
     (void) s;
@@ -463,6 +524,7 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
 #endif
         s->sr[s->sr_index] = val & sr_mask[s->sr_index];
         if (s->sr_index == 1) s->update_retrace_info(s);
+        vga_update_memory_access(s);
         break;
     case 0x3c7:
         s->dac_read_index = val;
@@ -490,6 +552,7 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
         printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
 #endif
         s->gr[s->gr_index] = val & gr_mask[s->gr_index];
+        vga_update_memory_access(s);
         break;
     case 0x3b4:
     case 0x3d4:
@@ -623,6 +686,7 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
             }
             s->vbe_regs[s->vbe_index] = val;
             s->bank_offset = (val << 16);
+            vga_update_memory_access(s);
             break;
         case VBE_DISPI_INDEX_ENABLE:
             if ((val & VBE_DISPI_ENABLED) &&
@@ -682,6 +746,7 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
             }
             s->dac_8bit = (val & VBE_DISPI_8BIT_DAC) > 0;
             s->vbe_regs[s->vbe_index] = val;
+            vga_update_memory_access(s);
             break;
         case VBE_DISPI_INDEX_VIRT_WIDTH:
             {
@@ -1924,6 +1989,7 @@ void vga_common_reset(VGACommonState *s)
         memset(&s->retrace_info, 0, sizeof (s->retrace_info));
         break;
     }
+    vga_update_memory_access(s);
 }
 
 static void vga_reset(void *opaque)
@@ -2255,15 +2321,13 @@ int vga_init_io(VGACommonState *s)
 
 void vga_init(VGACommonState *s)
 {
-    int vga_io_memory;
-
     qemu_register_reset(vga_reset, s);
 
     s->bank_offset = 0;
 
-    vga_io_memory = vga_init_io(s);
+    s->vga_io_memory = vga_init_io(s);
     cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
-                                 vga_io_memory);
+                                 s->vga_io_memory);
     qemu_register_coalesced_mmio(isa_mem_base + 0x000a0000, 0x20000);
 }
 
diff --git a/hw/vga_int.h b/hw/vga_int.h
index a6ea93c..dd8a283 100644
--- a/hw/vga_int.h
+++ b/hw/vga_int.h
@@ -112,6 +112,8 @@ typedef struct VGACommonState {
     uint32_t map_addr;
     uint32_t map_end;
     bool vga_mem_mapped; /* whether 0xa0000..0xbffff is mapped as RAM */
+    int vga_memory_map_mode;
+    int32_t vga_bank_offs_mapped;
     uint32_t latch;
     uint8_t sr_index;
     uint8_t sr[256];
