#include "vga_int.h"
#include "pixel_ops.h"
#include "qemu-timer.h"
-#include "kvm.h"
//#define DEBUG_VGA
//#define DEBUG_VGA_MEM
static uint8_t expand4to8[16];
static void vga_screen_dump(void *opaque, const char *filename);
-static char *screen_dump_filename;
+static const 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:
+ default:
+ base = 0xb8000;
+ size = 0x8000;
+ break;
+ }
+ base += isa_mem_base;
+ 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;
int cur_line, cur_line_char, cur_char;
int64_t cur_tick;
- cur_tick = qemu_get_clock(vm_clock);
+ cur_tick = qemu_get_clock_ns(vm_clock);
cur_char = (cur_tick / r->ticks_per_char) % r->total_chars;
cur_line = cur_char / r->htotal;
#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;
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:
}
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) &&
}
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:
{
#endif
/* called for accesses between 0xa0000 and 0xc0000 */
-uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr)
+uint32_t vga_mem_readb(VGACommonState *s, target_phys_addr_t addr)
{
- VGACommonState *s = opaque;
int memory_map_mode, plane;
uint32_t ret;
return ret;
}
-static uint32_t vga_mem_readw(void *opaque, target_phys_addr_t addr)
-{
- uint32_t v;
- v = vga_mem_readb(opaque, addr);
- v |= vga_mem_readb(opaque, addr + 1) << 8;
- return v;
-}
-
-static uint32_t vga_mem_readl(void *opaque, target_phys_addr_t addr)
-{
- uint32_t v;
- 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;
- return v;
-}
-
/* called for accesses between 0xa0000 and 0xc0000 */
-void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+void vga_mem_writeb(VGACommonState *s, target_phys_addr_t addr, uint32_t val)
{
- VGACommonState *s = opaque;
int memory_map_mode, plane, write_mode, b, func_select, mask;
uint32_t write_mask, bit_mask, set_mask;
printf("vga: chain4: [0x" TARGET_FMT_plx "]\n", addr);
#endif
s->plane_updated |= mask; /* only used to detect font change */
- cpu_physical_memory_set_dirty(s->vram_offset + addr);
+ memory_region_set_dirty(&s->vram, addr);
}
} else if (s->gr[5] & 0x10) {
/* odd/even mode (aka text mode mapping) */
printf("vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr);
#endif
s->plane_updated |= mask; /* only used to detect font change */
- cpu_physical_memory_set_dirty(s->vram_offset + addr);
+ memory_region_set_dirty(&s->vram, addr);
}
} else {
/* standard VGA latched access */
printf("vga: latch: [0x" TARGET_FMT_plx "] mask=0x%08x val=0x%08x\n",
addr * 4, write_mask, val);
#endif
- cpu_physical_memory_set_dirty(s->vram_offset + (addr << 2));
+ memory_region_set_dirty(&s->vram, addr << 2);
}
}
-static void vga_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
- vga_mem_writeb(opaque, addr, val & 0xff);
- vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
-}
-
-static void vga_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
- 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);
-}
-
typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
const uint8_t *font_ptr, int h,
uint32_t fgcol, uint32_t bgcol);
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;
static void vga_sync_dirty_bitmap(VGACommonState *s)
{
- if (s->map_addr)
- cpu_physical_sync_dirty_bitmap(s->map_addr, s->map_end);
-
- if (s->lfb_vram_mapped) {
- cpu_physical_sync_dirty_bitmap(isa_mem_base + 0xa0000, 0xa8000);
- cpu_physical_sync_dirty_bitmap(isa_mem_base + 0xa8000, 0xb0000);
- }
-
-#ifdef CONFIG_BOCHS_VBE
- if (s->vbe_mapped) {
- cpu_physical_sync_dirty_bitmap(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
- VBE_DISPI_LFB_PHYSICAL_ADDRESS + s->vram_size);
- }
-#endif
-
+ memory_region_sync_dirty_bitmap(&s->vram);
}
void vga_dirty_log_start(VGACommonState *s)
{
- if (kvm_enabled() && s->map_addr)
- kvm_log_start(s->map_addr, s->map_end - s->map_addr);
-
- if (kvm_enabled() && s->lfb_vram_mapped) {
- kvm_log_start(isa_mem_base + 0xa0000, 0x8000);
- kvm_log_start(isa_mem_base + 0xa8000, 0x8000);
- }
-
-#ifdef CONFIG_BOCHS_VBE
- if (kvm_enabled() && s->vbe_mapped) {
- kvm_log_start(VBE_DISPI_LFB_PHYSICAL_ADDRESS, s->vram_size);
- }
-#endif
+ memory_region_set_log(&s->vram, true, DIRTY_MEMORY_VGA);
}
void vga_dirty_log_stop(VGACommonState *s)
{
- if (kvm_enabled() && s->map_addr)
- kvm_log_stop(s->map_addr, s->map_end - s->map_addr);
-
- if (kvm_enabled() && s->lfb_vram_mapped) {
- kvm_log_stop(isa_mem_base + 0xa0000, 0x8000);
- kvm_log_stop(isa_mem_base + 0xa8000, 0x8000);
- }
-
-#ifdef CONFIG_BOCHS_VBE
- if (kvm_enabled() && s->vbe_mapped) {
- kvm_log_stop(VBE_DISPI_LFB_PHYSICAL_ADDRESS, s->vram_size);
- }
-#endif
-}
-
-void vga_dirty_log_restart(VGACommonState *s)
-{
- vga_dirty_log_stop(s);
- vga_dirty_log_start(s);
+ memory_region_set_log(&s->vram, false, DIRTY_MEMORY_VGA);
}
/*
if (!(s->cr[0x17] & 2)) {
addr = (addr & ~0x8000) | ((y1 & 2) << 14);
}
- page0 = s->vram_offset + (addr & TARGET_PAGE_MASK);
- page1 = s->vram_offset + ((addr + bwidth - 1) & TARGET_PAGE_MASK);
+ page0 = addr & TARGET_PAGE_MASK;
+ page1 = (addr + bwidth - 1) & TARGET_PAGE_MASK;
update = full_update |
- cpu_physical_memory_get_dirty(page0, VGA_DIRTY_FLAG) |
- cpu_physical_memory_get_dirty(page1, VGA_DIRTY_FLAG);
+ memory_region_get_dirty(&s->vram, page0, DIRTY_MEMORY_VGA) |
+ memory_region_get_dirty(&s->vram, page1, DIRTY_MEMORY_VGA);
if ((page1 - page0) > TARGET_PAGE_SIZE) {
/* if wide line, can use another page */
- update |= cpu_physical_memory_get_dirty(page0 + TARGET_PAGE_SIZE,
- VGA_DIRTY_FLAG);
+ update |= memory_region_get_dirty(&s->vram,
+ page0 + TARGET_PAGE_SIZE,
+ DIRTY_MEMORY_VGA);
}
/* explicit invalidation for the hardware cursor */
update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
}
/* reset modified pages */
if (page_max >= page_min) {
- cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
- VGA_DIRTY_FLAG);
+ memory_region_reset_dirty(&s->vram,
+ page_min,
+ page_max + TARGET_PAGE_SIZE - page_min,
+ DIRTY_MEMORY_VGA);
}
memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
}
VGACommonState *s = opaque;
int full_update, graphic_mode;
+ qemu_flush_coalesced_mmio_buffer();
+
if (ds_get_bits_per_pixel(s->ds) == 0) {
/* nothing to do */
} else {
void vga_common_reset(VGACommonState *s)
{
- s->lfb_addr = 0;
- s->lfb_end = 0;
- s->map_addr = 0;
- s->map_end = 0;
- s->lfb_vram_mapped = 0;
s->sr_index = 0;
memset(s->sr, '\0', sizeof(s->sr));
s->gr_index = 0;
memset(&s->retrace_info, 0, sizeof (s->retrace_info));
break;
}
+ vga_update_memory_access(s);
}
static void vga_reset(void *opaque)
char msg_buffer[80];
int full_update = 0;
+ qemu_flush_coalesced_mmio_buffer();
+
if (!(s->ar_index & 0x20)) {
graphic_mode = GMODE_BLANK;
} else {
dpy_update(s->ds, 0, 0, s->last_width, height);
}
-CPUReadMemoryFunc * const vga_mem_read[3] = {
- vga_mem_readb,
- vga_mem_readw,
- vga_mem_readl,
-};
+static uint64_t vga_mem_read(void *opaque, target_phys_addr_t addr,
+ unsigned size)
+{
+ VGACommonState *s = opaque;
-CPUWriteMemoryFunc * const vga_mem_write[3] = {
- vga_mem_writeb,
- vga_mem_writew,
- vga_mem_writel,
+ return vga_mem_readb(s, addr);
+}
+
+static void vga_mem_write(void *opaque, target_phys_addr_t addr,
+ uint64_t data, unsigned size)
+{
+ VGACommonState *s = opaque;
+
+ return vga_mem_writeb(s, addr, data);
+}
+
+const MemoryRegionOps vga_mem_ops = {
+ .read = vga_mem_read,
+ .write = vga_mem_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .impl = {
+ .min_access_size = 1,
+ .max_access_size = 1,
+ },
};
static int vga_common_post_load(void *opaque, int version_id)
#else
s->is_vbe_vmstate = 0;
#endif
- s->vram_offset = qemu_ram_alloc(NULL, "vga.vram", vga_ram_size);
- s->vram_ptr = qemu_get_ram_ptr(s->vram_offset);
+ memory_region_init_ram(&s->vram, NULL, "vga.vram", vga_ram_size);
+ s->vram_ptr = memory_region_get_ram_ptr(&s->vram);
s->vram_size = vga_ram_size;
s->get_bpp = vga_get_bpp;
s->get_offsets = vga_get_offsets;
s->update_retrace_info = vga_precise_update_retrace_info;
break;
}
+ vga_dirty_log_start(s);
}
-/* used by both ISA and PCI */
-void vga_init(VGACommonState *s)
-{
- int vga_io_memory;
+static const MemoryRegionPortio vga_portio_list[] = {
+ { 0x04, 2, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3b4 */
+ { 0x0a, 1, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3ba */
+ { 0x10, 16, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3c0 */
+ { 0x24, 2, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3d4 */
+ { 0x2a, 1, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3da */
+ PORTIO_END_OF_LIST(),
+};
- qemu_register_reset(vga_reset, s);
+#ifdef CONFIG_BOCHS_VBE
+static const MemoryRegionPortio vbe_portio_list[] = {
+ { 0, 1, 2, .read = vbe_ioport_read_index, .write = vbe_ioport_write_index },
+# ifdef TARGET_I386
+ { 1, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data },
+# else
+ { 2, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data },
+# endif
+ PORTIO_END_OF_LIST(),
+};
+#endif /* CONFIG_BOCHS_VBE */
- register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
+/* Used by both ISA and PCI */
+MemoryRegion *vga_init_io(VGACommonState *s,
+ const MemoryRegionPortio **vga_ports,
+ const MemoryRegionPortio **vbe_ports)
+{
+ MemoryRegion *vga_mem;
- register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
- register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);
- register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);
- register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);
+ *vga_ports = vga_portio_list;
+ *vbe_ports = NULL;
+#ifdef CONFIG_BOCHS_VBE
+ *vbe_ports = vbe_portio_list;
+#endif
- register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
+ vga_mem = g_malloc(sizeof(*vga_mem));
+ memory_region_init_io(vga_mem, &vga_mem_ops, s,
+ "vga-lowmem", 0x20000);
- register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);
- 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 = 0;
+ return vga_mem;
+}
-#ifdef CONFIG_BOCHS_VBE
-#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);
+void vga_init(VGACommonState *s, MemoryRegion *address_space,
+ MemoryRegion *address_space_io, bool init_vga_ports)
+{
+ MemoryRegion *vga_io_memory;
+ const MemoryRegionPortio *vga_ports, *vbe_ports;
+ PortioList *vga_port_list = g_new(PortioList, 1);
+ PortioList *vbe_port_list = g_new(PortioList, 1);
- register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
- register_ioport_write(0x1cf, 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);
+ qemu_register_reset(vga_reset, s);
- register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
- register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data, s);
-#endif
-#endif /* CONFIG_BOCHS_VBE */
+ s->bank_offset = 0;
- vga_io_memory = cpu_register_io_memory(vga_mem_read, vga_mem_write, s,
- DEVICE_LITTLE_ENDIAN);
- cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
- vga_io_memory);
- qemu_register_coalesced_mmio(isa_mem_base + 0x000a0000, 0x20000);
+ s->legacy_address_space = address_space;
+
+ vga_io_memory = vga_init_io(s, &vga_ports, &vbe_ports);
+ memory_region_add_subregion_overlap(address_space,
+ isa_mem_base + 0x000a0000,
+ vga_io_memory,
+ 1);
+ memory_region_set_coalescing(vga_io_memory);
+ if (init_vga_ports) {
+ portio_list_init(vga_port_list, vga_ports, s, "vga");
+ portio_list_add(vga_port_list, address_space_io, 0x3b0);
+ }
+ if (vbe_ports) {
+ portio_list_init(vbe_port_list, vbe_ports, s, "vbe");
+ portio_list_add(vbe_port_list, address_space_io, 0x1ce);
+ }
}
-void vga_init_vbe(VGACommonState *s)
+void vga_init_vbe(VGACommonState *s, MemoryRegion *system_memory)
{
#ifdef CONFIG_BOCHS_VBE
/* XXX: use optimized standard vga accesses */
- cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
- VGA_RAM_SIZE, s->vram_offset);
+ memory_region_add_subregion(system_memory,
+ VBE_DISPI_LFB_PHYSICAL_ADDRESS,
+ &s->vram);
s->vbe_mapped = 1;
#endif
}
{
if (screen_dump_filename) {
ppm_save(screen_dump_filename, ds->surface);
- screen_dump_filename = NULL;
}
}
uint32_t v;
int y, x;
uint8_t r, g, b;
+ int ret;
+ char *linebuf, *pbuf;
f = fopen(filename, "wb");
if (!f)
return -1;
fprintf(f, "P6\n%d %d\n%d\n",
ds->width, ds->height, 255);
+ linebuf = g_malloc(ds->width * 3);
d1 = ds->data;
for(y = 0; y < ds->height; y++) {
d = d1;
+ pbuf = linebuf;
for(x = 0; x < ds->width; x++) {
if (ds->pf.bits_per_pixel == 32)
v = *(uint32_t *)d;
(ds->pf.gmax + 1);
b = ((v >> ds->pf.bshift) & ds->pf.bmax) * 256 /
(ds->pf.bmax + 1);
- fputc(r, f);
- fputc(g, f);
- fputc(b, f);
+ *pbuf++ = r;
+ *pbuf++ = g;
+ *pbuf++ = b;
d += ds->pf.bytes_per_pixel;
}
d1 += ds->linesize;
+ ret = fwrite(linebuf, 1, pbuf - linebuf, f);
+ (void)ret;
}
+ g_free(linebuf);
fclose(f);
return 0;
}
{
DisplayChangeListener *dcl;
- dcl = qemu_mallocz(sizeof(DisplayChangeListener));
+ dcl = g_malloc0(sizeof(DisplayChangeListener));
dcl->dpy_update = vga_save_dpy_update;
dcl->dpy_resize = vga_save_dpy_resize;
dcl->dpy_refresh = vga_save_dpy_refresh;
if (!screen_dump_dcl)
screen_dump_dcl = vga_screen_dump_init(s->ds);
- screen_dump_filename = (char *)filename;
+ screen_dump_filename = filename;
vga_invalidate_display(s);
vga_hw_update();
+ screen_dump_filename = NULL;
}
-