diff --git a/hw/vga.c b/hw/vga.c index 432d2cb800..851fd689b3 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -152,6 +152,48 @@ static void vga_screen_dump(void *opaque, const char *filename); static char *screen_dump_filename; static DisplayChangeListener *screen_dump_dcl; +static void vga_update_memory_access(VGACommonState *s) +{ + MemoryRegion *region, *old_region = s->chain4_alias; + target_phys_addr_t base, offset, size; + + s->chain4_alias = NULL; + + if ((s->sr[0x02] & 0xf) == 0xf && s->sr[0x04] & 0x08) { + offset = 0; + switch ((s->gr[6] >> 2) & 3) { + case 0: + base = 0xa0000; + size = 0x20000; + break; + case 1: + base = 0xa0000; + size = 0x10000; + offset = s->bank_offset; + break; + case 2: + base = 0xb0000; + size = 0x8000; + break; + case 3: + base = 0xb8000; + size = 0x8000; + break; + } + region = g_malloc(sizeof(*region)); + memory_region_init_alias(region, "vga.chain4", &s->vram, offset, size); + memory_region_add_subregion_overlap(s->legacy_address_space, base, + region, 2); + s->chain4_alias = region; + } + if (old_region) { + memory_region_del_subregion(s->legacy_address_space, old_region); + memory_region_destroy(old_region); + g_free(old_region); + s->plane_updated = 0xf; + } +} + static void vga_dumb_update_retrace_info(VGACommonState *s) { (void) s; @@ -445,6 +487,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; @@ -472,6 +515,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: @@ -605,6 +649,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) && @@ -664,6 +709,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: { @@ -1238,7 +1284,7 @@ static void vga_draw_text(VGACommonState *s, int full_update) s->font_offsets[1] = offset; full_update = 1; } - if (s->plane_updated & (1 << 2)) { + if (s->plane_updated & (1 << 2) || s->chain4_alias) { /* if the plane 2 was modified since the last display, it indicates the font may have been modified */ s->plane_updated = 0; @@ -1885,6 +1931,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) @@ -2242,6 +2289,8 @@ void vga_init(VGACommonState *s, MemoryRegion *address_space) s->bank_offset = 0; + s->legacy_address_space = address_space; + vga_io_memory = vga_init_io(s); memory_region_add_subregion_overlap(address_space, isa_mem_base + 0x000a0000, diff --git a/hw/vga_int.h b/hw/vga_int.h index d2dd7dd367..28b9287fb2 100644 --- a/hw/vga_int.h +++ b/hw/vga_int.h @@ -105,11 +105,13 @@ typedef uint8_t (* vga_retrace_fn)(struct VGACommonState *s); typedef void (* vga_update_retrace_info_fn)(struct VGACommonState *s); typedef struct VGACommonState { + MemoryRegion *legacy_address_space; uint8_t *vram_ptr; MemoryRegion vram; uint32_t vram_size; uint32_t latch; uint32_t lfb_vram_mapped; /* whether 0xa0000 is mapped as ram */ + MemoryRegion *chain4_alias; uint8_t sr_index; uint8_t sr[256]; uint8_t gr_index;